diff --git a/README.md b/README.md index 40dc597..9d72631 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ wm.rebuildPlaceholderRegistry(); // optional: after changing callback while por Some small HTML snippets (status messages, OTA blurb, help table, etc.) are still assembled in RAM or pulled from `HTML.h` and then injected into templates. That is **intentional**: not every line of markup needs its own placeholder or registry churn. Customize those via DFTE where it pays off (shell, branding, layout); keep trivial blobs as strings when appropriate. -## Debug: WiFiManager (`DEBUG_WM`) and DFTE logging +## Debug: WiFiManager logging and DFTE ### How DFTE logging is designed @@ -74,16 +74,14 @@ DFTE keeps a **single global pointer** `deviceFrameworkTemplateEngineLogger` (se ### WiFiManager today -- **`DEBUG_WM`**: compile-time gated with **`WM_DEBUG_LEVEL`** (see commented `#define WM_DFTE_LOGGING` / `WM_DEBUG_LEVEL` in `WiFiManager.h`). At runtime, `_debug`, `_debugLevel`, `_debugPrefix`, and `_debugPort` control volume and destination (`Serial` unless **`WM_DEBUG_PORT`** is set). This is tuned for **firmware size** (strip verbose strings when the macro is absent) and familiar serial prefixes (`*wm:`). -- **`WM_DFTE_LOGGING`** (build flag, **off by default**): when defined, `WiFiManagerServer::setupTemplateEngine()` registers **`WiFiManagerDfteLogger`**, which forwards DFTE messages into **`DEBUG_WM`** with a `[DFTE]` prefix and WM levels (error → `WM_DEBUG_ERROR`, warn → `WM_DEBUG_NOTIFY`, info → `WM_DEBUG_VERBOSE`, debug → `WM_DEBUG_DEV`). If **`deviceFrameworkTemplateEngineIsLoggingEnabled()`** is already true (for example **DeviceFramework** installed `WebInterfaceTemplateEngineLogger` first), WiFiManager **does not replace** that sink; it only owns teardown when it installed its own. **`shutdownServer()`** disables logging and drops the adapter only when WiFiManager installed it—avoiding clobbering a host logger on portal shutdown. +- **`WM_LOG_LEVEL`**: compile-time default is **`0`** (silent). Set **`1`–`5`** for `Error` … `Trace` (see `WiFiManagerLogLevel` in `WiFiManagerLogLevel.h`). Example: `-DWM_LOG_LEVEL=5` in `platformio.ini` for full verbosity. Strip all log **call sites** from the binary with **`WM_NO_LOG`** (or legacy **`WM_NODEBUG`**). At runtime, **`setLogEnabled`**, **`setLogOutput(enabled, maxLevel)`**, **`_logPrefix`**, and **`_logPort`** gate output; use **`WM_DEBUG_PORT`** to redirect the default `Print` target. **`WiFiManagerLogSink`** receives structured **`WiFiManagerLogMessage`** (level, subsystem, full line). +- **`WM_DFTE_LOGGING`** (build flag, **off by default**): when defined, `WiFiManagerServer::setupTemplateEngine()` registers **`WiFiManagerDfteLogger`**, which forwards DFTE into **`WiFiManager::log(..., "WM/DFTE", ...)`**. It uses **`deviceFrameworkTemplateEngineEnableLogging(..., this)`** so **`disableLoggingForOwner(this)`** on shutdown does not clobber another owner. If DFTE logging was already enabled, WiFiManager does not replace it. Use **`pio test -e esp8266_dfte_log --without-uploading --without-testing`** in this repo to compile the test firmware with **`WM_DFTE_LOGGING`** enabled. -### Should WiFiManager’s logging be refactored to match DFTE’s hook style? +### Design note -**Not as a big-bang rewrite.** DFTE’s model fits a **small library** with one pipeline: optional sink, zero cost when disabled. WiFiManager has **hundreds** of `DEBUG_WM` sites and relies on **`#ifdef WM_DEBUG_LEVEL`** to remove entire print paths from the binary. Replacing that with only a runtime pointer would either **regain flash/RAM** for the strings or require keeping both mechanisms. - -A practical middle path (what we did here) is: **keep `DEBUG_WM` + `WM_DEBUG_LEVEL` for WM-native traces**, and **optionally bridge DFTE into the same stream** with `WM_DFTE_LOGGING`. If you later want a unified sink for *both*, a small internal `WiFiManagerLogSink` interface *behind* `DEBUG_WM` could forward to `Serial` or a custom `Print`—that is incremental and does not force every call site through a virtual function in release builds. +DFTE uses a small optional logger pointer; WiFiManager uses **`#ifndef WM_NO_LOG`** around log call sites so release builds can omit strings entirely. **`WiFiManagerLogSink`** lets hosts (e.g. **DeviceFramework**) map levels without parsing ad hoc prefixes. ## License diff --git a/lib/WiFiManager/include/WiFiManager.h b/lib/WiFiManager/include/WiFiManager.h index 09790d5..7f623e6 100644 --- a/lib/WiFiManager/include/WiFiManager.h +++ b/lib/WiFiManager/include/WiFiManager.h @@ -24,8 +24,19 @@ #include #include "WiFiManagerParameter.h" +#include "WiFiManagerLogLevel.h" -// #define WM_DFTE_LOGGING // opt-in: register a DFTE log sink that forwards to DEBUG_WM (see README) +#ifdef WM_NODEBUG +#ifndef WM_NO_LOG +#define WM_NO_LOG +#endif +#endif + +#ifndef WM_LOG_LEVEL +#define WM_LOG_LEVEL 0 +#endif + +// #define WM_DFTE_LOGGING // opt-in: bridge DFTE logging into WiFiManager (see README) // #define WM_MDNS // includes MDNS, also set MDNS with sethostname // #define WM_FIXERASECONFIG // use erase flash fix // #define WM_ERASE_NVS // esp32 erase(true) will erase NVS @@ -185,20 +196,11 @@ const char WM_VERSION_STR[] PROGMEM = "v2.0.18"; // WiFiManagerRequestArgs is defined as a nested class inside WiFiManager (after WM_WebServer is defined) - // debugging - typedef enum { - WM_DEBUG_SILENT = 0, // debug OFF but still compiled for runtime - WM_DEBUG_ERROR = 1, // error only - WM_DEBUG_NOTIFY = 2, // default stable,INFO - WM_DEBUG_VERBOSE = 3, // move verbose info - WM_DEBUG_DEV = 4, // development useful debugging info - WM_DEBUG_MAX = 5 // MAX extra dev auditing, var dumps etc (MAX+1 will print timing,mem and frag info) - } wm_debuglevel_t; - // Forward declarations class WiFiManagerServer; class WiFiManagerHandlers; class WiFiManagerDfteLogger; +class WiFiManagerLogSink; class WiFiManager { @@ -357,10 +359,21 @@ class WiFiManager // lets you disable automatically connecting after save from webportal void setSaveConnect(bool connect = true); - // toggle debug output - void setDebugOutput(boolean debug); - void setDebugOutput(boolean debug, String prefix); // log line prefix, default "*wm:" - void setDebugOutput(boolean debug, wm_debuglevel_t level ); // log line prefix, default "*wm:" + void setLogEnabled(boolean enabled); + void setLogPrefix(String prefix); + void setLogOutput(boolean enabled, WiFiManagerLogLevel maxLevel); + + /** When non-null, log lines go here instead of the Print stream. */ + void setLogSink(WiFiManagerLogSink* sink); + WiFiManagerLogSink* getLogSink(); + + template + void log(WiFiManagerLogLevel level, const char* subsystem, T&& text); + + template + void log(WiFiManagerLogLevel level, const char* subsystem, T&& a, U&& b); + + void log(WiFiManagerLogLevel level, const char* subsystem, const String& text); //set min quality percentage to include in scan, defaults to 8% if not specified void setMinimumSignalQuality(int quality = 8); @@ -839,8 +852,6 @@ protected: #endif protected: - friend class WiFiManagerDfteLogger; // WM_DFTE_LOGGING: bridge calls protected DEBUG_WM - //helpers (rendering methods moved to WiFiManagerHandlers) boolean isIp(String str); String toStringIp(IPAddress ip); @@ -867,46 +878,24 @@ protected: int _max_params; WiFiManagerParameter** _params = NULL; - boolean _debug = true; - String _debugPrefix = "*wm:"; // default debug prefix + boolean _logEnabled = true; + String _logPrefix = "*wm:"; + WiFiManagerLogLevel _logTagMinLevel = WiFiManagerLogLevel::Debug; - wm_debuglevel_t debugLvlShow = WM_DEBUG_VERBOSE; // at which level start showing [n] level tags - - // build debuglevel support - // @todo use DEBUG_ESP_x? - - // Set default debug level - #ifndef WM_DEBUG_LEVEL - #define WM_DEBUG_LEVEL WM_DEBUG_NOTIFY - #endif - - // override debug level OFF - #ifdef WM_NODEBUG - #undef WM_DEBUG_LEVEL - #endif - - #ifdef WM_DEBUG_LEVEL - uint8_t _debugLevel = (uint8_t)WM_DEBUG_LEVEL; - #else - uint8_t _debugLevel = 0; // default debug level - #endif +#ifndef WM_NO_LOG + WiFiManagerLogLevel _runtimeMaxLevel = static_cast((uint8_t)WM_LOG_LEVEL); +#else + WiFiManagerLogLevel _runtimeMaxLevel = WiFiManagerLogLevel::Silent; +#endif // @todo use DEBUG_ESP_PORT ? #ifdef WM_DEBUG_PORT - Print& _debugPort = WM_DEBUG_PORT; + Print& _logPort = WM_DEBUG_PORT; #else - Print& _debugPort = Serial; // debug output stream ref + Print& _logPort = Serial; #endif - template - void DEBUG_WM(Generic text); - - template - void DEBUG_WM(wm_debuglevel_t level,Generic text); - template - void DEBUG_WM(Generic text,Genericb textb); - template - void DEBUG_WM(wm_debuglevel_t level, Generic text,Genericb textb); + void emitLogImpl(WiFiManagerLogLevel level, const char* subsystem, const String& textA, const String& textB); // callbacks // @todo use cb list (vector) maybe event ids, allow no return value @@ -920,19 +909,19 @@ protected: std::function _preotaupdatecallback; std::function _configportaltimeoutcallback; + WiFiManagerLogSink* _logSink = nullptr; + template auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { return obj->fromString(s); } auto optionalIPFromString(...) -> bool { - // DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); return false; } }; -// Include template implementations for DEBUG_WM -#include "WiFiManagerDebug.h" +#include "WiFiManagerLogTemplates.h" #endif diff --git a/lib/WiFiManager/include/WiFiManagerDebug.h b/lib/WiFiManager/include/WiFiManagerDebug.h deleted file mode 100644 index 3f0a9ac..0000000 --- a/lib/WiFiManager/include/WiFiManagerDebug.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * WiFiManagerDebug.h - * - * Debug output macros and templates for WiFiManager - * - * @author tablatronix - * @author Alex Hope-O'Connor - * @license MIT - */ - -#ifndef WiFiManagerDebug_h -#define WiFiManagerDebug_h - -#if defined(ESP8266) || defined(ESP32) - -// Template implementations for DEBUG_WM - must be in header for template instantiation -// This file is included at the end of WiFiManager.h after the class definition -template -void WiFiManager::DEBUG_WM(Generic text) { - DEBUG_WM(WM_DEBUG_NOTIFY,text,""); -} - -template -void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text) { - if(_debugLevel >= level) DEBUG_WM(level,text,""); -} - -template -void WiFiManager::DEBUG_WM(Generic text,Genericb textb) { - DEBUG_WM(WM_DEBUG_NOTIFY,text,textb); -} - -template -void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) { - if(!_debug || _debugLevel < level) return; - - if(_debugLevel >= WM_DEBUG_MAX){ - #ifdef ESP8266 - // uint32_t free; - // uint16_t max; - // uint8_t frag; - // ESP.getHeapStats(&free, &max, &frag);// @todo Does not exist in 2.3.0 - // _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); - #elif defined ESP32 - // total_free_bytes; ///< Total free bytes in the heap. Equivalent to multi_free_heap_size(). - // total_allocated_bytes; ///< Total bytes allocated to data in the heap. - // largest_free_block; ///< Size of largest free block in the heap. This is the largest malloc-able size. - // minimum_free_bytes; ///< Lifetime minimum free heap size. Equivalent to multi_minimum_free_heap_size(). - // allocated_blocks; ///< Number of (variable size) blocks allocated in the heap. - // free_blocks; ///< Number of (variable size) free blocks in the heap. - // total_blocks; ///< Total number of (variable size) blocks in the heap. - multi_heap_info_t info; - heap_caps_get_info(&info, MALLOC_CAP_INTERNAL); - uint32_t free = info.total_free_bytes; - uint16_t max = info.largest_free_block; - uint8_t frag = 100 - (max * 100) / free; - _debugPort.printf("[MEM] free: %5u | max: %5u | frag: %3u%% \n", free, max, frag); - #endif - } - - _debugPort.print(_debugPrefix); - if(_debugLevel >= debugLvlShow) _debugPort.print("["+(String)level+"] "); - _debugPort.print(text); - if(textb){ - _debugPort.print(" "); - _debugPort.print(textb); - } - _debugPort.println(); -} - -#endif // defined(ESP8266) || defined(ESP32) - -#endif // WiFiManagerDebug_h - diff --git a/lib/WiFiManager/include/WiFiManagerDfteLogger.h b/lib/WiFiManager/include/WiFiManagerDfteLogger.h index 7d174bb..e3ac5a1 100644 --- a/lib/WiFiManager/include/WiFiManagerDfteLogger.h +++ b/lib/WiFiManager/include/WiFiManagerDfteLogger.h @@ -1,7 +1,7 @@ /** * WiFiManagerDfteLogger.h * - * Optional bridge from DFTE's logging hooks to WiFiManager::DEBUG_WM. + * Optional bridge from DFTE's logging hooks to WiFiManager::log. * Enabled only when the sketch / library build defines WM_DFTE_LOGGING. */ @@ -14,38 +14,26 @@ #include "WiFiManager.h" /** - * Forwards DeviceFrameworkTemplateEngineLogger calls to WiFiManager's - * existing DEBUG_WM pipeline (respects _debug, _debugLevel, _debugPrefix, _debugPort). + * Forwards DeviceFrameworkTemplateEngineLogger calls to WiFiManager logging + * with subsystem WM/DFTE. */ class WiFiManagerDfteLogger : public DeviceFrameworkTemplateEngineLogger { public: explicit WiFiManagerDfteLogger(WiFiManager* wm) : _wm(wm) {} - void error(const String& msg) override { - logLine(WM_DEBUG_ERROR, msg); - } - void warn(const String& msg) override { - logLine(WM_DEBUG_NOTIFY, msg); - } - void info(const String& msg) override { - logLine(WM_DEBUG_VERBOSE, msg); - } - void debug(const String& msg) override { - logLine(WM_DEBUG_DEV, msg); - } + void error(const String& msg) override { logLine(WiFiManagerLogLevel::Error, msg); } + void warn(const String& msg) override { logLine(WiFiManagerLogLevel::Warn, msg); } + void info(const String& msg) override { logLine(WiFiManagerLogLevel::Debug, msg); } + void debug(const String& msg) override { logLine(WiFiManagerLogLevel::Trace, msg); } private: WiFiManager* _wm; - void logLine(wm_debuglevel_t level, const String& msg) { + void logLine(WiFiManagerLogLevel level, const String& msg) { if (!_wm) { return; } - String line; - line.reserve(static_cast(msg.length()) + 12u); - line += F("[DFTE] "); - line += msg; - _wm->DEBUG_WM(level, line); + _wm->log(level, "WM/DFTE", msg); } }; diff --git a/lib/WiFiManager/include/WiFiManagerHandlers.h b/lib/WiFiManager/include/WiFiManagerHandlers.h index 901eb25..4d8dfc9 100644 --- a/lib/WiFiManager/include/WiFiManagerHandlers.h +++ b/lib/WiFiManager/include/WiFiManagerHandlers.h @@ -69,6 +69,21 @@ class WiFiManagerHandlers { void handleUpdate(AsyncWebServerRequest *request); void handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); void handleUpdateDone(AsyncWebServerRequest *request); + + // JSON / SPA API (portal is a single-page app; only GET / serves HTML) + void handleApiBootstrap(AsyncWebServerRequest *request); + void handleApiWifiScanStatus(AsyncWebServerRequest *request); + void handleApiWifiScan(AsyncWebServerRequest *request); + void handleApiWifiMeta(AsyncWebServerRequest *request); + void handleApiWifiSave(AsyncWebServerRequest *request); + void handleApiParamsGet(AsyncWebServerRequest *request); + void handleApiParamsSave(AsyncWebServerRequest *request); + void handleApiInfo(AsyncWebServerRequest *request); + void handleApiStatus(AsyncWebServerRequest *request); + void handleApiDeviceRestart(AsyncWebServerRequest *request); + void handleApiDeviceErase(AsyncWebServerRequest *request); + void handleApiPortalClose(AsyncWebServerRequest *request); + void handleApiPortalExit(AsyncWebServerRequest *request); // Captive Portal boolean captivePortal(AsyncWebServerRequest *request); @@ -91,6 +106,11 @@ class WiFiManagerHandlers { WiFiManager* _wm; void collectVisibleScanResults(std::vector& networks); void appendVisibleScanResultsJson(String& json, const std::vector& networks); + + String buildPortalBootstrapJson(); + void applyWifiAndParamsFromRequest(AsyncWebServerRequest *request); + void buildPlainStatusSummary(String& out); + static void sendApiJson(AsyncWebServerRequest *request, int code, const String& json); }; #endif // defined(ESP8266) || defined(ESP32) diff --git a/lib/WiFiManager/include/WiFiManagerLogLevel.h b/lib/WiFiManager/include/WiFiManagerLogLevel.h new file mode 100644 index 0000000..f755f13 --- /dev/null +++ b/lib/WiFiManager/include/WiFiManagerLogLevel.h @@ -0,0 +1,32 @@ +/** + * WiFiManagerLogLevel.h + * + * Compile-time and runtime log levels for WiFiManager. Higher numeric values + * mean more verbose output. Matches the old 0..5 tier model for build flags. + */ + +#ifndef WiFiManagerLogLevel_h +#define WiFiManagerLogLevel_h + +#include + +/** Default subsystem tag for core WiFiManager messages (macro for C++11 embedded toolchains). */ +#define kWiFiMgrLogSubsystem "WM" + +enum class WiFiManagerLogLevel : uint8_t { + Silent = 0, + Error = 1, + Warn = 2, + Info = 3, + Debug = 4, + Trace = 5, +}; + +/** Full line delivered to Print or WiFiManagerLogSink (prefix and tags included). */ +struct WiFiManagerLogMessage { + WiFiManagerLogLevel level; + const char* subsystem; + String line; +}; + +#endif diff --git a/lib/WiFiManager/include/WiFiManagerLogSink.h b/lib/WiFiManager/include/WiFiManagerLogSink.h new file mode 100644 index 0000000..7374e39 --- /dev/null +++ b/lib/WiFiManager/include/WiFiManagerLogSink.h @@ -0,0 +1,19 @@ +/** + * WiFiManagerLogSink.h + * + * Optional host-provided sink for WiFiManager log output. When set, logs are + * delivered here instead of the configured Print stream (usually Serial). + */ + +#ifndef WiFiManagerLogSink_h +#define WiFiManagerLogSink_h + +#include "WiFiManagerLogLevel.h" + +class WiFiManagerLogSink { +public: + virtual void log(const WiFiManagerLogMessage& msg) = 0; + virtual ~WiFiManagerLogSink() = default; +}; + +#endif diff --git a/lib/WiFiManager/include/WiFiManagerLogTemplates.h b/lib/WiFiManager/include/WiFiManagerLogTemplates.h new file mode 100644 index 0000000..14e5e11 --- /dev/null +++ b/lib/WiFiManager/include/WiFiManagerLogTemplates.h @@ -0,0 +1,45 @@ +/** + * WiFiManagerLogTemplates.h + * + * Template implementations for WiFiManager::log(...). Included at the end of WiFiManager.h. + */ + +#ifndef WiFiManagerLogTemplates_h +#define WiFiManagerLogTemplates_h + +#include "WiFiManagerLogLevel.h" +#include +#include + +#if defined(ESP8266) || defined(ESP32) + +inline String wmLogStringifyArg(const __FlashStringHelper* v) { + return String(v); +} + +inline String wmLogStringifyArg(const IPAddress& v) { + return v.toString(); +} + +template +inline String wmLogStringifyArg(const T& v) { + return String(v); +} + +template +inline void WiFiManager::log(WiFiManagerLogLevel level, const char* subsystem, T&& text) { +#ifndef WM_NO_LOG + emitLogImpl(level, subsystem, wmLogStringifyArg(text), String()); +#endif +} + +template +inline void WiFiManager::log(WiFiManagerLogLevel level, const char* subsystem, T&& a, U&& b) { +#ifndef WM_NO_LOG + emitLogImpl(level, subsystem, wmLogStringifyArg(a), wmLogStringifyArg(b)); +#endif +} + +#endif // ESP8266 || ESP32 + +#endif // WiFiManagerLogTemplates_h diff --git a/lib/WiFiManager/include/WiFiManagerServer.h b/lib/WiFiManager/include/WiFiManagerServer.h index 9420195..066896c 100644 --- a/lib/WiFiManager/include/WiFiManagerServer.h +++ b/lib/WiFiManager/include/WiFiManagerServer.h @@ -55,6 +55,20 @@ const char R_scan[] PROGMEM = "/wifi/scan"; const char R_update[] PROGMEM = "/update"; const char R_updatedone[] PROGMEM = "/u"; +const char R_api_bootstrap[] PROGMEM = "/api/bootstrap"; +const char R_api_wifi_scan_status[] PROGMEM = "/api/wifi/scan-status"; +const char R_api_wifi_scan[] PROGMEM = "/api/wifi/scan"; +const char R_api_wifi_meta[] PROGMEM = "/api/wifi/meta"; +const char R_api_wifi_save[] PROGMEM = "/api/wifi/save"; +const char R_api_params[] PROGMEM = "/api/params"; +const char R_api_params_save[] PROGMEM = "/api/params/save"; +const char R_api_info[] PROGMEM = "/api/info"; +const char R_api_status[] PROGMEM = "/api/status"; +const char R_api_device_restart[] PROGMEM = "/api/device/restart"; +const char R_api_device_erase[] PROGMEM = "/api/device/erase"; +const char R_api_portal_close[] PROGMEM = "/api/portal/close"; +const char R_api_portal_exit[] PROGMEM = "/api/portal/exit"; + class WiFiManagerServer { public: // Singleton access @@ -122,7 +136,7 @@ class WiFiManagerServer { std::function _tplSetupCallback; #ifdef WM_DFTE_LOGGING - // DFTE -> DEBUG_WM bridge (only installed when WM_DFTE_LOGGING and no other logger registered) + // DFTE -> WiFiManager::log bridge (only installed when WM_DFTE_LOGGING and no other logger registered) std::unique_ptr _dfteLogger; bool _wmOwnsDfteLogSink = false; #endif diff --git a/lib/WiFiManager/include/templates/PortalAppJS.h b/lib/WiFiManager/include/templates/PortalAppJS.h new file mode 100644 index 0000000..3416968 --- /dev/null +++ b/lib/WiFiManager/include/templates/PortalAppJS.h @@ -0,0 +1,214 @@ +/** + * PortalAppJS.h + * Embedded SPA for WiFiManager config portal (hash routing + JSON APIs). + */ + +#ifndef _WM_PORTAL_APP_JS_H_ +#define _WM_PORTAL_APP_JS_H_ + +#include + +const char PORTAL_APP_JS[] PROGMEM = R"rawliteral( +(function(){ +'use strict'; +var boot={}; +try{var el=document.getElementById('wm-bootstrap');if(el&&el.textContent)boot=JSON.parse(el.textContent);}catch(e){boot={};} + +function $(id){return document.getElementById(id);} +function esc(t){if(!t)return'';return String(t).replace(/[&<>"']/g,function(c){return({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]);});} + +function setView(html){ + var a=$('app'); + if(!a)return; + a.innerHTML="
"+html+"
"; +} + +function navBar(){ + var f=boot.features||{}; + var h="

"; + h+="Home · "; + h+="WiFi"; + if(!f.paramsInWifi){h+=" · Setup";} + h+=" · Info"; + h+=" · Update"; + h+="


"; + return h; +} + +function viewHome(){ + var sub=esc(boot.subtitle||''); + var t=esc(boot.title||'WiFiManager'); + var html=navBar(); + html+="

"+t+"

"+sub+"

"; + html+="

Use the links above to configure WiFi, view device info, or update firmware.

"; + setView(html); +} + +function api(path, opt){ + opt=opt||{}; + return fetch(path,{method:opt.method||'GET',headers:opt.headers,body:opt.body,credentials:'same-origin'}) + .then(function(r){return r.text().then(function(t){return {ok:r.ok,status:r.status,body:t};});}); +} + +function scanPollTimer(){} + +function renderScanList(data){ + if(!data||data.scanning){return '

Scanning for networks...

';} + if(data.error==='timeout')return '

Scan timed out. Try Refresh.

'; + if(data.error==='failed')return '

Scan failed.

'; + if(!data.networks||data.count===0)return '

No networks found.

'; + var html='',i,n,q,pct,qi,enc; + for(i=0;i4)qi=4; + enc=n.encrypted?'l':''; + html+="
"+esc(n.ssid)+""; + html+=""; + html+="
"+pct+"
"; + } + return html; +} + +window.portalPickSsid=function(el){ + var s=el.getAttribute('data-ssid'); + var inp=document.getElementById('wm-s'); + if(inp&&s){inp.value=s;} + return false; +}; + +function wifiRefresh(){ + var box=document.getElementById('wm-scan-results'); + if(!box)return; + box.innerHTML='

Starting scan...

'; + api('/api/wifi/scan',{method:'POST'}).then(function(){ + var iv=setInterval(function(){ + api('/api/wifi/scan-status').then(function(res){ + try{var d=JSON.parse(res.body);}catch(e){return;} + if(box)box.innerHTML=renderScanList(d); + if(!d.scanning)clearInterval(iv); + }); + },800); + }); +} + +function viewWifi(){ + setView(navBar()+"

WiFi

Loading...

"); + api('/api/wifi/meta').then(function(res){ + try{var m=JSON.parse(res.body);}catch(e){m={};} + var html=navBar()+"

WiFi

"; + html+="
"; + html+="
"; + html+=""; + html+=""; + html+=" "; + if(m.staticFieldsHtml){html+=m.staticFieldsHtml;} + if(m.paramsHtml){html+=m.paramsHtml;} + html+="
"; + html+="
"; + html+="
"; + setView(html); + api('/api/wifi/scan-status').then(function(r2){ + try{var d=JSON.parse(r2.body);}catch(e){d={};} + var box=document.getElementById('wm-scan-results'); + if(box)box.innerHTML=renderScanList(d); + if(d&&d.scanning){wifiRefresh();} + }); + }); +} + +window.portalWifiSave=function(ev){ + ev.preventDefault(); + var fd=new FormData(document.getElementById('wm-wifi-form')); + var msg=$('wm-wifi-msg'); + if(msg)msg.innerHTML='Saving...'; + api('/api/wifi/save',{method:'POST',body:fd}).then(function(res){ + try{var j=JSON.parse(res.body);}catch(e){j={ok:false};} + if(msg)msg.innerHTML=(j&&j.message)?esc(j.message):(res.ok?'Saved.':'Error'); + }); + return false; +}; + +function viewInfo(){ + setView(navBar()+"

Loading info...

"); + api('/api/info').then(function(res){ + try{var d=JSON.parse(res.body);}catch(e){d={};} + var html=navBar()+"

Info

"; + function section(title,rows){ + if(!rows||!rows.length)return''; + var h="

"+esc(title)+"


"; + for(var i=0;i
"+rows[i].value+"
"; + } + h+="
"; + return h; + } + html+=section('Status',d.status||[]); + html+=section('Device',d.device||[]); + html+=section('WiFi',d.wifi||[]); + html+=section('About',d.about||[]); + var act=d.actions||{}; + if(act.showUpdate)html+="

Firmware update

"; + if(act.showErase)html+="

"; + setView(html); + }); +} + +window.portalErase=function(){ + if(!confirm('Erase WiFi configuration?'))return; + api('/api/device/erase',{method:'POST'}).then(function(res){ + try{var j=JSON.parse(res.body);}catch(e){j={};} + alert((j&&j.message)?j.message:'Done'); + }); +}; + +function viewSetup(){ + setView(navBar()+"

Loading...

"); + api('/api/params').then(function(res){ + try{var d=JSON.parse(res.body);}catch(e){d={};} + var html=navBar()+"

Parameters

"; + html+="
"+(d.paramsHtml||'')+"
"; + html+="
"; + setView(html); + }); +} + +window.portalParamSave=function(ev){ + ev.preventDefault(); + var fd=new FormData(document.getElementById('wm-param-form')); + var msg=$('wm-param-msg'); + if(msg)msg.innerHTML='Saving...'; + api('/api/params/save',{method:'POST',body:fd}).then(function(res){ + try{var j=JSON.parse(res.body);}catch(e){j={};} + if(msg)msg.innerHTML=(j&&j.message)?esc(j.message):'Saved.'; + }); + return false; +}; + +function viewUpdate(){ + var html=navBar()+"

Firmware update

"; + html+="
"; + html+=""; + html+="
"; + html+="

Upload a .bin firmware. Device may restart after update.

"; + setView(html); +} + +function route(){ + var h=location.hash||'#/'; + if(h.indexOf('#/')!==0)h='#/'; + if(h==='#/'||h==='#'){viewHome();return;} + if(h==='#/wifi'){viewWifi();return;} + if(h==='#/info'){viewInfo();return;} + if(h==='#/setup'){viewSetup();return;} + if(h==='#/update'){viewUpdate();return;} + viewHome(); +} + +window.addEventListener('hashchange',route); +window.addEventListener('load',route); +})(); + +)rawliteral"; + +#endif // _WM_PORTAL_APP_JS_H_ diff --git a/lib/WiFiManager/include/templates/RootSelector.h b/lib/WiFiManager/include/templates/RootSelector.h index 21ed0e8..134e4dd 100644 --- a/lib/WiFiManager/include/templates/RootSelector.h +++ b/lib/WiFiManager/include/templates/RootSelector.h @@ -9,7 +9,7 @@ #ifdef WM_CUSTOM_ROOT_TEMPLATE_HEADER #include WM_CUSTOM_ROOT_TEMPLATE_HEADER #else -#include "Root.h" +#include "RootShell.h" #endif #endif // _WM_ROOT_SELECTOR_H_ diff --git a/lib/WiFiManager/include/templates/RootShell.h b/lib/WiFiManager/include/templates/RootShell.h new file mode 100644 index 0000000..4aacad7 --- /dev/null +++ b/lib/WiFiManager/include/templates/RootShell.h @@ -0,0 +1,32 @@ +/** + * RootShell.h + * Single-page portal shell: only HTML document served for GET /. + * Dynamic UI is driven by embedded JS + JSON APIs under /api/*. + */ + +#ifndef _WM_ROOT_SHELL_TEMPLATE_H_ +#define _WM_ROOT_SHELL_TEMPLATE_H_ + +#include + +const char WM_ROOT_SHELL_TEMPLATE[] PROGMEM = + "" + "" + "" + "" + "" + "" + "%PAGE_TITLE%" + "%SCRIPTS%" + "%STYLES%" + "" + "" + "
" + "" + "" + "" + ""; + +#endif // _WM_ROOT_SHELL_TEMPLATE_H_ diff --git a/lib/WiFiManager/src/WiFiManager.cpp b/lib/WiFiManager/src/WiFiManager.cpp index ce11c4a..db7eecd 100644 --- a/lib/WiFiManager/src/WiFiManager.cpp +++ b/lib/WiFiManager/src/WiFiManager.cpp @@ -11,10 +11,15 @@ */ #include "WiFiManager.h" +#include "WiFiManagerLogSink.h" #include "WiFiManagerServer.h" // Need menu tokens #if defined(ESP8266) || defined(ESP32) +#ifdef ESP32 +#include +#endif + #ifdef ESP32 uint8_t WiFiManager::_lastconxresulttmp = WL_IDLE_STATUS; #endif @@ -63,8 +68,8 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { if(p->getID()){ for (size_t i = 0; i < strlen(p->getID()); i++){ if(!(isAlphaNumeric(p->getID()[i])) && !(p->getID()[i]=='_')){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] parameter IDs can only contain alpha numeric chars")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] parameter IDs can only contain alpha numeric chars")); #endif return false; } @@ -73,8 +78,8 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { // init params if never malloc if(_params == NULL){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); #endif _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*)); } @@ -82,16 +87,16 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { // resize the params array by increment of WIFI_MANAGER_MAX_PARAMS if(_paramsCount == _max_params){ _max_params += WIFI_MANAGER_MAX_PARAMS; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Updated _max_params:"),_max_params); - DEBUG_WM(WM_DEBUG_DEV,F("re-allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("Updated _max_params:"),_max_params); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("re-allocating params bytes:"),_max_params * sizeof(WiFiManagerParameter*)); #endif WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*)); if (new_params != NULL) { _params = new_params; } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] failed to realloc params, size not increased!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] failed to realloc params, size not increased!")); #endif return false; } @@ -100,8 +105,8 @@ bool WiFiManager::addParameter(WiFiManagerParameter *p) { _params[_paramsCount] = p; _paramsCount++; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Added Parameter:"),p->getID()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Added Parameter:"),p->getID()); #endif return true; } @@ -115,7 +120,7 @@ int WiFiManager::getParametersCount() { } // Constructors -WiFiManager::WiFiManager(Print& consolePort):_debugPort(consolePort){ +WiFiManager::WiFiManager(Print& consolePort) : _logPort(consolePort) { WiFiManagerInit(); } @@ -124,7 +129,9 @@ WiFiManager::WiFiManager() { } void WiFiManager::WiFiManagerInit(){ - if(_debug && _debugLevel >= WM_DEBUG_DEV) debugPlatformInfo(); + if (_logEnabled && (uint8_t)_runtimeMaxLevel >= (uint8_t)WiFiManagerLogLevel::Trace) { + debugPlatformInfo(); + } _max_params = WIFI_MANAGER_MAX_PARAMS; // _serverManager is created lazily when config portal is started to save memory } @@ -140,8 +147,8 @@ WiFiManager::~WiFiManager() { // Free allocated parameters if (_params != NULL){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("freeing allocated params!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("freeing allocated params!")); #endif free(_params); _params = NULL; @@ -152,8 +159,8 @@ WiFiManager::~WiFiManager() { WiFi.removeEvent(wm_event_id); #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("unloading")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("unloading")); #endif } @@ -183,8 +190,8 @@ boolean WiFiManager::autoConnect() { * @return true if connected successfully, false if config portal started */ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AutoConnect")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AutoConnect")); #endif // Assume WiFi credentials are saved (workaround for ESP32 detection) @@ -215,8 +222,8 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { // attempt to connect using saved settings, on fail fallback to AP config portal if(!WiFi.enableSTA(true)){ // handle failure mode Brownout detector etc. - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[FATAL] Unable to enable wifi!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[FATAL] Unable to enable wifi!")); #endif return false; } @@ -244,43 +251,43 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { bool connected = false; if (WiFi.status() == WL_CONNECTED){ connected = true; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AutoConnect: ESP Already Connected")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AutoConnect: ESP Already Connected")); #endif setSTAConfig(); } if(connected || connectWifi(_defaultssid, _defaultpass) == WL_CONNECTED){ //connected - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AutoConnect: SUCCESS")); - DEBUG_WM(WM_DEBUG_VERBOSE,F("Connected in"),(String)((millis()-_startconn)) + " ms"); - DEBUG_WM(F("STA IP Address:"),WiFi.localIP()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AutoConnect: SUCCESS")); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Connected in"),(String)((millis()-_startconn)) + " ms"); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("STA IP Address:"),WiFi.localIP()); #endif _lastconxresult = WL_CONNECTED; if(_hostname != ""){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("hostname: STA: "),getWiFiHostname()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("hostname: STA: "),getWiFiHostname()); #endif } return true; // connected success } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AutoConnect: FAILED for "),(String)((millis()-_startconn)) + " ms"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AutoConnect: FAILED for "),(String)((millis()-_startconn)) + " ms"); #endif } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("No Credentials are Saved, skipping connect")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("No Credentials are Saved, skipping connect")); #endif } // possibly skip the config portal if (!_enableConfigPortal) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("enableConfigPortal: FALSE, skipping ")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("enableConfigPortal: FALSE, skipping ")); #endif return false; // not connected and not cp @@ -293,39 +300,39 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { bool WiFiManager::setupHostname(bool restart){ if(_hostname == "") { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("No Hostname to set")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("No Hostname to set")); #endif return false; } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting Hostnames: "),_hostname); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Setting Hostnames: "),_hostname); #endif } bool res = true; #ifdef ESP8266 - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting WiFi hostname")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Setting WiFi hostname")); #endif res = WiFi.hostname(_hostname.c_str()); #ifdef WM_MDNS - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting MDNS hostname, tcp 80")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Setting MDNS hostname, tcp 80")); #endif if(MDNS.begin(_hostname.c_str())){ MDNS.addService("http", "tcp", 80); } #endif #elif defined(ESP32) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting WiFi hostname")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Setting WiFi hostname")); #endif res = WiFi.setHostname(_hostname.c_str()); #ifdef WM_MDNS - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Setting MDNS hostname, tcp 80")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Setting MDNS hostname, tcp 80")); #endif if(MDNS.begin(_hostname.c_str())){ MDNS.addService("http", "tcp", 80); @@ -333,13 +340,13 @@ bool WiFiManager::setupHostname(bool restart){ #endif #endif - #ifdef WM_DEBUG_LEVEL - if(!res)DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] hostname: set failed!")); + #ifndef WM_NO_LOG + if(!res)log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] hostname: set failed!")); #endif if(restart && (WiFi.status() == WL_CONNECTED)){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("reconnecting to set new hostname")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("reconnecting to set new hostname")); #endif WiFi_Disconnect(); delay(200); // do not remove, need a delay for disconnect to change status() @@ -350,14 +357,14 @@ bool WiFiManager::setupHostname(bool restart){ bool WiFiManager::startAP(){ bool ret = true; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("StartAP with SSID: "),_apName); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("StartAP with SSID: "),_apName); #endif #ifdef ESP8266 if(!WiFi.enableAP(true)) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] enableAP failed!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] enableAP failed!")); #endif return false; } @@ -366,12 +373,12 @@ bool WiFiManager::startAP(){ // setup optional soft AP static ip config if (_ap_static_ip) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Custom AP IP/GW/Subnet:")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Custom AP IP/GW/Subnet:")); #endif if(!WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn)){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] softAPConfig failed!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] softAPConfig failed!")); #endif } } @@ -382,8 +389,8 @@ bool WiFiManager::startAP(){ else channel = _apChannel; if(channel>0){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting AP on channel:"),channel); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Starting AP on channel:"),channel); #endif } @@ -393,8 +400,8 @@ bool WiFiManager::startAP(){ return WiFi.softAP(_apName.c_str(), _apPassword.c_str(), apChannel, _apHidden); } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("AP has anonymous access!")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("AP has anonymous access!")); #endif return WiFi.softAP(_apName.c_str(), "", apChannel, _apHidden); }; @@ -402,30 +409,32 @@ bool WiFiManager::startAP(){ // Start soft AP with password or anonymous ret = startSoftAP(); for (uint8_t attempt = 1; !ret && attempt < kSoftApStartMaxAttempts; attempt++) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] softAP start failed, retry attempt"), attempt + 1); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] softAP start failed, retry attempt"), attempt + 1); #endif WiFi.softAPdisconnect(false); delay(150 * attempt); ret = startSoftAP(); } - if(_debugLevel >= WM_DEBUG_DEV) debugSoftAPConfig(); + if ((uint8_t)_runtimeMaxLevel >= (uint8_t)WiFiManagerLogLevel::Trace) { + debugSoftAPConfig(); + } delay(500); // slight delay to make sure we get an AP IP - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] There was a problem starting the AP")); - DEBUG_WM(F("AP IP address:"),WiFi.softAPIP()); + #ifndef WM_NO_LOG + if(!ret) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] There was a problem starting the AP")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AP IP address:"),WiFi.softAPIP()); #endif // set ap hostname #ifdef ESP32 if(ret && _hostname != ""){ bool res = WiFi.softAPsetHostname(_hostname.c_str()); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("setting softAP Hostname:"),_hostname); - if(!res)DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] hostname: AP set failed!")); - DEBUG_WM(WM_DEBUG_DEV,F("hostname: AP: "),WiFi.softAPgetHostname()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("setting softAP Hostname:"),_hostname); + if(!res)log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] hostname: AP set failed!")); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("hostname: AP: "),WiFi.softAPgetHostname()); #endif } #endif @@ -448,8 +457,8 @@ void WiFiManager::startWebPortal() { */ void WiFiManager::stopWebPortal() { if(!configPortalActive && !webPortalActive) return; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Stopping Web Portal")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Stopping Web Portal")); #endif webPortalActive = false; shutdownConfigPortal(); @@ -464,8 +473,8 @@ boolean WiFiManager::configPortalHasTimeout(){ // debug num clients every 30s if(millis() - timer > logintvl){ timer = millis(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("NUM CLIENTS: "),(String)WiFi_softap_num_stations()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("NUM CLIENTS: "),(String)WiFi_softap_num_stations()); #endif } _configPortalStart = millis(); // kludge, bump configportal start time to skew timeouts @@ -477,17 +486,17 @@ boolean WiFiManager::configPortalHasTimeout(){ // handle timed out if(millis() > _configPortalStart + _configPortalTimeout){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("config portal has timed out")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("config portal has timed out")); #endif return true; // timeout bail, else do debug logging } - else if(_debug && _debugLevel > 0) { + else if (_logEnabled && (uint8_t)_runtimeMaxLevel > (uint8_t)WiFiManagerLogLevel::Silent) { // log timeout time remaining every 30s if((millis() - timer) > logintvl){ timer = millis(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal Timeout In"),(String)((_configPortalStart + _configPortalTimeout-millis())/1000) + (String)F(" seconds")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Portal Timeout In"),(String)((_configPortalStart + _configPortalTimeout-millis())/1000) + (String)F(" seconds")); #endif } } @@ -521,8 +530,8 @@ void WiFiManager::startConfigPortal(char const *apName, char const *apPassword) _begin(); if(configPortalActive){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting Config Portal FAILED, is already running")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Starting Config Portal FAILED, is already running")); #endif return; } @@ -531,8 +540,8 @@ void WiFiManager::startConfigPortal(char const *apName, char const *apPassword) _apName = apName; _apPassword = apPassword; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Starting Config Portal")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Starting Config Portal")); #endif if(_apName == "") _apName = getDefaultAPName(); @@ -546,8 +555,8 @@ void WiFiManager::startConfigPortal(char const *apName, char const *apPassword) #endif WiFi_Disconnect(); WiFi_enableSTA(false); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Disabling STA")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Disabling STA")); #endif } @@ -559,37 +568,37 @@ void WiFiManager::startConfigPortal(char const *apName, char const *apPassword) _configPortalStart = millis(); // start access point - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Enabling AP")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Enabling AP")); #endif startAP(); WiFiSetCountry(); // do AP callback if set if ( _apcallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] _apcallback calling")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[CB] _apcallback calling")); #endif _apcallback(this); } // init configportal - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("setupConfigPortal")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("setupConfigPortal")); #endif setupConfigPortal(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("setupDNSD")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("setupDNSD")); #endif if (_serverManager) { _serverManager->setupDNSD(); } _scanLifecycleBlocked = false; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Config Portal Running (call process() periodically)")); - if(_configPortalTimeout > 0) DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal Timeout In"),(String)(_configPortalTimeout/1000) + (String)F(" seconds")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Config Portal Running (call process() periodically)")); + if(_configPortalTimeout > 0) log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Portal Timeout In"),(String)(_configPortalTimeout/1000) + (String)F(" seconds")); #endif } @@ -621,14 +630,14 @@ boolean WiFiManager::process(){ if(webPortalActive || configPortalActive){ // if timed out or abort, break if(_allowExit && (configPortalHasTimeout() || abort)){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV, F("process loop abort")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("process loop abort")); #endif webPortalActive = false; shutdownConfigPortal(); if (_configportaltimeoutcallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE, F("[CB] config portal timeout callback")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("[CB] config portal timeout callback")); #endif _configportaltimeoutcallback(); // @CALLBACK } @@ -655,34 +664,34 @@ uint8_t WiFiManager::processConfigPortal(){ connect = false; _scanLifecycleBlocked = true; resetAsyncScan(false); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("processing save")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("processing save")); #endif if(_enableCaptivePortal) delay(_cpclosedelay); // keeps the captiveportal from closing to fast. // skip wifi if no ssid if(_ssid == ""){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("No ssid, skipping wifi save")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("No ssid, skipping wifi save")); #endif } else{ // attempt sta connection to submitted _ssid, _pass uint8_t res = connectWifi(_ssid, _pass, _connectonsave) == WL_CONNECTED; if (res || (!_connectonsave)) { - #ifdef WM_DEBUG_LEVEL + #ifndef WM_NO_LOG if(!_connectonsave){ - DEBUG_WM(F("SAVED with no connect to new AP")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("SAVED with no connect to new AP")); } else { - DEBUG_WM(F("Connect to new AP [SUCCESS]")); - DEBUG_WM(F("Got IP Address:")); - DEBUG_WM(WiFi.localIP()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Connect to new AP [SUCCESS]")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Got IP Address:")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, WiFi.localIP()); } #endif if ( _savewificallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] _savewificallback calling")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[CB] _savewificallback calling")); #endif _savewificallback(); // @CALLBACK } @@ -694,16 +703,16 @@ uint8_t WiFiManager::processConfigPortal(){ _scanLifecycleBlocked = false; return WL_CONNECTED; // CONNECT SUCCESS } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] Connect to new AP Failed")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] Connect to new AP Failed")); #endif } if (_shouldBreakAfterConfig) { // Execute save callback when breaking after config if ( _savewificallback != NULL) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[CB] WiFi/Param save callback")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[CB] WiFi/Param save callback")); #endif _savewificallback(); // @CALLBACK } @@ -713,8 +722,8 @@ uint8_t WiFiManager::processConfigPortal(){ } else{ // Portal remaining open - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Portal remaining open")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Portal remaining open")); #endif } _scanLifecycleBlocked = false; @@ -728,8 +737,8 @@ uint8_t WiFiManager::processConfigPortal(){ * @return true if shutdown successful, false otherwise */ bool WiFiManager::shutdownConfigPortal(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("shutdownConfigPortal")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("shutdownConfigPortal")); #endif if(webPortalActive) return false; @@ -755,24 +764,24 @@ bool WiFiManager::shutdownConfigPortal(){ bool ret = false; ret = WiFi.softAPdisconnect(false); - #ifdef WM_DEBUG_LEVEL - if(!ret)DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] disconnect configportal - softAPdisconnect FAILED")); - DEBUG_WM(WM_DEBUG_VERBOSE,F("restoring usermode"),getModeString(_usermode)); + #ifndef WM_NO_LOG + if(!ret)log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] disconnect configportal - softAPdisconnect FAILED")); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("restoring usermode"),getModeString(_usermode)); #endif delay(1000); WiFi_Mode(_usermode); // restore users wifi mode if(WiFi.status()==WL_IDLE_STATUS){ WiFi.reconnect(); // restart wifi since we disconnected it in startconfigportal - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Reconnect, was idle")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("WiFi Reconnect, was idle")); #endif } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("wifi status:"),getWLStatusString(WiFi.status())); - DEBUG_WM(WM_DEBUG_VERBOSE,F("wifi mode:"),getModeString(WiFi.getMode())); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("wifi status:"),getWLStatusString(WiFi.status())); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("wifi mode:"),getModeString(WiFi.getMode())); #endif configPortalActive = false; - DEBUG_WM(WM_DEBUG_VERBOSE,F("configportal closed")); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("configportal closed")); _end(); _scanLifecycleBlocked = false; return ret; @@ -781,8 +790,8 @@ bool WiFiManager::shutdownConfigPortal(){ // TODO: Consider splitting saved vs new connect paths into separate methods // (e.g., connectSaved() and connectNew()) to reduce branching and improve testability. uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Connecting as wifi client...")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Connecting as wifi client...")); #endif uint8_t retry = 1; uint8_t connRes = (uint8_t)WL_NO_SSID_AVAIL; @@ -799,8 +808,8 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { while(retry <= _connectRetries && (connRes!=WL_CONNECTED)){ if(_connectRetries > 1){ if(_aggresiveReconn) delay(1000); // add idle time before recon - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Connect Wifi, ATTEMPT #"),(String)retry+" of "+(String)_connectRetries); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Connect Wifi, ATTEMPT #"),(String)retry+" of "+(String)_connectRetries); #endif } // If SSID argument provided, connect to that (also handles preload() _defaultssid) @@ -820,14 +829,14 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { connRes = waitForConnectResult(); } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("No wifi saved, skipping")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("No wifi saved, skipping")); #endif } } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Connection result:"),getWLStatusString(connRes)); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Connection result:"),getWLStatusString(connRes)); #endif retry++; } @@ -858,16 +867,16 @@ uint8_t WiFiManager::connectWifi(String ssid, String pass, bool connect) { */ bool WiFiManager::wifiConnectNew(String ssid, String pass,bool connect){ bool ret = false; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Connecting to NEW AP:"),ssid); - DEBUG_WM(WM_DEBUG_DEV,F("Using Password:"),pass); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Connecting to NEW AP:"),ssid); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("Using Password:"),pass); #endif WiFi_enableSTA(true,storeSTAmode); // storeSTAmode will also toggle STA on in default opmode (persistent) if true (default) WiFi.persistent(true); ret = WiFi.begin(ssid.c_str(), pass.c_str(), 0, NULL, connect); WiFi.persistent(false); - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); + #ifndef WM_NO_LOG + if(!ret) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] wifi begin failed")); #endif return ret; } @@ -879,23 +888,23 @@ bool WiFiManager::wifiConnectNew(String ssid, String pass,bool connect){ bool WiFiManager::wifiConnectDefault(){ bool ret = false; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Connecting to SAVED AP:"),WiFi_SSID(true)); - DEBUG_WM(WM_DEBUG_DEV,F("Using Password:"),WiFi_psk(true)); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Connecting to SAVED AP:"),WiFi_SSID(true)); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("Using Password:"),WiFi_psk(true)); #endif ret = WiFi_enableSTA(true,storeSTAmode); delay(500); // Required delay for ESP8266 mode change to stabilize - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("Mode after delay: "),getModeString(WiFi.getMode())); - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi enableSta failed")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("Mode after delay: "),getModeString(WiFi.getMode())); + if(!ret) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] wifi enableSta failed")); #endif ret = WiFi.begin(); - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi begin failed")); + #ifndef WM_NO_LOG + if(!ret) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] wifi begin failed")); #endif return ret; @@ -907,35 +916,35 @@ bool WiFiManager::wifiConnectDefault(){ * @return true if config succeeded or no config needed, false on error */ bool WiFiManager::setSTAConfig(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("STA static IP:"),_sta_static_ip); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("STA static IP:"),_sta_static_ip); #endif bool ret = true; if (_sta_static_ip) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom static IP/GW/Subnet/DNS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Custom static IP/GW/Subnet/DNS")); #endif if(_sta_static_dns) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom static DNS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Custom static DNS")); #endif ret = WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns); } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Custom STA IP/GW/Subnet")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Custom STA IP/GW/Subnet")); #endif ret = WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); } - #ifdef WM_DEBUG_LEVEL - if(!ret) DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] wifi config failed")); - else DEBUG_WM(F("STA IP set:"),WiFi.localIP()); + #ifndef WM_NO_LOG + if(!ret) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] wifi config failed")); + else log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("STA IP set:"),WiFi.localIP()); #endif } else { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("setSTAConfig static ip not set, skipping")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("setSTAConfig static ip not set, skipping")); #endif } return ret; @@ -952,21 +961,21 @@ void WiFiManager::updateConxResult(uint8_t status){ } #elif defined(ESP32) if(_lastconxresult == WL_CONNECT_FAILED || _lastconxresult == WL_DISCONNECTED){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("lastconxresulttmp:"),getWLStatusString(_lastconxresulttmp)); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("lastconxresulttmp:"),getWLStatusString(_lastconxresulttmp)); #endif if(_lastconxresulttmp != WL_IDLE_STATUS){ _lastconxresult = _lastconxresulttmp; } } - DEBUG_WM(WM_DEBUG_DEV,F("lastconxresult:"),getWLStatusString(_lastconxresult)); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("lastconxresult:"),getWLStatusString(_lastconxresult)); #endif } uint8_t WiFiManager::waitForConnectResult() { - #ifdef WM_DEBUG_LEVEL - if(_connectTimeout > 0) DEBUG_WM(WM_DEBUG_DEV,_connectTimeout,F("ms connectTimeout set")); + #ifndef WM_NO_LOG + if(_connectTimeout > 0) log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,_connectTimeout,F("ms connectTimeout set")); #endif return waitForConnectResult(_connectTimeout); } @@ -978,15 +987,15 @@ uint8_t WiFiManager::waitForConnectResult() { */ uint8_t WiFiManager::waitForConnectResult(uint32_t timeout) { if (timeout == 0){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("connectTimeout not set, ESP waitForConnectResult...")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("connectTimeout not set, ESP waitForConnectResult...")); #endif return WiFi.waitForConnectResult(); } unsigned long timeoutmillis = millis() + timeout; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,timeout,F("ms timeout, waiting for connect...")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,timeout,F("ms timeout, waiting for connect...")); #endif uint8_t status = WiFi.status(); @@ -995,8 +1004,8 @@ uint8_t WiFiManager::waitForConnectResult(uint32_t timeout) { if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) { return status; } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM (WM_DEBUG_VERBOSE,F(".")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F(".")); #endif delay(100); } @@ -1006,14 +1015,14 @@ uint8_t WiFiManager::waitForConnectResult(uint32_t timeout) { // WPS enabled? https://github.com/esp8266/Arduino/pull/4889 #ifdef NO_EXTRA_4K_HEAP void WiFiManager::startWPS() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("START WPS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("START WPS")); #endif #ifdef ESP8266 WiFi.beginWPSConfig(); #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("END WPS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("END WPS")); #endif } #endif @@ -1041,13 +1050,13 @@ bool WiFiManager::WiFi_scanNetworks(unsigned int cachetime){ bool WiFiManager::WiFi_scanNetworks(bool force){ if(_numNetworks == 0 && _autoforcerescan){ - DEBUG_WM(WM_DEBUG_DEV,"NO APs found forcing new scan"); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,"NO APs found forcing new scan"); force = true; } if(!force && hasFreshScanResults(_scancachetime)){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Scan is cached"),(String)(millis()-_lastscan )+" ms ago"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Scan is cached"),(String)(millis()-_lastscan )+" ms ago"); #endif return true; } @@ -1184,8 +1193,8 @@ bool WiFiManager::startAsyncScan() { _scan.runningGeneration = _scan.generation; _scan.completionGeneration = 0; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC started")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("WiFi Scan ASYNC started")); #endif #ifdef ESP8266 @@ -1200,8 +1209,8 @@ bool WiFiManager::startAsyncScan() { _scan.forceRefresh = false; return true; #else - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] Async scan not available on this ESP8266 core")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] Async scan not available on this ESP8266 core")); #endif failAsyncScan(WM_SCAN_FAILED); return false; @@ -1264,9 +1273,9 @@ void WiFiManager::finalizeAsyncScan(int networksFound) { _scan.runningGeneration = 0; WiFi.scanDelete(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC completed"), "in "+(String)(_scan.finishedAt - _scan.startedAt)+" ms"); - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFi Scan ASYNC found:"),_numNetworks); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("WiFi Scan ASYNC completed"), "in "+(String)(_scan.finishedAt - _scan.startedAt)+" ms"); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("WiFi Scan ASYNC found:"),_numNetworks); #endif } @@ -1286,11 +1295,11 @@ void WiFiManager::failAsyncScan(wm_scan_state_t state, int scanResult) { _scan.runningGeneration = 0; _scanResultsCache.clear(); - #ifdef WM_DEBUG_LEVEL + #ifndef WM_NO_LOG if (state == WM_SCAN_TIMEOUT) { - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] scan timed out")); + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] scan timed out")); } else { - DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] scan failed")); + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] scan failed")); } #endif } @@ -1376,13 +1385,13 @@ void WiFiManager::stopConfigPortal(){ */ bool WiFiManager::disconnect(){ if(WiFi.status() != WL_CONNECTED){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("Disconnecting: Not connected")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Disconnecting: Not connected")); #endif return false; } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Disconnecting")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Disconnecting")); #endif return WiFi_Disconnect(); } @@ -1392,8 +1401,8 @@ bool WiFiManager::disconnect(){ * @access public */ void WiFiManager::reboot(){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Restarting")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Restarting")); #endif ESP.restart(); } @@ -1407,24 +1416,24 @@ bool WiFiManager::erase(){ } bool WiFiManager::erase(bool opt){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM("Erasing"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, "Erasing"); #endif #if defined(ESP32) && ((defined(WM_ERASE_NVS) || defined(nvs_flash_h))) // if opt true, do nvs erase if(opt){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing NVS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Erasing NVS")); #endif esp_err_t err; err = nvs_flash_init(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("nvs_flash_init: "),err!=ESP_OK ? (String)err : "Success"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("nvs_flash_init: "),err!=ESP_OK ? (String)err : "Success"); #endif err = nvs_flash_erase(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("nvs_flash_erase: "), err!=ESP_OK ? (String)err : "Success"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("nvs_flash_erase: "), err!=ESP_OK ? (String)err : "Success"); #endif return err == ESP_OK; } @@ -1432,16 +1441,16 @@ bool WiFiManager::erase(bool opt){ if(opt){ bool ret = false; if(SPIFFS.begin()){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing SPIFFS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Erasing SPIFFS")); #endif bool ret = SPIFFS.format(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("spiffs erase: "),ret ? "Success" : "ERROR"); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("spiffs erase: "),ret ? "Success" : "ERROR"); #endif } else{ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("[ERROR] Could not start SPIFFS")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[ERROR] Could not start SPIFFS")); #endif } return ret; @@ -1450,8 +1459,8 @@ bool WiFiManager::erase(bool opt){ (void)opt; #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("Erasing WiFi Config")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Erasing WiFi Config")); #endif return WiFi_eraseConfig(); } @@ -1462,8 +1471,8 @@ bool WiFiManager::erase(bool opt){ * @access public */ void WiFiManager::resetSettings() { -#ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("resetSettings")); +#ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("resetSettings")); #endif WiFi_enableSTA(true,true); // must be sta to disconnect erase delay(500); // ensure sta is enabled @@ -1478,8 +1487,8 @@ void WiFiManager::resetSettings() { WiFi.disconnect(true); WiFi.persistent(false); #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("SETTINGS ERASED")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("SETTINGS ERASED")); #endif } @@ -1548,26 +1557,101 @@ void WiFiManager::setSaveConnect(bool connect) { _connectonsave = connect; } -/** - * [setDebugOutput description] - * @access public - * @param {[type]} boolean debug [description] - */ -void WiFiManager::setDebugOutput(boolean debug) { - _debug = debug; - if(_debug && _debugLevel == WM_DEBUG_DEV) debugPlatformInfo(); - if(_debug && _debugLevel >= WM_DEBUG_NOTIFY)DEBUG_WM((__FlashStringHelper *)WM_VERSION_STR," D:"+String(_debugLevel)); +void WiFiManager::setLogEnabled(boolean enabled) { + _logEnabled = enabled; + if (_logEnabled && (uint8_t)_runtimeMaxLevel == (uint8_t)WiFiManagerLogLevel::Trace) { + debugPlatformInfo(); + } + if (_logEnabled && (uint8_t)_runtimeMaxLevel >= (uint8_t)WiFiManagerLogLevel::Info) { + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, (__FlashStringHelper*)WM_VERSION_STR, + String(F(" D:")) + String((uint8_t)_runtimeMaxLevel)); + } } -void WiFiManager::setDebugOutput(boolean debug, String prefix) { - _debugPrefix = prefix; - setDebugOutput(debug); +void WiFiManager::setLogPrefix(String prefix) { + _logPrefix = prefix; } -void WiFiManager::setDebugOutput(boolean debug, wm_debuglevel_t level) { - _debugLevel = level; - // _debugPrefix = prefix; - setDebugOutput(debug); +void WiFiManager::setLogOutput(boolean enabled, WiFiManagerLogLevel maxLevel) { + _runtimeMaxLevel = maxLevel; + setLogEnabled(enabled); +} + +void WiFiManager::setLogSink(WiFiManagerLogSink* sink) { + _logSink = sink; +} + +WiFiManagerLogSink* WiFiManager::getLogSink() { + return _logSink; +} + +void WiFiManager::log(WiFiManagerLogLevel level, const char* subsystem, const String& text) { +#ifndef WM_NO_LOG + emitLogImpl(level, subsystem, text, String()); +#endif +} + +void WiFiManager::emitLogImpl(WiFiManagerLogLevel level, const char* subsystem, const String& textA, + const String& textB) { +#ifndef WM_NO_LOG + if (!_logEnabled || (uint8_t)_runtimeMaxLevel < (uint8_t)level) { + return; + } + +#if defined(ESP32) + if ((uint8_t)_runtimeMaxLevel >= (uint8_t)WiFiManagerLogLevel::Trace) { + multi_heap_info_t info; + heap_caps_get_info(&info, MALLOC_CAP_INTERNAL); + uint32_t free = info.total_free_bytes; + uint16_t maxb = info.largest_free_block; + uint8_t frag = (free > 0) ? static_cast(100 - (maxb * 100) / free) : 0; + String memLine; + memLine.reserve(64); + memLine += F("[MEM] free: "); + memLine += String(free); + memLine += F(" | max: "); + memLine += String(maxb); + memLine += F(" | frag: "); + memLine += String(frag); + memLine += F("%"); + WiFiManagerLogMessage memMsg{WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, memLine}; + if (_logSink) { + _logSink->log(memMsg); + } else { + _logPort.print(memLine); + _logPort.println(); + } + } +#endif + + String line; + line.reserve(96u + textA.length() + textB.length()); + line += _logPrefix; + if ((uint8_t)_runtimeMaxLevel >= (uint8_t)_logTagMinLevel) { + line += F("["); + line += String(static_cast((uint8_t)level)); + line += F("] "); + } + const char* sub = subsystem ? subsystem : kWiFiMgrLogSubsystem; + if (strcmp(sub, kWiFiMgrLogSubsystem) != 0) { + line += F("["); + line += sub; + line += F("] "); + } + line += textA; + if (textB.length() > 0) { + line += F(" "); + line += textB; + } + + WiFiManagerLogMessage msg{level, sub, std::move(line)}; + if (_logSink) { + _logSink->log(msg); + } else { + _logPort.print(msg.line); + _logPort.println(); + } +#endif } @@ -1734,8 +1818,8 @@ void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { void WiFiManager::setRestorePersistent(boolean persistent) { _userpersistent = persistent; if(!persistent){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("persistent is off")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("persistent is off")); #endif } } @@ -1866,16 +1950,16 @@ void WiFiManager::setDisableConfigPortal(boolean enable) */ bool WiFiManager::setHostname(const char * hostname){ if (hostname == nullptr) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] hostname: null value rejected")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] hostname: null value rejected")); #endif return false; } String candidate(hostname); if (!normalizeHostname(candidate)) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] hostname: invalid value rejected")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] hostname: invalid value rejected")); #endif return false; } @@ -1886,8 +1970,8 @@ bool WiFiManager::setHostname(const char * hostname){ bool WiFiManager::setHostname(String hostname){ if (!normalizeHostname(hostname)) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] hostname: invalid value rejected")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] hostname: invalid value rejected")); #endif return false; } @@ -2112,23 +2196,23 @@ void WiFiManager::debugSoftAPConfig(){ esp_wifi_get_country(&country); #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("SoftAP Configuration")); - DEBUG_WM(F("--------------------")); - DEBUG_WM(F("ssid: "),(char *) config.ssid); - DEBUG_WM(F("password: "),(char *) config.password); - DEBUG_WM(F("ssid_len: "),config.ssid_len); - DEBUG_WM(F("channel: "),config.channel); - DEBUG_WM(F("authmode: "),config.authmode); - DEBUG_WM(F("ssid_hidden: "),config.ssid_hidden); - DEBUG_WM(F("max_connection: "),config.max_connection); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("SoftAP Configuration")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("--------------------")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("ssid: "),(char *) config.ssid); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("password: "),(char *) config.password); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("ssid_len: "),config.ssid_len); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("channel: "),config.channel); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("authmode: "),config.authmode); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("ssid_hidden: "),config.ssid_hidden); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("max_connection: "),config.max_connection); #endif #if !defined(WM_NOCOUNTRY) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("country: "),(String)country.cc); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("country: "),(String)country.cc); #endif - DEBUG_WM(F("beacon_interval: "),(String)config.beacon_interval + "(ms)"); - DEBUG_WM(F("--------------------")); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("beacon_interval: "),(String)config.beacon_interval + "(ms)"); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("--------------------")); #endif } @@ -2140,25 +2224,26 @@ void WiFiManager::debugSoftAPConfig(){ void WiFiManager::debugPlatformInfo(){ #ifdef ESP8266 system_print_meminfo(); - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("[SYS] getCoreVersion(): "),ESP.getCoreVersion()); - DEBUG_WM(F("[SYS] system_get_sdk_version(): "),system_get_sdk_version()); - DEBUG_WM(F("[SYS] system_get_boot_version():"),system_get_boot_version()); - DEBUG_WM(F("[SYS] getFreeHeap(): "),(String)ESP.getFreeHeap()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] getCoreVersion(): "),ESP.getCoreVersion()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] system_get_sdk_version(): "),system_get_sdk_version()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] system_get_boot_version():"),system_get_boot_version()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] getFreeHeap(): "),(String)ESP.getFreeHeap()); #endif #elif defined(ESP32) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("[SYS] WM version: "), String((__FlashStringHelper *)WM_VERSION_STR) +" D:"+String(_debugLevel)); - DEBUG_WM(F("[SYS] Arduino version: "), VER_ARDUINO_STR); - DEBUG_WM(F("[SYS] ESP SDK version: "), ESP.getSdkVersion()); - DEBUG_WM(F("[SYS] Free heap: "), ESP.getFreeHeap()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] WM version: "), + String((__FlashStringHelper*)WM_VERSION_STR) + String(F(" D:")) + String((uint8_t)_runtimeMaxLevel)); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Arduino version: "), VER_ARDUINO_STR); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] ESP SDK version: "), ESP.getSdkVersion()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Free heap: "), ESP.getFreeHeap()); #endif - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("[SYS] Chip ID:"),WIFI_getChipId()); - DEBUG_WM(F("[SYS] Chip Model:"), ESP.getChipModel()); - DEBUG_WM(F("[SYS] Chip Cores:"), ESP.getChipCores()); - DEBUG_WM(F("[SYS] Chip Rev:"), ESP.getChipRevision()); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Chip ID:"),WIFI_getChipId()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Chip Model:"), ESP.getChipModel()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Chip Cores:"), ESP.getChipCores()); + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("[SYS] Chip Rev:"), ESP.getChipRevision()); #endif #endif } @@ -2182,15 +2267,15 @@ boolean WiFiManager::validApPassword(){ if (_apPassword == NULL) _apPassword = ""; if (_apPassword != "") { if (!WiFiManagerUtils::isValidAPPassword(_apPassword)) { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(F("AccessPoint set password is INVALID or <8 chars")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("AccessPoint set password is INVALID or <8 chars")); #endif _apPassword = ""; return false; // Fail secure - invalid password } - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("AccessPoint set password is VALID")); - DEBUG_WM(WM_DEBUG_DEV,"ap pass",_apPassword); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("AccessPoint set password is VALID")); + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,"ap pass",_apPassword); #endif } return true; @@ -2230,15 +2315,15 @@ const wifi_country_t WM_COUNTRY_JP{"JP",1,14,WIFI_COUNTRY_POLICY_AUTO}; bool WiFiManager::WiFiSetCountry(){ if(_wificountry == "") return false; // skip not set - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("WiFiSetCountry to"),_wificountry); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("WiFiSetCountry to"),_wificountry); #endif bool ret = true; #ifdef ESP32 esp_err_t err = ESP_OK; if(WiFi.getMode() == WIFI_MODE_NULL){ - DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] cannot set country, wifi not init"); + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,"[ERROR] cannot set country, wifi not init"); // TODO: Document precondition: WiFi must be initialized (mode != NULL) before setting country return false; } @@ -2253,15 +2338,15 @@ bool WiFiManager::WiFiSetCountry(){ #ifndef WM_NOCOUNTRY err = esp_wifi_set_country_code(_wificountry.c_str(), true); #else - DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] esp wifi set country is not available"); + log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,"[ERROR] esp wifi set country is not available"); err = true; #endif } - #ifdef WM_DEBUG_LEVEL + #ifndef WM_NO_LOG if(err){ - if(err == ESP_ERR_WIFI_NOT_INIT) DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_NOT_INIT"); - else if(err == ESP_ERR_INVALID_ARG) DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] ESP_ERR_WIFI_ARG (invalid country code)"); - else if(err != ESP_OK)DEBUG_WM(WM_DEBUG_ERROR,"[ERROR] unknown error",(String)err); + if(err == ESP_ERR_WIFI_NOT_INIT) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,"[ERROR] ESP_ERR_WIFI_NOT_INIT"); + else if(err == ESP_ERR_INVALID_ARG) log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,"[ERROR] ESP_ERR_WIFI_ARG (invalid country code)"); + else if(err != ESP_OK)log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,"[ERROR] unknown error",(String)err); } #endif ret = err == ESP_OK; @@ -2271,14 +2356,14 @@ bool WiFiManager::WiFiSetCountry(){ if(_wificountry == "US") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_US); else if(_wificountry == "JP") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_JP); else if(_wificountry == "CN") ret = wifi_set_country((wifi_country_t*)&WM_COUNTRY_CN); - #ifdef WM_DEBUG_LEVEL - else DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] country code not found")); + #ifndef WM_NO_LOG + else log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] country code not found")); #endif #endif - #ifdef WM_DEBUG_LEVEL - if(ret) DEBUG_WM(WM_DEBUG_VERBOSE,F("[OK] esp_wifi_set_country: "),_wificountry); - else DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] esp_wifi_set_country failed")); + #ifndef WM_NO_LOG + if(ret) log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[OK] esp_wifi_set_country: "),_wificountry); + else log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] esp_wifi_set_country failed")); #endif return ret; } @@ -2311,8 +2396,8 @@ bool WiFiManager::WiFi_Disconnect() { #ifdef ESP8266 if((WiFi.getMode() & WIFI_STA) != 0) { bool ret; - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi station disconnect")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("WiFi station disconnect")); #endif ETS_UART_INTR_DISABLE(); // @todo possibly not needed ret = wifi_station_disconnect(); @@ -2320,8 +2405,8 @@ bool WiFiManager::WiFi_Disconnect() { return ret; } #elif defined(ESP32) - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi station disconnect")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("WiFi station disconnect")); #endif return WiFi.disconnect(); // not persistent atm #endif @@ -2330,8 +2415,8 @@ bool WiFiManager::WiFi_Disconnect() { // toggle STA without persistent bool WiFiManager::WiFi_enableSTA(bool enable,bool persistent) { -#ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi_enableSTA"),(String) enable? "enable" : "disable"); +#ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("WiFi_enableSTA"),(String) enable? "enable" : "disable"); #endif #ifdef ESP8266 WiFiMode_t newMode; @@ -2342,8 +2427,8 @@ bool WiFiManager::WiFi_enableSTA(bool enable,bool persistent) { if((isEnabled != enable) || persistent) { if(enable) { - #ifdef WM_DEBUG_LEVEL - if(persistent) DEBUG_WM(WM_DEBUG_DEV,F("enableSTA PERSISTENT ON")); + #ifndef WM_NO_LOG + if(persistent) log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("enableSTA PERSISTENT ON")); #endif return WiFi_Mode(newMode,persistent); } @@ -2367,8 +2452,8 @@ bool WiFiManager::WiFi_enableSTA(bool enable) { } bool WiFiManager::WiFi_eraseConfig() { - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_DEV,F("WiFi_eraseConfig")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("WiFi_eraseConfig")); #endif #ifdef ESP8266 @@ -2478,22 +2563,22 @@ String WiFiManager::WiFi_psk(bool persistent) const { return; } if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED){ - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: "),info.wifi_sta_disconnected.reason); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[EVENT] WIFI_REASON: "),info.wifi_sta_disconnected.reason); #endif if(info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE || info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_FAIL){ _lastconxresulttmp = 7; // Wrong password detected - SDK emits WIFI_REASON_AUTH_EXPIRE on some routers on auth_fail } else _lastconxresulttmp = WiFi.status(); - #ifdef WM_DEBUG_LEVEL - if(info.wifi_sta_disconnected.reason == WIFI_REASON_NO_AP_FOUND) DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: NO_AP_FOUND")); + #ifndef WM_NO_LOG + if(info.wifi_sta_disconnected.reason == WIFI_REASON_NO_AP_FOUND) log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[EVENT] WIFI_REASON: NO_AP_FOUND")); if(info.wifi_sta_disconnected.reason == WIFI_REASON_ASSOC_FAIL){ if(_aggresiveReconn && _connectRetries<4) _connectRetries=4; - DEBUG_WM(WM_DEBUG_VERBOSE,F("[EVENT] WIFI_REASON: AUTH FAIL")); + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[EVENT] WIFI_REASON: AUTH FAIL")); } #endif #ifdef esp32autoreconnect - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("[Event] SYSTEM_EVENT_STA_DISCONNECTED, reconnecting")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("[Event] SYSTEM_EVENT_STA_DISCONNECTED, reconnecting")); #endif WiFi.reconnect(); #endif @@ -2510,8 +2595,8 @@ void WiFiManager::WiFi_autoReconnect(){ WiFi.setAutoReconnect(_wifiAutoReconnect); #elif defined(ESP32) // Enable ESP32 event handler for auto-reconnect - #ifdef WM_DEBUG_LEVEL - DEBUG_WM(WM_DEBUG_VERBOSE,F("ESP32 event handler enabled")); + #ifndef WM_NO_LOG + log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("ESP32 event handler enabled")); #endif using namespace std::placeholders; if(wm_event_id == 0) wm_event_id = WiFi.onEvent(std::bind(&WiFiManager::WiFiEvent,this,_1,_2)); diff --git a/lib/WiFiManager/src/WiFiManagerHandlers.cpp b/lib/WiFiManager/src/WiFiManagerHandlers.cpp index f709c12..3dd8686 100644 --- a/lib/WiFiManager/src/WiFiManagerHandlers.cpp +++ b/lib/WiFiManager/src/WiFiManagerHandlers.cpp @@ -21,6 +21,7 @@ #include "templates/Param.h" #include "templates/WiFi.h" #include "templates/RootSelector.h" +#include "templates/PortalAppJS.h" #include #include @@ -30,6 +31,75 @@ #define WM_PAGE_RESERVE_BYTES 8192 #endif +static void jsonAppendEscaped(String& out, const String& s) { + for (size_t i = 0; i < s.length(); i++) { + const char c = s[i]; + if (c == '"') { + out += F("\\\""); + } else if (c == '\\') { + out += F("\\\\"); + } else if (c == '\n') { + out += F("\\n"); + } else if (c == '\r') { + // skip + } else { + out += c; + } + } +} + +/** Parse a single `
...
...
` row from `getInfoData` HTML. */ +static bool parseInfoRowDtDd(const String& html, String& label, String& value) { + const int dtOpen = html.indexOf(F("
")); + if (dtOpen < 0) { + return false; + } + const int dtClose = html.indexOf(F("
"), dtOpen); + if (dtClose < 0) { + return false; + } + label = html.substring(dtOpen + 4, dtClose); + const int ddOpen = html.indexOf(F("
"), dtClose); + if (ddOpen < 0) { + return false; + } + const int ddClose = html.indexOf(F("
"), ddOpen); + if (ddClose < 0) { + return false; + } + value = html.substring(ddOpen + 4, ddClose); + return true; +} + +static void appendJsonInfoArrayFromIds(WiFiManagerHandlers* handlers, + String& json, + const char* const* ids, + size_t count, + bool& first) { + for (size_t i = 0; i < count; i++) { + const String row = handlers->getInfoData(ids[i]); + if (row.length() == 0) { + continue; + } + String label; + String value; + if (!parseInfoRowDtDd(row, label, value)) { + continue; + } + if (!first) { + json += F(","); + } + first = false; + json += F("{\"key\":\""); + json += ids[i]; + json += F("\",\"label\":\""); + jsonAppendEscaped(json, label); + json += F("\",\"value\":\""); + jsonAppendEscaped(json, value); + json += F("\"}"); + } +} + namespace { const char kEmptyTemplateChunk[] PROGMEM = ""; @@ -95,11 +165,6 @@ void registerShellTemplate(PlaceholderRegistry& registry, registry.registerProgmemTemplate("%PAGE_CONTENT%", pageContentTemplate); } -struct RootState { - String menu; - String status; -}; - struct MessagePageState { String docTitle; const char* bodyClass; @@ -153,69 +218,36 @@ void escapePercentsForTemplate(String& value) { value = escaped; } -void registerDynamicStringPlaceholder(PlaceholderRegistry& registry, - const char* placeholder, - String& value, - DynamicTemplateDescriptor& descriptor) { - escapePercentsForTemplate(value); - configureDynamicStringDescriptor(descriptor, value); - registry.registerDynamicTemplate(placeholder, &descriptor); -} - -String renderTemplateToString(const char* templateData, PlaceholderRegistry& registry) { - TemplateContext context; - context.setRegistry(®istry); - TemplateRenderer::initializeContext(context, templateData); - - uint8_t buffer[128]; - String output; - while (true) { - size_t written = TemplateRenderer::renderNextChunk(context, buffer, sizeof(buffer)); - if (written == 0) { - break; - } - output.concat(reinterpret_cast(buffer), written); - } - return output; -} - String renderActionForm(const String& action, const String& method, const String& label, const String& buttonClassAttr = String(), const String& prefix = String(), const String& suffix = String()) { - PlaceholderRegistry registry(6); - DynamicTemplateDescriptor actionDescriptor; - DynamicTemplateDescriptor methodDescriptor; - DynamicTemplateDescriptor labelDescriptor; - DynamicTemplateDescriptor classDescriptor; - DynamicTemplateDescriptor prefixDescriptor; - DynamicTemplateDescriptor suffixDescriptor; - - String actionValue = action; - String methodValue = method; - String labelValue = label; - String classValue = buttonClassAttr; - String prefixValue = prefix; - String suffixValue = suffix; - - registerDynamicStringPlaceholder(registry, "%ACTION%", actionValue, actionDescriptor); - registerDynamicStringPlaceholder(registry, "%METHOD%", methodValue, methodDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_LABEL%", labelValue, labelDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_CLASS_ATTR%", classValue, classDescriptor); - registerDynamicStringPlaceholder(registry, "%ACTION_PREFIX%", prefixValue, prefixDescriptor); - registerDynamicStringPlaceholder(registry, "%ACTION_SUFFIX%", suffixValue, suffixDescriptor); - - return renderTemplateToString(WM_ACTION_FORM_TEMPLATE, registry); + String output; + reservePage(output, prefix.length() + suffix.length() + action.length() + method.length() + + label.length() + buttonClassAttr.length() + 48); + output += prefix; + output += F("
"); + output += label; + output += F(""); + output += suffix; + return output; } String renderSubmitButton(const String& label) { - PlaceholderRegistry registry(1); - DynamicTemplateDescriptor labelDescriptor; - String labelValue = label; - registerDynamicStringPlaceholder(registry, "%BUTTON_LABEL%", labelValue, labelDescriptor); - return renderTemplateToString(WM_SUBMIT_BUTTON_TEMPLATE, registry); + String output; + reservePage(output, label.length() + 40); + output += F("

"); + return output; } String renderCenteredButton(const String& id, @@ -223,26 +255,21 @@ String renderCenteredButton(const String& id, const String& onClick, const String& label, const String& extraAttrs = String()) { - PlaceholderRegistry registry(5); - DynamicTemplateDescriptor idDescriptor; - DynamicTemplateDescriptor typeDescriptor; - DynamicTemplateDescriptor onClickDescriptor; - DynamicTemplateDescriptor labelDescriptor; - DynamicTemplateDescriptor extraAttrsDescriptor; - - String idValue = id; - String typeValue = type; - String onClickValue = onClick; - String labelValue = label; - String extraAttrsValue = extraAttrs; - - registerDynamicStringPlaceholder(registry, "%BUTTON_ID%", idValue, idDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_TYPE%", typeValue, typeDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_ONCLICK%", onClickValue, onClickDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_LABEL%", labelValue, labelDescriptor); - registerDynamicStringPlaceholder(registry, "%BUTTON_EXTRA_ATTRS%", extraAttrsValue, extraAttrsDescriptor); - - return renderTemplateToString(WM_CENTERED_BUTTON_TEMPLATE, registry); + String output; + reservePage(output, id.length() + type.length() + onClick.length() + label.length() + + extraAttrs.length() + 72); + output += F("
"); + return output; } String renderSectionBreak(const String& content) { @@ -250,19 +277,19 @@ String renderSectionBreak(const String& content) { return String(); } - PlaceholderRegistry registry(1); - DynamicTemplateDescriptor contentDescriptor; - String contentValue = content; - registerDynamicStringPlaceholder(registry, "%SECTION_CONTENT%", contentValue, contentDescriptor); - return renderTemplateToString(WM_SECTION_BREAK_TEMPLATE, registry); + String output; + reservePage(output, content.length() + 16); + output += F("

"); + output += content; + return output; } String renderScanMessage(const String& message) { - PlaceholderRegistry registry(1); - DynamicTemplateDescriptor messageDescriptor; - String messageValue = message; - registerDynamicStringPlaceholder(registry, "%SCAN_MESSAGE%", messageValue, messageDescriptor); - return renderTemplateToString(WM_SCAN_MESSAGE_TEMPLATE, registry); + String output; + reservePage(output, message.length() + 16); + output += message; + output += F("

"); + return output; } String renderScanRow(const String& ssidAttr, @@ -273,35 +300,31 @@ String renderScanRow(const String& ssidAttr, const String& iconVisibilityClass, const String& valueVisibilityClass, const String& qualityValue) { - PlaceholderRegistry registry(8); - DynamicTemplateDescriptor ssidAttrDescriptor; - DynamicTemplateDescriptor ssidTextDescriptor; - DynamicTemplateDescriptor qualityLabelDescriptor; - DynamicTemplateDescriptor qualityIconDescriptor; - DynamicTemplateDescriptor lockClassDescriptor; - DynamicTemplateDescriptor iconVisibilityDescriptor; - DynamicTemplateDescriptor valueVisibilityDescriptor; - DynamicTemplateDescriptor qualityValueDescriptor; - - String ssidAttrValue = ssidAttr; - String ssidTextValue = ssidText; - String qualityLabelValue = qualityLabel; - String qualityIconValue = qualityIcon; - String lockClassValue = lockClass; - String iconVisibilityValue = iconVisibilityClass; - String valueVisibilityValue = valueVisibilityClass; - String qualityValueValue = qualityValue; - - registerDynamicStringPlaceholder(registry, "%SSID_ATTR%", ssidAttrValue, ssidAttrDescriptor); - registerDynamicStringPlaceholder(registry, "%SSID_TEXT%", ssidTextValue, ssidTextDescriptor); - registerDynamicStringPlaceholder(registry, "%QUALITY_LABEL%", qualityLabelValue, qualityLabelDescriptor); - registerDynamicStringPlaceholder(registry, "%QUALITY_ICON%", qualityIconValue, qualityIconDescriptor); - registerDynamicStringPlaceholder(registry, "%LOCK_CLASS%", lockClassValue, lockClassDescriptor); - registerDynamicStringPlaceholder(registry, "%ICON_VISIBILITY_CLASS%", iconVisibilityValue, iconVisibilityDescriptor); - registerDynamicStringPlaceholder(registry, "%VALUE_VISIBILITY_CLASS%", valueVisibilityValue, valueVisibilityDescriptor); - registerDynamicStringPlaceholder(registry, "%QUALITY_VALUE%", qualityValueValue, qualityValueDescriptor); - - return renderTemplateToString(WM_SCAN_RESULT_ROW_TEMPLATE, registry); + String output; + reservePage(output, ssidAttr.length() + ssidText.length() + qualityLabel.length() + + qualityIcon.length() + lockClass.length() + + iconVisibilityClass.length() + valueVisibilityClass.length() + + qualityValue.length() + 160); + output += F("
"); + output += ssidText; + output += F("
"); + output += qualityValue; + output += F("
"); + return output; } String renderFieldTemplate(const char* templateData, @@ -310,105 +333,104 @@ String renderFieldTemplate(const char* templateData, const String& maxLength, const String& value, const String& extraAttrs = String()) { - PlaceholderRegistry registry(6); - DynamicTemplateDescriptor idDescriptor; - DynamicTemplateDescriptor nameDescriptor; - DynamicTemplateDescriptor labelDescriptor; - DynamicTemplateDescriptor maxLengthDescriptor; - DynamicTemplateDescriptor valueDescriptor; - DynamicTemplateDescriptor extraAttrsDescriptor; + String input; + reservePage(input, id.length() + label.length() + maxLength.length() + value.length() + + extraAttrs.length() + 96); + input += F(""); - String idValue = id; - String nameValue = id; - String labelValue = label; - String maxLengthValue = maxLength; - String valueValue = value; - String extraAttrsValue = extraAttrs; + if (templateData == WM_FIELD_LABEL_BEFORE_TEMPLATE) { + String output; + reservePage(output, label.length() + input.length() + 32); + output += F("
"); + output += input; + return output; + } - registerDynamicStringPlaceholder(registry, "%FIELD_ID%", idValue, idDescriptor); - registerDynamicStringPlaceholder(registry, "%FIELD_NAME%", nameValue, nameDescriptor); - registerDynamicStringPlaceholder(registry, "%FIELD_LABEL%", labelValue, labelDescriptor); - registerDynamicStringPlaceholder(registry, "%FIELD_MAXLENGTH%", maxLengthValue, maxLengthDescriptor); - registerDynamicStringPlaceholder(registry, "%FIELD_VALUE%", valueValue, valueDescriptor); - registerDynamicStringPlaceholder(registry, "%FIELD_EXTRA_ATTRS%", extraAttrsValue, extraAttrsDescriptor); + if (templateData == WM_FIELD_LABEL_AFTER_TEMPLATE) { + String output; + reservePage(output, label.length() + input.length() + 32); + output += F("
"); + output += input; + output += F(""); + return output; + } - return renderTemplateToString(templateData, registry); + String output; + reservePage(output, input.length() + 8); + output += F("
"); + output += input; + return output; } String renderInfoRow(const String& label, const String& value) { - PlaceholderRegistry registry(2); - DynamicTemplateDescriptor labelDescriptor; - DynamicTemplateDescriptor valueDescriptor; - String labelValue = label; - String valueValue = value; - registerDynamicStringPlaceholder(registry, "%INFO_LABEL%", labelValue, labelDescriptor); - registerDynamicStringPlaceholder(registry, "%INFO_VALUE%", valueValue, valueDescriptor); - return renderTemplateToString(WM_INFO_ROW_TEMPLATE, registry); + String output; + reservePage(output, label.length() + value.length() + 24); + output += F("
"); + output += label; + output += F("
"); + output += value; + output += F("
"); + return output; } String renderInfoSection(const String& title, const String& rows, const String& prefix = String(), const String& suffix = String()) { - PlaceholderRegistry registry(4); - DynamicTemplateDescriptor titleDescriptor; - DynamicTemplateDescriptor rowsDescriptor; - DynamicTemplateDescriptor prefixDescriptor; - DynamicTemplateDescriptor suffixDescriptor; - - String titleValue = title; - String rowsValue = rows; - String prefixValue = prefix; - String suffixValue = suffix; - - registerDynamicStringPlaceholder(registry, "%SECTION_TITLE%", titleValue, titleDescriptor); - registerDynamicStringPlaceholder(registry, "%SECTION_ROWS%", rowsValue, rowsDescriptor); - registerDynamicStringPlaceholder(registry, "%SECTION_PREFIX%", prefixValue, prefixDescriptor); - registerDynamicStringPlaceholder(registry, "%SECTION_SUFFIX%", suffixValue, suffixDescriptor); - - return renderTemplateToString(WM_INFO_SECTION_TEMPLATE, registry); + String output; + reservePage(output, prefix.length() + suffix.length() + title.length() + rows.length() + 40); + output += prefix; + output += F("

"); + output += title; + output += F("


"); + output += rows; + output += F("
"); + output += suffix; + return output; } String renderStatusMessage(const String& title, const String& body, const String& statusClassSuffix = String()) { - PlaceholderRegistry registry(3); - DynamicTemplateDescriptor titleDescriptor; - DynamicTemplateDescriptor bodyDescriptor; - DynamicTemplateDescriptor classDescriptor; - - String titleValue = title; - String bodyValue = body; - String classValue = statusClassSuffix; - - registerDynamicStringPlaceholder(registry, "%STATUS_TITLE%", titleValue, titleDescriptor); - registerDynamicStringPlaceholder(registry, "%STATUS_BODY%", bodyValue, bodyDescriptor); - registerDynamicStringPlaceholder(registry, "%STATUS_CLASS_SUFFIX%", classValue, classDescriptor); - - return renderTemplateToString(WM_STATUS_MESSAGE_TEMPLATE, registry); -} - -void buildRootState(WiFiManagerHandlers* handlers, RootState& state) { - reservePage(state.menu, 768); - reservePage(state.status, 512); - - handlers->getMenuOut(&state.menu); - handlers->reportStatus(state.status); - - // Dynamic templates are parsed as template content, so escape literal '%' values. - escapePercentsForTemplate(state.menu); - escapePercentsForTemplate(state.status); + String output; + reservePage(output, title.length() + body.length() + statusClassSuffix.length() + 48); + output += F("
"); + output += title; + output += F(""); + output += body; + output += F("
"); + return output; } String renderPageHeading(const String& title, const String& subtitle) { - PlaceholderRegistry registry(2); - DynamicTemplateDescriptor titleDescriptor; - DynamicTemplateDescriptor subtitleDescriptor; - String titleValue = title; - String subtitleValue = subtitle; - registerDynamicStringPlaceholder(registry, "%HEADER_TITLE%", titleValue, titleDescriptor); - registerDynamicStringPlaceholder(registry, "%HEADER_SUBTITLE%", subtitleValue, subtitleDescriptor); - return renderTemplateToString(WM_PAGE_HEADING_TEMPLATE, registry); + String output; + reservePage(output, title.length() + subtitle.length() + 20); + output += F("

"); + output += title; + output += F("

"); + output += subtitle; + output += F("

"); + return output; } void buildMessagePageState(MessagePageState& state, @@ -601,15 +623,16 @@ void buildParamPageState(WiFiManagerHandlers* handlers, escapePercentsForTemplate(state.status); } -struct RootRenderBundle { - RootState state; +struct ShellRenderBundle { + String bootstrapJson; + String pageTitleStatic; PlaceholderRegistry registry; TemplateContext context; - DynamicTemplateDescriptor menuDescriptor; - DynamicTemplateDescriptor statusDescriptor; + DynamicTemplateDescriptor bootstrapDescriptor; + DynamicTemplateDescriptor pageTitleDescriptor; - RootRenderBundle() - : registry(WM_TEMPLATE_REGISTRY_CAPACITY), menuDescriptor{}, statusDescriptor{} {} + ShellRenderBundle() + : registry(WM_TEMPLATE_REGISTRY_CAPACITY), bootstrapDescriptor{}, pageTitleDescriptor{} {} }; struct MessageRenderBundle { @@ -806,8 +829,8 @@ String WiFiManagerHandlers::getScanItemOut(){ } if (!_wm->_scan.resultsValid || n == 0) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(F("No networks found")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("No networks found")); #endif if (_wm->_scan.state == WiFiManager::WM_SCAN_TIMEOUT) { page += renderScanMessage(F("Scan timed out. Refresh to try again.")); @@ -819,8 +842,8 @@ String WiFiManagerHandlers::getScanItemOut(){ return page; } - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(n,F("networks found")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, n,F("networks found")); #endif String hiddenClass = _wm->_scanDispOptions ? "" : "h"; @@ -829,8 +852,8 @@ String WiFiManagerHandlers::getScanItemOut(){ for (int i = 0; i < n; i++) { const auto* network = networks[static_cast(i)]; - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE,F("AP: "),(String)network->rssi + " " + network->ssid); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("AP: "),(String)network->rssi + " " + network->ssid); #endif int rssiperc = _wm->getRSSIasQuality(network->rssi); @@ -851,8 +874,8 @@ String WiFiManagerHandlers::getScanItemOut(){ qualityPercent ); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Added network item")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Added network item")); #endif delay(0); } @@ -871,8 +894,8 @@ String WiFiManagerHandlers::getStaticOut(){ String fields; reservePage(fields, 384); if ((_wm->_staShowStaticFields || _wm->_sta_static_ip) && _wm->_staShowStaticFields>=0) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV,F("_staShowStaticFields")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("_staShowStaticFields")); #endif fields += getIpForm(FPSTR(S_ip),F("Static IP"),(_wm->_sta_static_ip ? _wm->_sta_static_ip.toString() : "")); fields += getIpForm(FPSTR(S_gw),F("Static gateway"),(_wm->_sta_static_gw ? _wm->_sta_static_gw.toString() : "")); @@ -895,8 +918,8 @@ String WiFiManagerHandlers::getParamOut(){ String page; reservePage(page, 256 + (_wm->_paramsCount > 0 ? static_cast(_wm->_paramsCount) * 128 : 64)); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV,F("getParamOut"),_wm->_paramsCount); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("getParamOut"),_wm->_paramsCount); #endif if(_wm->_paramsCount > 0){ @@ -905,8 +928,8 @@ String WiFiManagerHandlers::getParamOut(){ for (int i = 0; i < _wm->_paramsCount; i++) { if (_wm->_params[i] == NULL || _wm->_params[i]->getValueLength() > 99999) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] WiFiManagerParameter is out of scope")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] WiFiManagerParameter is out of scope")); #endif return ""; } @@ -1122,8 +1145,8 @@ String WiFiManagerHandlers::getInfoData(String id){ } void WiFiManagerHandlers::reportStatus(String &page){ - _wm->DEBUG_WM(WM_DEBUG_DEV,F("[WIFI] reportStatus prev:"),_wm->getWLStatusString(_wm->_lastconxresult)); - _wm->DEBUG_WM(WM_DEBUG_DEV,F("[WIFI] reportStatus current:"),_wm->getWLStatusString(WiFi.status())); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("[WIFI] reportStatus prev:"),_wm->getWLStatusString(_wm->_lastconxresult)); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem,F("[WIFI] reportStatus current:"),_wm->getWLStatusString(WiFi.status())); String str; if (_wm->WiFi_SSID() != ""){ if (WiFi.status()==WL_CONNECTED){ @@ -1168,9 +1191,9 @@ boolean WiFiManagerHandlers::captivePortal(AsyncWebServerRequest *request) { String serverLoc = _wm->toStringIp(request->client()->localIP()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, "-> " + request->host()); - _wm->DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, "-> " + request->host()); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, "serverLoc " + serverLoc); #endif // fallback for ipv6 bug @@ -1185,10 +1208,10 @@ boolean WiFiManagerHandlers::captivePortal(AsyncWebServerRequest *request) { bool doredirect = serverLoc != request->host(); if (doredirect) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Request redirected to captive portal")); - _wm->DEBUG_WM(WM_DEBUG_DEV, "serverLoc " + serverLoc); - _wm->DEBUG_WM(WM_DEBUG_DEV, "Original URL " + request->url()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- Request redirected to captive portal")); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, "serverLoc " + serverLoc); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, "Original URL " + request->url()); #endif String redirectUrl = (String)F("http://") + serverLoc + request->url(); if (request->params() > 0) { @@ -1198,8 +1221,8 @@ boolean WiFiManagerHandlers::captivePortal(AsyncWebServerRequest *request) { redirectUrl += request->getParam(i)->name() + F("=") + request->getParam(i)->value(); } } - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, "Redirect URL " + redirectUrl); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, "Redirect URL " + redirectUrl); #endif request->redirect(redirectUrl); return true; @@ -1218,152 +1241,59 @@ void WiFiManagerHandlers::handleRequest(AsyncWebServerRequest *request) { } void WiFiManagerHandlers::handleRoot(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Root")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Root")); #endif if (captivePortal(request)) return; handleRequest(request); - AsyncWebServerResponse *response = nullptr; - auto bundle = std::make_shared(); - buildRootState(this, bundle->state); + auto bundle = std::make_shared(); + bundle->bootstrapJson = buildPortalBootstrapJson(); if (_wm->_serverManager) { _wm->_serverManager->registerDefaultStyles(bundle->registry); _wm->_serverManager->registerDefaultScripts(bundle->registry); _wm->_serverManager->registerDefaultPageTitle(bundle->registry); - _wm->_serverManager->registerDefaultSubtitle(bundle->registry); _wm->_serverManager->applyTemplateSetupCallback(bundle->registry); + } else { + registerSharedShellPlaceholders(nullptr, bundle->registry); + bundle->pageTitleStatic = _wm->_title; + configureDynamicStringDescriptor(bundle->pageTitleDescriptor, bundle->pageTitleStatic); + bundle->registry.registerDynamicTemplate("%PAGE_TITLE%", &bundle->pageTitleDescriptor); } - if (bundle->registry.getPlaceholder("%MENU%") == nullptr) { - configureDynamicStringDescriptor(bundle->menuDescriptor, bundle->state.menu); - bundle->registry.registerDynamicTemplate("%MENU%", &bundle->menuDescriptor); - } + configureDynamicStringDescriptor(bundle->bootstrapDescriptor, bundle->bootstrapJson); + bundle->registry.registerDynamicTemplate("%BOOTSTRAP_JSON%", &bundle->bootstrapDescriptor); + bundle->registry.registerProgmemData("%PORTAL_APP_JS%", PORTAL_APP_JS); - if (bundle->registry.getPlaceholder("%STATUS%") == nullptr) { - configureDynamicStringDescriptor(bundle->statusDescriptor, bundle->state.status); - bundle->registry.registerDynamicTemplate("%STATUS%", &bundle->statusDescriptor); - } - - response = beginTemplateResponse(request, bundle, WM_ROOT_TEMPLATE); - - request->send(response); + request->send(beginTemplateResponse(request, bundle, WM_ROOT_SHELL_TEMPLATE)); } void WiFiManagerHandlers::handleWifi(AsyncWebServerRequest *request, boolean scan) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Wifi")); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("handleWifi called, scan="), scan ? "true" : "false"); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Wifi")); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("handleWifi called, scan="), scan ? "true" : "false"); #endif + (void)scan; if (captivePortal(request)) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Captive portal redirect")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Captive portal redirect")); #endif return; } handleRequest(request); - auto bundle = std::make_shared(); - - String ssidPlaceholder = _wm->WiFi_SSID(); - String passwordPlaceholder = ""; - if(_wm->_showPassword){ - passwordPlaceholder = _wm->WiFi_psk(); - } - else if(_wm->WiFi_psk() != ""){ - passwordPlaceholder = F("********"); - } - - buildWiFiPageState(this, - bundle->state, - scan, - _wm->_showBack, - ssidPlaceholder, - passwordPlaceholder, - _wm->_paramsInWifi && _wm->_paramsCount > 0); - - registerSharedShellPlaceholders(_wm->_serverManager.get(), bundle->registry); - registerShellTemplate(bundle->registry, - bundle->docTitleDescriptor, - bundle->state.docTitle, - C_wifi, - WM_WIFI_CONTENT_TEMPLATE, - WIFI_POLLING_JS); - configureDynamicStringDescriptor(bundle->scanContentDescriptor, bundle->state.scanContent); - configureDynamicStringDescriptor(bundle->ssidPlaceholderDescriptor, bundle->state.ssidPlaceholder); - configureDynamicStringDescriptor(bundle->passwordPlaceholderDescriptor, bundle->state.passwordPlaceholder); - configureDynamicStringDescriptor(bundle->staticFieldsDescriptor, bundle->state.staticFields); - configureDynamicStringDescriptor(bundle->paramSectionDescriptor, bundle->state.paramSection); - configureDynamicStringDescriptor(bundle->formActionsDescriptor, bundle->state.formActions); - configureDynamicStringDescriptor(bundle->pageActionsDescriptor, bundle->state.pageActions); - configureDynamicStringDescriptor(bundle->statusDescriptor, bundle->state.status); - - bundle->registry.registerDynamicTemplate("%WIFI_SCAN_CONTENT%", &bundle->scanContentDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_SSID_PLACEHOLDER%", &bundle->ssidPlaceholderDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_PASSWORD_PLACEHOLDER%", &bundle->passwordPlaceholderDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_STATIC_FIELDS%", &bundle->staticFieldsDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_PARAM_SECTION%", &bundle->paramSectionDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_FORM_ACTIONS%", &bundle->formActionsDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_PAGE_ACTIONS%", &bundle->pageActionsDescriptor); - bundle->registry.registerDynamicTemplate("%WIFI_STATUS%", &bundle->statusDescriptor); - - #ifdef WM_DEBUG_LEVEL - size_t debugPageLength = bundle->state.scanContent.length() + bundle->state.staticFields.length() - + bundle->state.paramSection.length() - + bundle->state.formActions.length() + bundle->state.pageActions.length() - + bundle->state.status.length(); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Page length: "), String(debugPageLength)); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("_numNetworks: "), String(_wm->_numNetworks)); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("_scanState: "), String(_wm->_scan.state)); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("_lastscan: "), String(_wm->_lastscan)); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("About to send response")); - #endif - - request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); - - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Response sent")); - #endif + request->redirect(String(F("/#/wifi"))); } void WiFiManagerHandlers::handleParam(AsyncWebServerRequest *request){ - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Param")); #endif handleRequest(request); - auto bundle = std::make_shared(); - buildParamPageState(this, bundle->state, _wm->_showBack); - - registerSharedShellPlaceholders(_wm->_serverManager.get(), bundle->registry); - registerShellTemplate(bundle->registry, - bundle->docTitleDescriptor, - bundle->state.docTitle, - C_param, - WM_PARAM_CONTENT_TEMPLATE); - configureDynamicStringDescriptor(bundle->fieldsDescriptor, bundle->state.fields); - configureDynamicStringDescriptor(bundle->formActionsDescriptor, bundle->state.formActions); - configureDynamicStringDescriptor(bundle->pageActionsDescriptor, bundle->state.pageActions); - configureDynamicStringDescriptor(bundle->statusDescriptor, bundle->state.status); - - bundle->registry.registerDynamicTemplate("%PARAM_FIELDS%", &bundle->fieldsDescriptor); - bundle->registry.registerDynamicTemplate("%PARAM_FORM_ACTIONS%", &bundle->formActionsDescriptor); - bundle->registry.registerDynamicTemplate("%PARAM_PAGE_ACTIONS%", &bundle->pageActionsDescriptor); - bundle->registry.registerDynamicTemplate("%PARAM_STATUS%", &bundle->statusDescriptor); - - request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); - - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Sent param page")); - #endif + request->redirect(String(F("/#/setup"))); } -void WiFiManagerHandlers::handleWifiSave(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi save ")); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Method:"), request->method() == HTTP_GET ? F("GET") : F("POST")); - #endif - handleRequest(request); - +void WiFiManagerHandlers::applyWifiAndParamsFromRequest(AsyncWebServerRequest *request) { WiFiManager::WiFiManagerRequestArgs requestArgs(request); if (request->hasParam("s", true)) { @@ -1373,14 +1303,14 @@ void WiFiManagerHandlers::handleWifiSave(AsyncWebServerRequest *request) { _wm->_pass = request->getParam("p", true)->value().c_str(); } - if(_wm->_ssid == "" && _wm->_pass != ""){ + if (_wm->_ssid == "" && _wm->_pass != "") { _wm->_ssid = _wm->WiFi_SSID(true); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("Detected WiFi password change")); - #endif +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("Detected WiFi password change")); +#endif } - #ifdef WM_DEBUG_LEVEL +#ifndef WM_NO_LOG String requestinfo = "SERVER_REQUEST\n----------------\n"; requestinfo += "URI: "; requestinfo += request->url(); @@ -1389,48 +1319,60 @@ void WiFiManagerHandlers::handleWifiSave(AsyncWebServerRequest *request) { requestinfo += "\nArguments: "; requestinfo += request->params(); requestinfo += "\n"; - for (size_t i = 0; i < request->params(); i++) { - const AsyncWebParameter* p = request->getParam(i); - requestinfo += " " + p->name() + ": " + p->value() + "\n"; - } + for (size_t i = 0; i < request->params(); i++) { + const AsyncWebParameter* p = request->getParam(i); + requestinfo += " " + p->name() + ": " + p->value() + "\n"; + } - _wm->DEBUG_WM(WM_DEBUG_MAX, requestinfo); - #endif + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, requestinfo); +#endif if (request->hasParam(FPSTR(S_ip), true)) { String ip = request->getParam(FPSTR(S_ip), true)->value(); _wm->optionalIPFromString(&_wm->_sta_static_ip, ip.c_str()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("static ip:"), ip); - #endif +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("static ip:"), ip); +#endif } if (request->hasParam(FPSTR(S_gw), true)) { String gw = request->getParam(FPSTR(S_gw), true)->value(); _wm->optionalIPFromString(&_wm->_sta_static_gw, gw.c_str()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("static gateway:"), gw); - #endif +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("static gateway:"), gw); +#endif } if (request->hasParam(FPSTR(S_sn), true)) { String sn = request->getParam(FPSTR(S_sn), true)->value(); _wm->optionalIPFromString(&_wm->_sta_static_sn, sn.c_str()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("static netmask:"), sn); - #endif +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("static netmask:"), sn); +#endif } if (request->hasParam(FPSTR(S_dns), true)) { String dns = request->getParam(FPSTR(S_dns), true)->value(); _wm->optionalIPFromString(&_wm->_sta_static_dns, dns.c_str()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("static DNS:"), dns); - #endif +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("static DNS:"), dns); +#endif } if (_wm->_presavewificallback != NULL) { _wm->_presavewificallback(); } - if(_wm->_paramsInWifi) doParamSave(requestArgs); + if (_wm->_paramsInWifi) { + doParamSave(requestArgs); + } +} + +void WiFiManagerHandlers::handleWifiSave(AsyncWebServerRequest *request) { + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP WiFi save ")); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Method:"), request->method() == HTTP_GET ? F("GET") : F("POST")); + #endif + handleRequest(request); + + applyWifiAndParamsFromRequest(request); auto bundle = std::make_shared(); String messageBody; @@ -1457,17 +1399,17 @@ void WiFiManagerHandlers::handleWifiSave(AsyncWebServerRequest *request) { response->addHeader(FPSTR(HTTP_HEAD_CORS), FPSTR(HTTP_HEAD_CORS_ALLOW_ALL)); request->send(response); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Sent wifi save page")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Sent wifi save page")); #endif _wm->connect = true; } void WiFiManagerHandlers::handleParamSave(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Param save ")); - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Method:"), request->method() == HTTP_GET ? F("GET") : F("POST")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Param save ")); + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Method:"), request->method() == HTTP_GET ? F("GET") : F("POST")); #endif handleRequest(request); @@ -1491,8 +1433,8 @@ void WiFiManagerHandlers::handleParamSave(AsyncWebServerRequest *request) { request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Sent param save page")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("Sent param save page")); #endif } @@ -1502,15 +1444,15 @@ void WiFiManagerHandlers::doParamSave(WiFiManager::WiFiManagerRequestArgs reques } if(_wm->_paramsCount > 0){ - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE,F("Parameters")); - _wm->DEBUG_WM(WM_DEBUG_VERBOSE,F("--------------------")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("Parameters")); + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("--------------------")); #endif for (int i = 0; i < _wm->_paramsCount; i++) { if (_wm->_params[i] == NULL || _wm->_params[i]->getValueLength() > 99999) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR,F("[ERROR] WiFiManagerParameter is out of scope")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem,F("[ERROR] WiFiManagerParameter is out of scope")); #endif break; } @@ -1535,12 +1477,12 @@ void WiFiManagerHandlers::doParamSave(WiFiManager::WiFiManagerRequestArgs reques } _wm->_params[i]->setValue(value.c_str(), value.length()); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE,(String)_wm->_params[i]->getID() + ":",value); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,(String)_wm->_params[i]->getID() + ":",value); #endif } - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE,F("--------------------")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem,F("--------------------")); #endif } @@ -1551,41 +1493,16 @@ void WiFiManagerHandlers::doParamSave(WiFiManager::WiFiManagerRequestArgs reques } void WiFiManagerHandlers::handleInfo(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Info")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Info")); #endif handleRequest(request); - auto bundle = std::make_shared(); - buildInfoPageState(this, bundle->state, _wm->_showInfoUpdate, _wm->_showInfoErase, _wm->_showBack); - - registerSharedShellPlaceholders(_wm->_serverManager.get(), bundle->registry); - registerShellTemplate(bundle->registry, - bundle->docTitleDescriptor, - bundle->state.docTitle, - C_info, - WM_INFO_CONTENT_TEMPLATE); - configureDynamicStringDescriptor(bundle->statusDescriptor, bundle->state.status); - configureDynamicStringDescriptor(bundle->deviceDescriptor, bundle->state.deviceSection); - configureDynamicStringDescriptor(bundle->wifiDescriptor, bundle->state.wifiSection); - configureDynamicStringDescriptor(bundle->aboutDescriptor, bundle->state.aboutSection); - configureDynamicStringDescriptor(bundle->footerDescriptor, bundle->state.footer); - - bundle->registry.registerDynamicTemplate("%INFO_STATUS%", &bundle->statusDescriptor); - bundle->registry.registerDynamicTemplate("%INFO_DEVICE_SECTION%", &bundle->deviceDescriptor); - bundle->registry.registerDynamicTemplate("%INFO_WIFI_SECTION%", &bundle->wifiDescriptor); - bundle->registry.registerDynamicTemplate("%INFO_ABOUT_SECTION%", &bundle->aboutDescriptor); - bundle->registry.registerDynamicTemplate("%INFO_FOOTER%", &bundle->footerDescriptor); - - request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); - - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("Sent info page")); - #endif + request->redirect(String(F("/#/info"))); } void WiFiManagerHandlers::handleExit(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Exit")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Exit")); #endif handleRequest(request); auto bundle = std::make_shared(); @@ -1604,8 +1521,8 @@ void WiFiManagerHandlers::handleExit(AsyncWebServerRequest *request) { } void WiFiManagerHandlers::handleReset(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP Reset")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP Reset")); #endif handleRequest(request); auto bundle = std::make_shared(); @@ -1617,16 +1534,16 @@ void WiFiManagerHandlers::handleReset(AsyncWebServerRequest *request) { request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(F("RESETTING ESP")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("RESETTING ESP")); #endif _wm->_rebootScheduled = true; _wm->_rebootTime = millis() + _wm->REBOOT_DELAY_MS; } void WiFiManagerHandlers::handleErase(AsyncWebServerRequest *request, boolean opt) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_NOTIFY, F("<- HTTP Erase")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("<- HTTP Erase")); #endif handleRequest(request); bool ret = _wm->erase(opt); @@ -1637,8 +1554,8 @@ void WiFiManagerHandlers::handleErase(AsyncWebServerRequest *request, boolean op if(ret) messageBody += F("Module will reset in a few seconds."); else { messageBody += F("An error occured"); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] WiFi EraseConfig failed")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] WiFi EraseConfig failed")); #endif } @@ -1653,17 +1570,17 @@ void WiFiManagerHandlers::handleErase(AsyncWebServerRequest *request, boolean op if(ret){ _wm->_rebootScheduled = true; _wm->_rebootTime = millis() + _wm->ERASE_REBOOT_DELAY_MS; - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(F("RESETTING ESP")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("RESETTING ESP")); #endif } } void WiFiManagerHandlers::handleClose(AsyncWebServerRequest *request){ - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("Disabling Captive Portal")); + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("Disabling Captive Portal")); stopCaptivePortal(); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP close")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP close")); #endif handleRequest(request); auto bundle = std::make_shared(); @@ -1688,8 +1605,8 @@ void WiFiManagerHandlers::handleNotFound(AsyncWebServerRequest *request) { } void WiFiManagerHandlers::handleWiFiScanStatus(AsyncWebServerRequest *request){ - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi scan status")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP WiFi scan status")); #endif handleRequest(request); @@ -1752,8 +1669,8 @@ void WiFiManagerHandlers::appendVisibleScanResultsJson(String& json, const std:: } void WiFiManagerHandlers::handleWiFiScanRequest(AsyncWebServerRequest *request){ - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- HTTP WiFi scan request")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- HTTP WiFi scan request")); #endif handleRequest(request); _wm->requestAsyncScan(true); @@ -1765,22 +1682,12 @@ void WiFiManagerHandlers::handleWiFiScanRequest(AsyncWebServerRequest *request){ } void WiFiManagerHandlers::handleUpdate(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- Handle update")); #endif if (captivePortal(request)) return; handleRequest(request); - auto bundle = std::make_shared(); - const String subtitle = _wm->configPortalActive - ? _wm->_apName - : (_wm->getWiFiHostname() + " - " + WiFi.localIP().toString()); - sendMessageTemplateResponse(_wm->_serverManager.get(), - bundle, - F("Update"), - C_update, - buildUpdatePanelContent(_wm->_title, subtitle)); - - request->send(beginTemplateResponse(request, bundle, WM_PAGE_SHELL_TEMPLATE)); + request->redirect(String(F("/#/update"))); } void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { @@ -1794,8 +1701,8 @@ void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String } _wm->_configPortalTimeout = 0; - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("[OTA] Update file: "), filename.c_str()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("[OTA] Update file: "), filename.c_str()); #endif if (_wm->_preotaupdatecallback != NULL) { @@ -1810,8 +1717,8 @@ void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String #endif if (!Update.begin(maxSketchSpace)) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update ERROR"), Update.getError()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] OTA Update ERROR"), Update.getError()); #endif request->send(500, "text/plain", "Update.begin failed"); _wm->_configPortalTimeout = _configPortalTimeoutSAV; @@ -1822,8 +1729,8 @@ void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String if (len) { if (Update.write(data, len) != len) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update WRITE ERROR"), Update.getError()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] OTA Update WRITE ERROR"), Update.getError()); #endif request->send(500, "text/plain", "Update.write failed"); _wm->_configPortalTimeout = _configPortalTimeoutSAV; @@ -1834,12 +1741,12 @@ void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String if (final) { if (Update.end(true)) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("\n\n[OTA] OTA FILE END bytes: "), (String)index); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("\n\n[OTA] OTA FILE END bytes: "), (String)index); #endif } else { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] OTA Update END ERROR"), Update.getError()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] OTA Update END ERROR"), Update.getError()); #endif request->send(500, "text/plain", "Update.end failed"); } @@ -1850,8 +1757,8 @@ void WiFiManagerHandlers::handleUpdating(AsyncWebServerRequest *request, String } void WiFiManagerHandlers::handleUpdateDone(AsyncWebServerRequest *request) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("<- Handle update done")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- Handle update done")); #endif handleRequest(request); @@ -1871,5 +1778,275 @@ void WiFiManagerHandlers::handleUpdateDone(AsyncWebServerRequest *request) { } } +void WiFiManagerHandlers::sendApiJson(AsyncWebServerRequest *request, int code, const String& json) { + AsyncWebServerResponse *response = request->beginResponse(code, F("application/json"), json); + response->addHeader(FPSTR(HTTP_HEAD_CORS), FPSTR(HTTP_HEAD_CORS_ALLOW_ALL)); + response->addHeader(F("Cache-Control"), F("no-cache")); + request->send(response); +} + +String WiFiManagerHandlers::buildPortalBootstrapJson() { + std::vector networks; + collectVisibleScanResults(networks); + const char *stateStr = "idle"; + switch (_wm->_scan.state) { + case WiFiManager::WM_SCAN_IDLE: + stateStr = "idle"; + break; + case WiFiManager::WM_SCAN_QUEUED: + stateStr = "queued"; + break; + case WiFiManager::WM_SCAN_RUNNING: + stateStr = "running"; + break; + case WiFiManager::WM_SCAN_COMPLETE: + stateStr = "complete"; + break; + case WiFiManager::WM_SCAN_FAILED: + stateStr = "failed"; + break; + case WiFiManager::WM_SCAN_TIMEOUT: + stateStr = "timeout"; + break; + default: + stateStr = "idle"; + break; + } + String json; + reservePage(json, 512); + json += F("{"); + json += F("\"title\":\""); + jsonAppendEscaped(json, _wm->_title); + json += F("\",\"subtitle\":\""); + { + String sub; + if (_wm->configPortalActive) { + sub = _wm->_apName; + } else { + sub = _wm->getWiFiHostname() + " - " + WiFi.localIP().toString(); + } + jsonAppendEscaped(json, sub); + } + json += F("\",\"portalActive\":"); + json += _wm->configPortalActive ? F("true") : F("false"); + json += F(",\"features\":{"); + json += F("\"showInfo\":true,\"showUpdate\":"); + json += _wm->_showInfoUpdate ? F("true") : F("false"); + json += F(",\"showErase\":"); + json += _wm->_showInfoErase ? F("true") : F("false"); + json += F(",\"paramsInWifi\":"); + json += _wm->_paramsInWifi ? F("true") : F("false"); + json += F("},\"showBack\":"); + json += _wm->_showBack ? F("true") : F("false"); + json += F(",\"scan\":{\"state\":\""); + json += stateStr; + json += F("\",\"count\":"); + json += String((unsigned int)networks.size()); + json += F("}}"); + return json; +} + +void WiFiManagerHandlers::buildPlainStatusSummary(String &out) { + out = ""; + if (_wm->WiFi_SSID() != "") { + if (WiFi.status() == WL_CONNECTED) { + out += F("Connected to "); + out += _wm->WiFi_SSID(); + out += F(" — IP "); + out += WiFi.localIP().toString(); + } else { + out += F("Not connected to "); + out += _wm->WiFi_SSID(); + if (_wm->_lastconxresult == _wm->WL_STATION_WRONG_PASSWORD) { + out += F(" (wrong password)"); + } else if (_wm->_lastconxresult == WL_NO_SSID_AVAIL) { + out += F(" (network not found)"); + } else if (_wm->_lastconxresult == WL_CONNECT_FAILED || _wm->_lastconxresult == WL_CONNECTION_LOST) { + out += F(" (connection failed)"); + } + } + } else { + out += F("No station network configured"); + } +} + +void WiFiManagerHandlers::handleApiBootstrap(AsyncWebServerRequest *request) { + handleRequest(request); + sendApiJson(request, 200, buildPortalBootstrapJson()); +} + +void WiFiManagerHandlers::handleApiWifiScanStatus(AsyncWebServerRequest *request) { + handleWiFiScanStatus(request); +} + +void WiFiManagerHandlers::handleApiWifiScan(AsyncWebServerRequest *request) { + handleWiFiScanRequest(request); +} + +void WiFiManagerHandlers::handleApiWifiMeta(AsyncWebServerRequest *request) { + handleRequest(request); + String ssidPlaceholder = _wm->WiFi_SSID(); + String passwordPlaceholder = ""; + if (_wm->_showPassword) { + passwordPlaceholder = _wm->WiFi_psk(); + } else if (_wm->WiFi_psk() != "") { + passwordPlaceholder = F("********"); + } + String staticHtml = getStaticOut(); + String paramsHtml; + if (_wm->_paramsInWifi && _wm->_paramsCount > 0) { + paramsHtml = renderSectionBreak(getParamOut()); + } + String json = F("{\"ssidPlaceholder\":\""); + jsonAppendEscaped(json, ssidPlaceholder); + json += F("\",\"passwordPlaceholder\":\""); + jsonAppendEscaped(json, passwordPlaceholder); + json += F("\",\"staticFieldsHtml\":\""); + jsonAppendEscaped(json, staticHtml); + json += F("\",\"paramsHtml\":\""); + jsonAppendEscaped(json, paramsHtml); + json += F("\"}"); + sendApiJson(request, 200, json); +} + +void WiFiManagerHandlers::handleApiWifiSave(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- API WiFi save")); +#endif + handleRequest(request); + applyWifiAndParamsFromRequest(request); + String json = F("{\"ok\":true,\"message\":\""); + if (_wm->_ssid == "") { + json += F("Settings saved"); + } else { + json += F("Credentials saved"); + } + json += F("\",\"next\":{\"connectScheduled\":true}}"); + sendApiJson(request, 200, json); + _wm->connect = true; +} + +void WiFiManagerHandlers::handleApiParamsGet(AsyncWebServerRequest *request) { + handleRequest(request); + String fields = getParamOut(); + String json = F("{\"paramsHtml\":\""); + jsonAppendEscaped(json, fields); + json += F("\"}"); + sendApiJson(request, 200, json); +} + +void WiFiManagerHandlers::handleApiParamsSave(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("<- API params save")); +#endif + handleRequest(request); + WiFiManager::WiFiManagerRequestArgs requestArgs(request); + doParamSave(requestArgs); + sendApiJson(request, 200, F("{\"ok\":true,\"message\":\"Setup saved\"}")); +} + +void WiFiManagerHandlers::handleApiInfo(AsyncWebServerRequest *request) { + handleRequest(request); + String summary; + buildPlainStatusSummary(summary); + String json = F("{\"status\":[{\"key\":\"summary\",\"label\":\"Status\",\"value\":\""); + jsonAppendEscaped(json, summary); + json += F("\"}],\"device\":["); + bool first = true; +#ifdef ESP8266 + static const char *const deviceIds[] = {"uptime", "chipid", "fchipid", "idesize", "flashsize", + "corever", "bootver", "cpufreq", "freeheap", "memsketch", + "memsmeter", "lastreset"}; +#elif defined(ESP32) + static const char *const deviceIds[] = {"uptime", "chipid", "chiprev", "idesize", "flashsize", + "cpufreq", "freeheap", "memsketch", "memsmeter", "lastreset", "temp"}; +#endif + appendJsonInfoArrayFromIds(this, json, deviceIds, sizeof(deviceIds) / sizeof(deviceIds[0]), first); + json += F("],\"wifi\":["); + first = true; +#ifdef ESP8266 + static const char *const wifiIds[] = {"conx", "stassid", "staip", "stagw", "stasub", "dnss", "host", + "stamac", "autoconx", "apssid", "apip", "apbssid", "apmac"}; +#elif defined(ESP32) + static const char *const wifiIds[] = {"conx", "stassid", "staip", "stagw", "stasub", "dnss", "host", + "stamac", "apssid", "apip", "apmac", "aphost", "apbssid"}; +#endif + appendJsonInfoArrayFromIds(this, json, wifiIds, sizeof(wifiIds) / sizeof(wifiIds[0]), first); + json += F("],\"about\":["); + first = true; + static const char *const aboutIds[] = {"aboutver", "aboutarduinover", "aboutsdkver", "aboutdate"}; + appendJsonInfoArrayFromIds(this, json, aboutIds, sizeof(aboutIds) / sizeof(aboutIds[0]), first); + json += F("],\"actions\":{"); + json += F("\"showUpdate\":"); + json += _wm->_showInfoUpdate ? F("true") : F("false"); + json += F(",\"showErase\":"); + json += _wm->_showInfoErase ? F("true") : F("false"); + json += F(",\"showBack\":"); + json += _wm->_showBack ? F("true") : F("false"); + json += F("}}"); + sendApiJson(request, 200, json); +} + +void WiFiManagerHandlers::handleApiStatus(AsyncWebServerRequest *request) { + handleRequest(request); + String summary; + buildPlainStatusSummary(summary); + String json = F("{\"text\":\""); + jsonAppendEscaped(json, summary); + json += F("\"}"); + sendApiJson(request, 200, json); +} + +void WiFiManagerHandlers::handleApiDeviceRestart(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("API device restart")); +#endif + handleRequest(request); + sendApiJson(request, 200, F("{\"ok\":true,\"message\":\"Restart scheduled\"}")); + _wm->_rebootScheduled = true; + _wm->_rebootTime = millis() + _wm->REBOOT_DELAY_MS; +} + +void WiFiManagerHandlers::handleApiDeviceErase(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("API device erase")); +#endif + handleRequest(request); + bool ret = _wm->erase(false); + String json = F("{\"ok\":"); + json += ret ? F("true") : F("false"); + json += F(",\"message\":\""); + if (ret) { + json += F("WiFi configuration erased. Device will restart shortly."); + } else { + json += F("Erase failed"); + } + json += F("\"}"); + sendApiJson(request, ret ? 200 : 500, json); + if (ret) { + _wm->_rebootScheduled = true; + _wm->_rebootTime = millis() + _wm->ERASE_REBOOT_DELAY_MS; + } +} + +void WiFiManagerHandlers::handleApiPortalClose(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("API portal close")); +#endif + stopCaptivePortal(); + handleRequest(request); + sendApiJson(request, 200, F("{\"ok\":true,\"message\":\"Captive portal detection disabled\"}")); +} + +void WiFiManagerHandlers::handleApiPortalExit(AsyncWebServerRequest *request) { +#ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("API portal exit")); +#endif + handleRequest(request); + sendApiJson(request, 200, F("{\"ok\":true,\"message\":\"Exiting portal\"}")); + _wm->_abortScheduled = true; + _wm->_abortTime = millis() + _wm->EXIT_DELAY_MS; +} + #endif // defined(ESP8266) || defined(ESP32) diff --git a/lib/WiFiManager/src/WiFiManagerServer.cpp b/lib/WiFiManager/src/WiFiManagerServer.cpp index 8b4f709..5e9d52a 100644 --- a/lib/WiFiManager/src/WiFiManagerServer.cpp +++ b/lib/WiFiManager/src/WiFiManagerServer.cpp @@ -17,7 +17,6 @@ #endif #include "templates/CSS.h" #include "templates/JS.h" -#include "templates/Root.h" #if defined(ESP8266) || defined(ESP32) @@ -141,7 +140,7 @@ void WiFiManagerServer::setupTemplateEngine() { if (!_dfteLogger) { _dfteLogger = std::make_unique(_wm); } - deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get()); + deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get(), static_cast(this)); _wmOwnsDfteLogSink = true; } #endif @@ -150,19 +149,19 @@ void WiFiManagerServer::setupTemplateEngine() { void WiFiManagerServer::createServer(uint16_t port) { // If server already exists, shutdown first to prevent leaks and connection drops if (server) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("Server already exists, shutting down first")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("Server already exists, shutting down first")); #endif shutdownServer(); } - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(F("Starting Web Portal")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Starting Web Portal")); #endif if(port != 80) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("http server started with custom port: "), port); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("http server started with custom port: "), port); #endif } @@ -174,8 +173,8 @@ void WiFiManagerServer::createServer(uint16_t port) { void WiFiManagerServer::registerRoutes() { if (!server) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] Server not created, call createServer() first")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] Server not created, call createServer() first")); #endif return; } @@ -186,8 +185,8 @@ void WiFiManagerServer::registerRoutes() { } if (_wm->_webservercallback != NULL) { - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("[CB] _webservercallback calling")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("[CB] _webservercallback calling")); #endif _wm->_webservercallback(); // @CALLBACK } @@ -198,6 +197,46 @@ void WiFiManagerServer::registerRoutes() { server->on(WM_G(R_root), HTTP_GET, [this](AsyncWebServerRequest *request) { this->_handlers->handleRoot(request); }); + + server->on(WM_G(R_api_bootstrap), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiBootstrap(request); + }); + server->on(WM_G(R_api_wifi_scan_status), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiWifiScanStatus(request); + }); + server->on(WM_G(R_api_wifi_scan), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiWifiScan(request); + }); + server->on(WM_G(R_api_wifi_meta), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiWifiMeta(request); + }); + server->on(WM_G(R_api_wifi_save), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiWifiSave(request); + }); + server->on(WM_G(R_api_params), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiParamsGet(request); + }); + server->on(WM_G(R_api_params_save), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiParamsSave(request); + }); + server->on(WM_G(R_api_info), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiInfo(request); + }); + server->on(WM_G(R_api_status), HTTP_GET, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiStatus(request); + }); + server->on(WM_G(R_api_device_restart), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiDeviceRestart(request); + }); + server->on(WM_G(R_api_device_erase), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiDeviceErase(request); + }); + server->on(WM_G(R_api_portal_close), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiPortalClose(request); + }); + server->on(WM_G(R_api_portal_exit), HTTP_POST, [this](AsyncWebServerRequest *request) { + this->_handlers->handleApiPortalExit(request); + }); server->on(WM_G(R_wifi), HTTP_GET, [this](AsyncWebServerRequest *request) { this->_handlers->handleWifi(request, true); @@ -267,8 +306,8 @@ void WiFiManagerServer::registerRoutes() { }); server->begin(); // Web server start - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("HTTP server started")); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("HTTP server started")); #endif } @@ -277,8 +316,8 @@ void WiFiManagerServer::setupDNSD() { /* Setup the DNS server redirecting all the domains to the apIP */ dnsServer->setErrorReplyCode(DNSReplyCode::NoError); - #ifdef WM_DEBUG_LEVEL - _wm->DEBUG_WM(WM_DEBUG_DEV, F("dns server started with ip: "), WiFi.softAPIP()); + #ifndef WM_NO_LOG + _wm->log(WiFiManagerLogLevel::Trace, kWiFiMgrLogSubsystem, F("dns server started with ip: "), WiFi.softAPIP()); #endif const uint8_t DNS_PORT = 53; dnsServer->start(DNS_PORT, F("*"), WiFi.softAPIP()); @@ -293,9 +332,7 @@ void WiFiManagerServer::processDNS() { void WiFiManagerServer::shutdownServer() { #ifdef WM_DFTE_LOGGING if (_wmOwnsDfteLogSink) { - if (deviceFrameworkTemplateEngineGetLogger() == _dfteLogger.get()) { - deviceFrameworkTemplateEngineDisableLogging(); - } + deviceFrameworkTemplateEngineDisableLoggingForOwner(static_cast(this)); _dfteLogger.reset(); _wmOwnsDfteLogSink = false; } diff --git a/platformio.ini b/platformio.ini index 822fe07..a09c3c8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,6 +11,8 @@ platform_packages = monitor_speed = 115200 test_framework = unity test_build_src = no +build_flags = + -DWM_LOG_LEVEL=5 lib_deps = ESP32Async/ESPAsyncWebServer@^3.9.1 symlink://../DFTE @@ -26,13 +28,15 @@ build_unflags = -std=gnu++11 build_flags = -std=gnu++14 + -DWM_LOG_LEVEL=5 lib_deps = ESP32Async/ESPAsyncWebServer@^3.9.1 symlink://../DFTE -; Optional: compile tests with DFTE logs bridged into DEBUG_WM (see README) +; Optional: compile tests with DFTE logs bridged into WiFiManager::log (see README) [env:esp8266_dfte_log] extends = env:esp8266 build_flags = + ${env:esp8266.build_flags} -DWM_DFTE_LOGGING diff --git a/tools/migrate_debug_wm.py b/tools/migrate_debug_wm.py new file mode 100644 index 0000000..fdbd323 --- /dev/null +++ b/tools/migrate_debug_wm.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +"""One-shot migration: DEBUG_WM -> WiFiManager::log(...). Run from repo root.""" + +import re +import sys + +SUB = "kWiFiMgrLogSubsystem" + +REPLACEMENTS = [ + # Longest / most specific first (with optional whitespace) + (r"_wm->\s*DEBUG_WM\s*\(\s*WM_DEBUG_ERROR\s*,", f"_wm->log(WiFiManagerLogLevel::Error, {SUB},"), + (r"_wm->\s*DEBUG_WM\s*\(\s*WM_DEBUG_VERBOSE\s*,", f"_wm->log(WiFiManagerLogLevel::Debug, {SUB},"), + (r"_wm->\s*DEBUG_WM\s*\(\s*WM_DEBUG_DEV\s*,", f"_wm->log(WiFiManagerLogLevel::Trace, {SUB},"), + (r"_wm->\s*DEBUG_WM\s*\(\s*WM_DEBUG_NOTIFY\s*,", f"_wm->log(WiFiManagerLogLevel::Info, {SUB},"), + (r"_wm->\s*DEBUG_WM\s*\(\s*WM_DEBUG_MAX\s*,", f"_wm->log(WiFiManagerLogLevel::Trace, {SUB},"), + (r"DEBUG_WM\s*\(\s*WM_DEBUG_ERROR\s*,", f"log(WiFiManagerLogLevel::Error, {SUB},"), + (r"DEBUG_WM\s*\(\s*WM_DEBUG_VERBOSE\s*,", f"log(WiFiManagerLogLevel::Debug, {SUB},"), + (r"DEBUG_WM\s*\(\s*WM_DEBUG_DEV\s*,", f"log(WiFiManagerLogLevel::Trace, {SUB},"), + (r"DEBUG_WM\s*\(\s*WM_DEBUG_NOTIFY\s*,", f"log(WiFiManagerLogLevel::Info, {SUB},"), + (r"DEBUG_WM\s*\(\s*WM_DEBUG_MAX\s*,", f"log(WiFiManagerLogLevel::Trace, {SUB},"), + # Default / notify-level (no explicit WM_DEBUG_* level) + (r"_wm->\s*DEBUG_WM\s*\(\s*F\(", f"_wm->log(WiFiManagerLogLevel::Info, {SUB}, F("), + (r"DEBUG_WM\s*\(\s*F\(", f"log(WiFiManagerLogLevel::Info, {SUB}, F("), + (r"_wm->\s*DEBUG_WM\s*\(", f"_wm->log(WiFiManagerLogLevel::Info, {SUB}, "), + (r"DEBUG_WM\s*\(", f"log(WiFiManagerLogLevel::Info, {SUB}, "), +] + + +def migrate(content: str) -> str: + content = content.replace("#ifdef WM_DEBUG_LEVEL", "#ifndef WM_NO_LOG") + content = content.replace("#ifdef WM_DEBUG_LEVEL", "#ifndef WM_NO_LOG") + for pat, repl in REPLACEMENTS: + content = re.sub(pat, repl, content) + return content + + +def main(): + for path in sys.argv[1:]: + with open(path, "r", encoding="utf-8") as f: + old = f.read() + new = migrate(old) + if new != old: + with open(path, "w", encoding="utf-8") as f: + f.write(new) + print(f"updated: {path}") + else: + print(f"unchanged: {path}") + + +if __name__ == "__main__": + main()