mirror of
https://github.com/alexhopeoconnor/WiFiManager.git
synced 2026-10-04 02:48:13 +10:00
WiFiManager: structured logging, SPA portal, DFTE bridge.
Replace DEBUG_WM with WiFiManagerLogLevel/log(), optional WiFiManagerLogSink, and WM_NO_LOG stripping. Add JSON API handlers and shell templates (RootShell, PortalAppJS). Bridge DFTE logging with owner-scoped teardown; add migrate_debug_wm helper; document and set WM_LOG_LEVEL in platformio.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -24,8 +24,19 @@
|
||||
#include <functional>
|
||||
|
||||
#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<typename T>
|
||||
void log(WiFiManagerLogLevel level, const char* subsystem, T&& text);
|
||||
|
||||
template<typename T, typename U>
|
||||
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<WiFiManagerLogLevel>((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 <typename Generic>
|
||||
void DEBUG_WM(Generic text);
|
||||
|
||||
template <typename Generic>
|
||||
void DEBUG_WM(wm_debuglevel_t level,Generic text);
|
||||
template <typename Generic, typename Genericb>
|
||||
void DEBUG_WM(Generic text,Genericb textb);
|
||||
template <typename Generic, typename Genericb>
|
||||
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<void()> _preotaupdatecallback;
|
||||
std::function<void()> _configportaltimeoutcallback;
|
||||
|
||||
WiFiManagerLogSink* _logSink = nullptr;
|
||||
|
||||
template <class T>
|
||||
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
|
||||
|
||||
|
||||
@@ -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 <typename Generic>
|
||||
void WiFiManager::DEBUG_WM(Generic text) {
|
||||
DEBUG_WM(WM_DEBUG_NOTIFY,text,"");
|
||||
}
|
||||
|
||||
template <typename Generic>
|
||||
void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text) {
|
||||
if(_debugLevel >= level) DEBUG_WM(level,text,"");
|
||||
}
|
||||
|
||||
template <typename Generic, typename Genericb>
|
||||
void WiFiManager::DEBUG_WM(Generic text,Genericb textb) {
|
||||
DEBUG_WM(WM_DEBUG_NOTIFY,text,textb);
|
||||
}
|
||||
|
||||
template <typename Generic, typename Genericb>
|
||||
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
|
||||
|
||||
@@ -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<unsigned>(msg.length()) + 12u);
|
||||
line += F("[DFTE] ");
|
||||
line += msg;
|
||||
_wm->DEBUG_WM(level, line);
|
||||
_wm->log(level, "WM/DFTE", msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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<const WiFiManager::WiFiScanNetwork*>& networks);
|
||||
void appendVisibleScanResultsJson(String& json, const std::vector<const WiFiManager::WiFiScanNetwork*>& 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)
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
/** 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
|
||||
@@ -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
|
||||
@@ -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 <IPAddress.h>
|
||||
#include <WString.h>
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
|
||||
inline String wmLogStringifyArg(const __FlashStringHelper* v) {
|
||||
return String(v);
|
||||
}
|
||||
|
||||
inline String wmLogStringifyArg(const IPAddress& v) {
|
||||
return v.toString();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline String wmLogStringifyArg(const T& v) {
|
||||
return String(v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void WiFiManager::log(WiFiManagerLogLevel level, const char* subsystem, T&& text) {
|
||||
#ifndef WM_NO_LOG
|
||||
emitLogImpl(level, subsystem, wmLogStringifyArg(text), String());
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
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
|
||||
@@ -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<void(PlaceholderRegistry&)> _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<WiFiManagerDfteLogger> _dfteLogger;
|
||||
bool _wmOwnsDfteLogSink = false;
|
||||
#endif
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
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="<div class='wrap'>"+html+"</div>";
|
||||
}
|
||||
|
||||
function navBar(){
|
||||
var f=boot.features||{};
|
||||
var h="<p style='text-align:center'>";
|
||||
h+="<a href='#/'>Home</a> · ";
|
||||
h+="<a href='#/wifi'>WiFi</a>";
|
||||
if(!f.paramsInWifi){h+=" · <a href='#/setup'>Setup</a>";}
|
||||
h+=" · <a href='#/info'>Info</a>";
|
||||
h+=" · <a href='#/update'>Update</a>";
|
||||
h+="</p><hr/>";
|
||||
return h;
|
||||
}
|
||||
|
||||
function viewHome(){
|
||||
var sub=esc(boot.subtitle||'');
|
||||
var t=esc(boot.title||'WiFiManager');
|
||||
var html=navBar();
|
||||
html+="<h1>"+t+"</h1><h3>"+sub+"</h3>";
|
||||
html+="<p>Use the links above to configure WiFi, view device info, or update firmware.</p>";
|
||||
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 '<p>Scanning for networks...</p>';}
|
||||
if(data.error==='timeout')return '<p>Scan timed out. Try Refresh.</p>';
|
||||
if(data.error==='failed')return '<p>Scan failed.</p>';
|
||||
if(!data.networks||data.count===0)return '<p>No networks found.</p>';
|
||||
var html='',i,n,q,pct,qi,enc;
|
||||
for(i=0;i<data.networks.length;i++){
|
||||
n=data.networks[i];
|
||||
pct=(n.quality||0)+'%';
|
||||
qi=Math.round((n.quality/100)*3)+1;if(qi<1)qi=1;if(qi>4)qi=4;
|
||||
enc=n.encrypted?'l':'';
|
||||
html+="<div><a href='#p' onclick='return portalPickSsid(this)' data-ssid='"+esc(n.ssid)+"'>"+esc(n.ssid)+"</a>";
|
||||
html+="<div role='img' aria-label='"+pct+"' title='"+pct+"' class='q q-"+qi+" "+enc+"'></div>";
|
||||
html+="<div class='q'>"+pct+"</div></div>";
|
||||
}
|
||||
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='<p>Starting scan...</p>';
|
||||
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()+"<h2>WiFi</h2><p>Loading...</p>");
|
||||
api('/api/wifi/meta').then(function(res){
|
||||
try{var m=JSON.parse(res.body);}catch(e){m={};}
|
||||
var html=navBar()+"<h2>WiFi</h2>";
|
||||
html+="<div id='wm-scan-results'></div>";
|
||||
html+="<form id='wm-wifi-form' onsubmit='return portalWifiSave(event)'>";
|
||||
html+="<label>SSID</label><input id='wm-s' name='s' maxlength='32' value='"+esc(m.ssidPlaceholder||'')+"'/>";
|
||||
html+="<label>Password</label><input id='wm-p' name='p' type='password' maxlength='64' placeholder='"+esc(m.passwordPlaceholder||'')+"'/>";
|
||||
html+="<input type='checkbox' id='wm-showpass' onclick='var p=document.getElementById(\"wm-p\");p.type=this.checked?\"text\":\"password\"'/> <label for='wm-showpass'>Show password</label>";
|
||||
if(m.staticFieldsHtml){html+=m.staticFieldsHtml;}
|
||||
if(m.paramsHtml){html+=m.paramsHtml;}
|
||||
html+="<button type='submit'>Save</button></form>";
|
||||
html+="<br/><button type='button' id='wm-refresh-scan' onclick='wifiRefresh()'>Refresh scan</button>";
|
||||
html+="<div id='wm-wifi-msg'></div>";
|
||||
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()+"<p>Loading info...</p>");
|
||||
api('/api/info').then(function(res){
|
||||
try{var d=JSON.parse(res.body);}catch(e){d={};}
|
||||
var html=navBar()+"<h2>Info</h2>";
|
||||
function section(title,rows){
|
||||
if(!rows||!rows.length)return'';
|
||||
var h="<h3>"+esc(title)+"</h3><hr/><dl>";
|
||||
for(var i=0;i<rows.length;i++){
|
||||
h+="<dt>"+esc(rows[i].label)+"</dt><dd>"+rows[i].value+"</dd>";
|
||||
}
|
||||
h+="</dl>";
|
||||
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+="<p><a href='#/update'>Firmware update</a></p>";
|
||||
if(act.showErase)html+="<p><button type='button' class='D' onclick='portalErase()'>Erase WiFi config</button></p>";
|
||||
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()+"<p>Loading...</p>");
|
||||
api('/api/params').then(function(res){
|
||||
try{var d=JSON.parse(res.body);}catch(e){d={};}
|
||||
var html=navBar()+"<h2>Parameters</h2>";
|
||||
html+="<form id='wm-param-form' onsubmit='return portalParamSave(event)'>"+(d.paramsHtml||'')+"<button type='submit'>Save</button></form>";
|
||||
html+="<div id='wm-param-msg'></div>";
|
||||
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()+"<h2>Firmware update</h2>";
|
||||
html+="<form method='POST' action='/u' enctype='multipart/form-data'>";
|
||||
html+="<input type='file' name='update'/>";
|
||||
html+="<button type='submit'>Update</button></form>";
|
||||
html+="<p><small>Upload a .bin firmware. Device may restart after update.</small></p>";
|
||||
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_
|
||||
@@ -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_
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
const char WM_ROOT_SHELL_TEMPLATE[] PROGMEM =
|
||||
"<!DOCTYPE html>"
|
||||
"<html lang='en'>"
|
||||
"<head>"
|
||||
"<meta name='format-detection' content='telephone=no'>"
|
||||
"<meta charset='UTF-8'/>"
|
||||
"<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
|
||||
"<title>%PAGE_TITLE%</title>"
|
||||
"%SCRIPTS%"
|
||||
"%STYLES%"
|
||||
"</head>"
|
||||
"<body class='portal'>"
|
||||
"<div id='app'></div>"
|
||||
"<script id='wm-bootstrap' type='application/json'>%BOOTSTRAP_JSON%</script>"
|
||||
"<script>"
|
||||
"%PORTAL_APP_JS%"
|
||||
"</script>"
|
||||
"</body>"
|
||||
"</html>";
|
||||
|
||||
#endif // _WM_ROOT_SHELL_TEMPLATE_H_
|
||||
+394
-309
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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<WiFiManagerDfteLogger>(_wm);
|
||||
}
|
||||
deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get());
|
||||
deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get(), static_cast<const void*>(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<const void*>(this));
|
||||
_dfteLogger.reset();
|
||||
_wmOwnsDfteLogSink = false;
|
||||
}
|
||||
|
||||
+5
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user