Compare commits

...
1241 Commits
Author SHA1 Message Date
alex 360b7cff86 fix: harden portal OTA release 2026-09-20 19:44:05 +10:00
alex 7c5b50499e fix: validate portal OTA and simplify test harness 2026-09-18 02:41:18 +10:00
alex 3e09958d11 fix: restart portal OTA after response completion 2026-09-17 15:12:15 +10:00
alex f1fdeec8ee fix: flush portal OTA response before reboot 2026-09-17 15:08:10 +10:00
alex 4aab676574 test: detect headless NetworkManager sessions 2026-09-17 14:51:55 +10:00
alex d1ad84db5b test: authorize headless portal adapters safely 2026-09-17 14:49:36 +10:00
alex babc58637f test: harden portal hardware recovery 2026-09-17 14:13:12 +10:00
alex 228e1252f4 test: add portal OTA A/B contract coverage 2026-09-17 12:10:48 +10:00
alex 7305ea8827 docs: improve portal guidance and examples 2026-09-17 09:09:35 +10:00
alex 9fec8799ac test: cover custom parameter portal regressions 2026-09-09 14:55:03 +10:00
alex 6500eee528 docs: annotate basic portal flow 2026-09-09 13:10:11 +10:00
alex 50972914e3 docs: clarify DeviceFramework portal ownership 2026-09-09 13:08:04 +10:00
alex 4fede428c4 docs: point Home Assistant devices to DeviceFramework 2026-09-09 13:06:00 +10:00
alex 20e75622ac feat: add reproducible portal README media 2026-09-09 12:56:52 +10:00
alex 5304aad4c8 Release v3.2.4 2026-09-08 22:40:17 +10:00
alex 21607d41bd Fix portal station hand-off ownership 2026-09-08 22:26:19 +10:00
alex 5592fd12e1 docs: clarify WiFiManager integration boundary 2026-09-08 09:54:38 +10:00
alex 9b070f45f4 test: harden portal hardware contract 2026-09-07 08:12:13 +10:00
alex daf9f207b2 test: containerize portal hardware contract 2026-09-06 20:32:46 +10:00
alex d57f6c91c5 test: add portal hardware lifecycle coverage 2026-09-06 20:03:38 +10:00
alex fcd991c5a2 Clarify cooperative process timing 2026-09-06 19:44:19 +10:00
alex 9707d18b2b Align provisioning recipes with profile mode 2026-09-06 19:35:29 +10:00
alex 242f60fa99 Expand API and deployment documentation 2026-09-06 14:35:32 +10:00
alex 28c095c2d1 Improve portal content documentation 2026-09-06 13:43:10 +10:00
alex 6920163026 test: align direct DFTE dependency with package 2026-09-06 00:29:29 +10:00
alex e2dcf9a1f3 fix: keep external station profiles authoritative 2026-09-05 23:40:35 +10:00
alex d2265e4a0d Clarify portal documentation examples 2026-09-05 21:36:55 +10:00
alex 3e9f12e3ac docs: clarify portal screenshot captions 2026-09-03 19:04:30 +10:00
alex 2fec33b952 feat: refine portal flow and examples 2026-09-03 18:54:41 +10:00
alex f8b87f7865 Keep portal branding examples neutral 2026-09-01 18:49:18 +10:00
alex e192c5a94c Improve release preparation tooling 2026-09-01 17:29:53 +10:00
alex c529fc15a8 Release v3.1.0 2026-09-01 10:59:25 +10:00
alex 25977a7320 feat: prepare WiFiManager 3.1.0 2026-08-27 14:25:38 +10:00
alex c10f1a3e92 fix: resolve PlatformIO async dependencies 2026-08-26 11:40:37 +10:00
alex d8a78bae03 fix: bridge nested PlatformIO async dependencies 2026-08-26 01:19:35 +10:00
alex f4fa653a7b fix: retain async dependencies for nested PlatformIO builds 2026-08-26 01:17:05 +10:00
alex 63b0291961 fix: declare async TCP PlatformIO dependencies 2026-08-26 01:06:22 +10:00
alex 3b07903bf4 docs: clarify provisioning and release workflow 2026-08-25 09:01:06 +10:00
alex 1f196895ce Update DFTE dependency to 1.0.2 2026-08-24 22:42:16 +10:00
alex 35e02f54e5 Redact WiFiManager diagnostic values 2026-08-24 22:17:22 +10:00
alex e2495843ff Release WiFiManager 3.0.0 2026-08-24 22:05:16 +10:00
alex 95e9f9a751 Stream portal templates via TemplateEngineAsyncWeb chunked wrapper
Use the DFTE async integration helper so portal HTML chunk callbacks handle
zero-length buffers and no-progress retries without terminating transfers
early on constrained hosts.
2026-05-06 00:44:56 +10:00
alex 396a6e07db Improve portal WiFi handoff and bump WiFiManager to v2.0.19.
Expose redirect details after connect-on-save so clients can land on the station IP before the AP closes, hide the mobile nav scrollbar, and document the updated API contract.
2026-05-05 00:23:22 +10:00
alex 7735d7f0cb Portal customization API v2, SPA hardening, and test cleanup
- Group portal state into brand/pages/actions/layout structs; portal* API
- Bootstrap JSON: nested brand/context/pages/actions/layout; param kind
- Handlers: PROGMEM default CSS when no override/append; dynamic CSS path
- PortalAppJS: portal timeout countdown; safe WiFi scan DOM; serialized
  scan-status polling; fetch error handling; wm:view-changed on redirects
- CSS: scan list icon alignment; wm-status for timeout
- Tests: remove low-value/no-op tests; trim fragile JS substring checks
2026-05-04 22:03:43 +10:00
alex 93711d981d Portal home: single Status card; rename params placement API
- Merge initial status and guidance into one wm-card (Status) on Home.
- Add .wm-home-summary styling for the primary status line.
- Replace legacy setParamsPage with setParametersEmbeddedInWifi (matches
  _paramsInWifi / SPA Setup vs WiFi placement); remove setParamsPage.
- Update README, handlers comment, and advanced-options tests.
2026-05-04 12:58:38 +10:00
alex 3af9706f87 Portal UI: design tokens, cards, nav, WiFi scan rows
- Replace legacy centered stylesheet with CSS variables, layout shell,
  pill navigation with active state, cards, form fields, buttons.
- Restructure SPA markup (hero, page heads, scan list as tap rows).
- Shell dialog buttons use wm-btn classes for consistent styling.
2026-05-02 21:11:35 +10:00
alex 66e6088bf1 Portal: request-scoped shell bundle, SPA connect poll fix, test tidy
- Use per-request PortalShellRenderBundle and one root shell template; drop
  server-side template registry and simplify WiFiManagerServer.
- PortalAppJS: centralize chrome/form binding; fix WiFi connect polling by
  stopping previous timers on view change and before new polls.
- processPortalConnect honors _cleanConnect like connectWifi.
- Remove brittle full-JSON API tests; trim test harness surface.
- README: small doc touch-up for the shell/portal flow.
2026-05-02 20:19:44 +10:00
alex bb1629af90 WiFiManager: consolidate portal JS, update handlers and tests
Remove legacy JS.h template; extend PortalAppJS and RootShell; adjust
WiFiManager core/server/handlers and platformio; refresh captive and
template tests.
2026-05-01 23:57:58 +10:00
alex da99137023 Clean stale portal-save wording in comments.
Update remaining references to the removed wifisave flow so the source comments match the SPA/API portal architecture.
2026-04-27 23:36:16 +10:00
alex 86d9004c9b Portal SPA: single shell, JSON /api surface, remove legacy portal routes
Replace multi-page portal with hash-routed SPA, DFTE shell placeholders, and
data-first JSON APIs. Remove legacy routes, root-template override path, and
HTML-derived info pipeline. Add bootstrap feature flags, in-DOM toast/dialog UX,
OTA via POST /u, and tests for shell, bootstrap, API JSON, and captive host rule.
Rewrite README as fork disclaimer and modernization overview.
2026-04-22 12:09:08 +10:00
alex 350f19cd93 Remove GitHub Actions compile workflow (CI used local DFTE symlink). 2026-04-20 23:34:22 +10:00
alex 5776341b86 Remove temporary tools/ directory (migrate_debug_wm helper). 2026-04-20 23:31:57 +10:00
alex ac42d9a342 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.
2026-04-20 23:28:57 +10:00
alex a7d1755bcf DFTE docs, single root library.json, optional DFTE logging bridge
- Document fork/DFTE in README; WiFiManager template setup API forwards to server
- Remove nested lib/WiFiManager/library.json; rely on root library.json only
- Delete legacy extras/ tooling; point HTML help link at this fork
- Add WiFiManagerDfteLogger and WM_DFTE_LOGGING integration in WiFiManagerServer
- Pin ESP8266 Arduino core (postmortem jump fix) in platformio.ini for tests
2026-04-19 21:16:02 +10:00
alex 55f1fd7ce6 Add root library manifest for git consumers.
Point local test builds at the local DFTE checkout while keeping the published WiFiManager metadata usable from the repository root.
2026-04-18 01:23:24 +10:00
alex 9401c20df6 WiFiManager: fragment templates, handler refactor, and tests.
Split reusable HTML into Fragments, Message, and Param headers; route
more pages through DFTE streaming. Update handlers, WiFi polling JS,
and configuration/scanning tests; add template rendering coverage.
2026-04-18 00:23:57 +10:00
alex 69aea5ce35 WiFiManager: stream info and wifi pages through DFTE.
Harden the root placeholder path, add direct render-isolation coverage, move simple status pages and /info onto request-scoped streamed templates, and switch /wifi to a streamed shell while keeping scan/form sections string-built for now.
2026-04-17 06:41:44 +10:00
alex 9f111ab8bd WiFiManager: stabilize root rendering and reduce page reallocations.
Keep root template state request-scoped so dynamic placeholders stay consistent during chunked renders, add reserve() coverage for non-streamed pages, and add compile/test coverage for the new root render lifecycle.
2026-04-16 20:54:03 +10:00
alex bb1008435f Update library.json and platformio.ini 2025-11-30 00:55:31 +10:00
alex d8046146b5 WiFiManager: add template customization hooks (callback, granular default registrations, rebuild); switch to RootSelector for overridable WM_ROOT_TEMPLATE; minor menu logic fixes 2025-11-16 23:05:12 +10:00
alex 3054123b7f WiFiManager: add DFTE root template and chunked rendering for handleRoot; introduce shared placeholder registry via server singleton; add getMenuOut(String*) overload and menu logic for params/close 2025-11-16 22:21:47 +10:00
alex 3b488423a8 WiFiManager: remove legacy web customization API; simplify handlers to static templates; drop custom menu; keep title and parameter customization; update tests; remove renderer abstraction; build/test clean 2025-11-16 18:09:59 +10:00
alex aa4705e1e3 deps: align with platformio.ini; add ESP32Async/ESPAsyncWebServer@3.8.1 and DFTE 2025-11-16 17:21:17 +10:00
alex ac38bc20f5 chore: tidy comments, remove dead code, add actionable TODOs, improve API docs 2025-11-16 17:05:15 +10:00
alex 10c068178e Remove multi-language support and reorganize constants
- Delete language files (wm_strings_*/wm_consts_*) and wm_consts_en.h
- Move constants to appropriate headers (routes/menu tokens to Server, CSS/forms/headers to Handlers)
- Extract utility functions to WiFiManagerUtils.h/cpp
- Create template files (HTML.h, CSS.h, JS.h) for web interface
- Update version to 2.0.18
- Remove unused HTTP_HEAD_CL constant
2025-11-16 00:07:10 +10:00
alex 1b2cc44bc3 Update author attribution in headers and documentation 2025-11-15 22:24:54 +10:00
alex 9cd5f62f9b Refactor WiFiManager: extract server and handlers into separate modules
- Move server lifecycle management to WiFiManagerServer
- Move HTTP handlers and rendering to WiFiManagerHandlers
- Move DEBUG_WM template definitions to WiFiManagerDebug
- Implement lazy initialization of server manager to save memory
- Add proper cleanup in destructor and on multiple createServer calls
- Update tests to use getServer() and getDNSServer() accessors
2025-11-15 22:22:36 +10:00
alex 1788aa3c4a Refactor WiFiManagerParameter 2025-11-14 16:18:44 +10:00
alex c4ab152566 Pin ESPAsyncWebServer version 2025-11-13 07:42:45 +10:00
alex e5174d1009 Merge branch 'device-framework' of github.com:alexhopeoconnor/WiFiManager into device-framework 2025-11-05 23:25:31 +10:00
alex f056893f87 Implement comprehensive test suite improvements
- Added 42 new tests covering critical functionality:
  * WiFi connection flow tests (6 tests)
  * Callback firing verification tests (4 tests)
  * DNS server lifecycle tests (3 tests)
  * Error condition tests (7 tests)
  * Parameter value management tests (5 tests)
  * WiFi scanning tests (4 tests)
  * State transition tests (4 tests)
  * Integration tests (5 tests)
  * Stress tests (5 tests)

- Fixed compilation errors by replacing protected connectWifi() calls with public autoConnect()
- Fixed config reset callback test to use resetSettings() instead of erase()
- Added delays around resetSettings() calls to prevent ESP8266 WiFi stack crashes
- Reduced stress test iterations to avoid excessive output
- Improved test stability with better state checking and error handling

Total test count: 86 tests (up from 44)
All tests passing successfully
2025-11-05 23:25:06 +10:00
alex f119b02815 Fix async WiFi scanning and captive portal redirects
- Fix captive portal redirect to preserve URL path and query params
- Fix password field rendering for WiFi networks (encryption detection)
- Add WiFiPollingJS template for AJAX polling (currently disabled due to size limit)
- Remove blocking WiFi scan operations
- Add debug output for response handling
2025-11-05 23:19:26 +10:00
alex f5db6b13d1 Merge branch 'device-framework' of github.com:alexhopeoconnor/WiFiManager into device-framework 2025-11-05 20:52:17 +10:00
alex b94f34f06a Remove blocking config portal mode and refactor API
- Remove setConfigPortalBlocking() API and _configPortalIsBlocking member variable
- Remove blocking while(1) loop from startConfigPortal()
- Change startConfigPortal() return type from boolean to void
- Change stopConfigPortal() return type from bool to void
- Make stopConfigPortal() immediately shutdown portal (call shutdownConfigPortal() directly)
- Remove unused portalAbortResult and portalTimeoutResult variables
- Update all comments to remove blocking mode references
- Simplify debug messages (remove 'non-blocking' references)
- Update tests to remove setConfigPortalBlocking() calls
- All 43 tests passing

The config portal is now always non-blocking, requiring users to call
process() periodically in their main loop. This aligns with the async
web server architecture and simplifies the API.
2025-11-05 20:49:22 +10:00
alex a0a7b7e263 Refactor WiFi scanning JavaScript to use raw string literal template
- Remove async parameter from WiFi_scanNetworks() method signatures
- Move JavaScript code to templates/WiFiPollingJS.h using R"rawliteral" format
- Fix JavaScript syntax errors by eliminating quote escaping issues
- Change scan status route from /wifi/scanstatus to /wifistatus to avoid route conflicts
- Cleaner code structure with JavaScript in separate template file
2025-11-05 20:47:10 +10:00
alex d533f4d754 Refactor WiFi scanning to be fully async for ESPAsyncWebServer
- Remove blocking WiFi scan operations from HTTP handlers
- Make WiFi_scanNetworks() always async, remove sync path
- Remove blocking wait loop that caused WDT resets
- Add scan status polling in process() function
- Make getScanItemOut() cache-only, never triggers scans
- Add /wifi/scanstatus JSON endpoint for AJAX polling
- Add client-side JavaScript for async network list updates
- Remove _asyncScan toggle, always use async scanning
- Add scan state management variables (_scanInProgress, _scanRequested)
2025-11-05 19:18:48 +10:00
alex d62f680132 Refactor to use ESPAsyncWebServer instead of ESP8266WebServer/WebServer
- Replace ESP8266WebServer/WebServer with ESPAsyncWebServer
- Update all route handlers to async pattern with AsyncWebServerRequest*
- Replace synchronous HTTPSend() with request->send()
- Add configurable delay constants (REBOOT_DELAY_MS, EXIT_DELAY_MS, ERASE_REBOOT_DELAY_MS)
- Implement scheduled reboot/abort flags instead of blocking delays
- Update WiFiManagerRequestArgs to use AsyncWebServerRequest
- Remove server->handleClient() and server->stop() calls (not needed for AsyncWebServer)
- Update parameter access to use request->getParam() instead of server->arg()
- Add ESPAsyncWebServer to platformio.ini dependencies
2025-11-04 22:51:22 +10:00
alex c2e1e7f95c Bump version to 2.0.18 2025-11-04 20:16:44 +10:00
alex 4b1226bd05 Add WiFiManagerRequestArgs class and update saveParamsCallback to pass request arguments
- Created WiFiManagerRequestArgs nested class to encapsulate HTTP request arguments
- Updated setSaveParamsCallback to accept WiFiManagerRequestArgs by value
- Updated handleWifiSave() and handleParamSave() to build RequestArgs early
- Updated doParamSave() to accept and use RequestArgs for custom HTML params
- Updated test callbacks to match new signature
- All tests passing (43/43)
2025-11-04 20:06:24 +10:00
alex 64c987a560 Remove examples directory and update tests for ESP32 compatibility
- Remove examples directory (not maintained)
- Remove ArduinoJson dependency from platformio.ini (only needed for examples)
- Update platformio.ini comments for test configuration
- Fix test_reset_settings to handle ESP32 NVS behavior differences
2025-11-02 14:17:07 +10:00
alex ca373b2b8e Consolidate and optimize test suite (80 -> 43 tests) 2025-11-02 13:44:49 +10:00
alex afb5bb61b8 Add comprehensive test suite for WiFiManager (80 tests) 2025-11-02 13:25:58 +10:00
alex b2a17d81bf Restructure project for PlatformIO best practices and add test framework
- Move library code from src/ to lib/WiFiManager/src/
- Move headers from include/ to lib/WiFiManager/include/
- Move library.json to lib/WiFiManager/
- Update platformio.ini with Unity test framework configuration
- Add test structure following PlatformIO unit testing best practices
- Remove empty src/ directory (not needed for library-only projects)
2025-11-02 12:50:57 +10:00
alex e6a0813666 Tidy up fork: remove .github, update LICENSE and README 2025-11-02 12:02:32 +10:00
alex 2b40362ff7 Refactor to proper PlatformIO library structure
- Move source files to src/ and headers to include/ directories
- Remove Arduino IDE specific files (.travis.yml, keywords.txt, library.properties, CMakeLists.txt, travis/)
- Update library.json with export section pointing to include/
- Add platformio.ini for development and testing
- Update .gitignore with PlatformIO-specific entries
- Update LICENSE with fork attribution
- Update README.md with PlatformIO-focused installation instructions

Verified working with:
- ESP8266 examples (Basic, Advanced)
- ESP32 examples (Basic)

All builds successful ✅
2025-11-02 01:05:34 +10:00
Rob Aleck 32655b7226 Update WiFiManager.cpp (#1812) 2025-03-28 19:32:57 -05:00
Pascal Brunot b67b7828b9 Fix compilation warning (#1740)
Compiler warning : format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'uint32_t'
he compiler warning arises because the format specifier %lu expects a long unsigned int, but the variable free is of type uint32_t (which is typically unsigned int). The ESP32, part of the Espressif32 family, typically defines uint32_t as unsigned int, so using the %u format specifier is appropriate.
2025-02-04 20:11:10 -06:00
Dave MadisonandAndreas Breitschopp 8e4c612fa3 Add user custom header/footer functions (#1769)
* Added setCustomTopBodyElement allowing to define custom HTML to be added at the top of the "<body>" tag.

* Change custom top body element to 'header'

This will make more sense once a footer is added. No functional changes.

* Make custom header concat conditional

Matching the _bodyClass comparison above

* Create getHTTPEnd function

* Add custom body footer functionality

* Fix <small> close tag on update page

* Add missing HTTP ends to exit and close

* Remove 'immediately' from header/footer desc

It's not immediate, the 'wrap' div is added before/after.

---------

Co-authored-by: Andreas Breitschopp <a-breitschopp@ab-tools.com>
2024-12-12 16:40:11 -06:00
Shawn A 7e2fa84daf Update cpp_lint.yml
remove line length
2024-12-12 16:39:33 -06:00
Jos Zuijderwijk 0fad7f50d1 Replace deprecated type (#1748) 2024-12-10 21:06:50 -06:00
Jack 47342ed6f7 Force remove DNS input from Captive portal issue #1733 (#1745) 2024-12-10 21:02:41 -06:00
Dave Madison 9333ec68ed Add CSS body classes for each page (#1767)
* Add body classes argument

Note that the additional function argument for getHTTPHead() includes a default argument for backwards compatibility with the API.

* Add page-specific classes

Allows easy styling of each page

* Change root CSS class to 'home'

Trying to avoid confusion between the class for the root level and the CSS ":root" pseudo-class

* Use conditional body class spacing

Avoids an extra space if a body class is set, but an empty string is passed to the function
2024-12-10 20:56:58 -06:00
Anil Raj Rimal 922059b472 fix(compile_example.yaml): Fix cache key inconsistency and correct typo in 'Compile examples' workflow (#1776) 2024-12-10 20:53:25 -06:00
Dave Madison b541d9cd9c Do not fill child backgrounds in dark mode (#1768)
Small change which allows users to style the body background with dark mode enabled, without having to style the child elements (a, h1) as well.
2024-12-10 20:26:18 -06:00
Anil Raj Rimal 7ebbcfe360 Enhance cache strategy with board-specific cache keys (#1777)
* fix(compile_example.yaml): Fix cache key inconsistency and correct typo in 'Compile examples' workflow

* feat(compile_library.yml): Use board-specific cache keys to avoid conflicts
2024-12-10 20:17:25 -06:00
David RAMBEAU a37f4fc41c FR Translation (#1755)
Proposal of French translation
2024-08-07 21:42:01 -05:00
Shawn A e978bc059c Update compile_examples.yaml 2024-03-29 20:40:20 -05:00
Shawn A 94020043a5 Update compile_examples.yaml 2024-03-29 20:39:46 -05:00
Shawn A 8cc5f290fa Rename onDemandWebPortal.ino to OnDemandWebPortal.ino 2024-03-29 20:38:12 -05:00
Harshad Italiya 4cca898927 Renaming as Arduino needs same name for sketch and directory. (#1727) 2024-03-29 14:58:31 -05:00
DarkZeros 76efbd5c36 Fix Debug Log format (#1722) 2024-03-17 15:58:54 -05:00
tablatronix d82d0a1b9f version bump 2024-03-01 20:29:49 -06:00
tablatronix b1720d2981 disable agressivereconn test method 2024-02-19 21:47:44 -06:00
tablatronix d8f8d5478a Adds connect status for ambiguous state
Will find a way to clear this up using assumption based on reason codes, wrong password is very ambiguous with PMF and modern APs
2024-02-16 22:07:21 -06:00
tablatronix 45675eae3e add debug level to version str 2024-02-16 22:02:42 -06:00
tablatronix 91451f58bf typo #1710 2024-02-15 08:59:09 -06:00
tablatronix 304d489c2f fix for #1710 2024-02-14 23:41:56 -06:00
tablatronix 607dfdb606 wifi mode debug 2024-01-22 20:35:10 -06:00
Frank Cohen 0d84861270 Wifi manager frank cohen (#1642)
* Readme update

Tested on ESP32-S3, so I added the ESP32-S3 shield to the readme

* testing a commit

* Update to Readme

Added ESP32-S3 tag and fixed the release shield to not click away from the project.

* Typos fixed
2024-01-20 10:21:23 -06:00
tablatronix e76e4c27af #1703 2024-01-16 22:13:54 -06:00
tablatronix c2af8e55d6 Update WiFiManager.cpp 2024-01-16 22:11:14 -06:00
Yohan Lasorsa 20535edf27 Allow subclassing (#1698) 2024-01-13 09:51:39 -06:00
tablatronix 73da98b3ec Remove S3 NOTEMP 2023-12-31 12:39:34 -06:00
tablatronix c09a3584dd revert, S3 platform does not have this yet 2023-12-31 12:39:19 -06:00
tablatronix 0b734828ba restore getWiFiIsSaved adds lowlevelinit 2023-12-16 22:16:20 -06:00
tablatronix 5656e5707b #1595 2023-11-22 14:08:00 -06:00
tablatronix 3efb536629 disable captiveportal for webportal 2023-11-17 19:37:44 -06:00
tablatronix 9df7acdeeb doh 2023-11-17 12:14:04 -06:00
tablatronix 18145e42ba update serverloc 2023-11-16 21:32:16 -06:00
tablatronix 0e2016879b #1558 fix?
Detect password only change
2023-11-15 21:56:07 -06:00
tablatronix 680968ff30 comments 2023-11-05 08:34:12 -06:00
tablatronix 94529cd08b turn off preload and async scanning
Until more qa can be done here , I have reports of these causing issues and first scans being empty on latest IDF and chips
2023-11-03 22:18:26 -05:00
tablatronix 7d95727761 add button funcs tests to super 2023-11-03 22:17:20 -05:00
tablatronix f328cd05cd possible fixes for these
Not entirely sure why esp8266 is not auto casting these
2023-10-10 22:52:41 -05:00
tablatronix 72956f563f Revert "Revert "#1587""
This reverts commit ba3f1986f2.
2023-10-10 21:56:28 -05:00
tablatronix 1cc7df59c2 add delays to some loops
These are fast and should not be needed but better safe I suppose
2023-10-10 07:09:39 -05:00
tablatronix 439af6e6b1 oops 2023-10-09 22:24:01 -05:00
tablatronix 99f770c493 adds button func tests 2023-10-09 22:22:36 -05:00
tablatronix 5a663db42e Fix debug_max 2023-10-09 22:22:02 -05:00
tablatronix ba3f1986f2 Revert "#1587"
This reverts commit b735c61f6e.
2023-09-28 23:41:35 -05:00
Nicolas T 6a92492bee Update WiFiManager.cpp (#1657) 2023-09-21 08:59:06 -05:00
tablatronix 0d07e09a44 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2023-09-18 18:20:48 -05:00
tablatronix d6bf07fd71 Update OnDemandConfigPortal.ino 2023-09-18 18:20:45 -05:00
tablatronix 5a8e869a7e add workaround for #1543
@etoten thanks, slight change, Might have to add ipv6 detection instead and handle it that way
2023-09-18 18:18:12 -05:00
tablatronix 465b44d734 localize debuglevel enum, add method 2023-09-18 18:14:18 -05:00
tablatronix eb27c525e3 move 404 handler public, remove 404 info, add examples for overrides 2023-09-08 13:27:15 -05:00
Avi B 3a303eeb45 Update CMakeLists.txt (#1624)
Change `REQUIRES` to `PRIV_REQUIRES` because the public API of this package does not require users of this package to know about `arduino`.
2023-06-10 20:53:21 -05:00
tablatronix 9b8de0d77f #1610 quick fix
dirty fix, will have to add proper flashstring helper casts instead probably
2023-05-18 22:51:04 -05:00
tablatronix df250c9074 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2023-05-16 20:20:05 -05:00
tablatronix b735c61f6e #1587
menutokens pointers not actually in progmem
2023-05-16 20:19:57 -05:00
Pascal Wagler cad9ffc83f Make *Show Password* a label so one can click on it (#1595) 2023-05-16 20:17:39 -05:00
tablatronix e9bbb6c588 fixes #1608 2023-05-16 20:14:38 -05:00
tablatronix 88c378f0a2 v2.0.16-rc.2 2023-05-11 13:40:19 -05:00
tablatronix aa8856adf3 #1583 missed this one 2023-05-02 15:03:29 -05:00
tablatronix 4611c75dfb fix #1540 2023-03-22 19:35:57 -05:00
tablatronix 8cf3b43efb Remove hacky scope check, param length 0 2023-03-15 21:24:44 -05:00
tablatronix ca5df00d60 fix HTTPSend copy 2023-03-15 21:17:46 -05:00
tablatronix 4c0d7fa777 Adds es_ES strings sample for WM_STRINGS_FILE
add strings file `build_flags = -DWM_DEBUG_PORT=Serial  -DWM_DEBUG_LEVEL=4 -DWM_STRINGS_FILE="\"wm_strings_es.h\""`
2023-03-15 20:58:45 -05:00
tablatronix ccf04aa5b0 added some http debugging 2023-03-15 17:54:47 -05:00
tablatronix 297123b5d7 disable hallread
I will add esp detection for this stuff before readding
2022-12-16 11:40:15 -06:00
tablatronix 32b6bda04c fixes #1532 2022-12-15 14:41:21 -06:00
Philipp bacaf521e4 Unified casing of strings (#1529) 2022-12-11 11:21:14 -06:00
tablatronix 430a9bcdcb I think i versioned this wrong 2022-12-10 11:22:15 -06:00
Shawn A 26a33e3e11 Update README.md 2022-12-08 10:18:15 -06:00
tablatronix 118ca1ec30 fixes #1528 2022-12-08 10:15:06 -06:00
tablatronix fe9774fe0f lower debug level 2022-11-28 16:34:44 -06:00
tablatronix 7cdaf5c785 2.0.0-RC.1 2022-11-28 16:32:13 -06:00
Shawn A 0080e3581e Refactor strings BREAKING (#1474)
* refactor strings, split out consts breaking!

* move consts out of strings file BREAKING

You will have to remove the constants from your strings files and add the new include instead, a simple diff should obviously show the changes

* adds WM_STRINGS_FILE for env overrides

* Revert "move consts out of strings file BREAKING"

This reverts commit bb9f092413153825d8e7acde1dcc1489e840df1e.

* Create wm_strings_en.h

* final clean up of strings_en.h, legacy

* comments
2022-11-28 16:15:20 -06:00
tablatronix 6eb8432357 add scan mode options examples 2022-11-28 15:30:44 -06:00
Shawn A 71937d1155 Update ISSUE_TEMPLATE.md 2022-11-10 13:07:45 -06:00
tablatronix 9f5981e2fd v bump 2022-10-14 11:50:32 -05:00
tablatronix 701d58fd07 fixes #1511 2022-10-14 11:35:51 -05:00
tablatronix dbefaed1a2 fix #1509 2022-10-14 11:34:50 -05:00
tablatronix 476952c2da add back button to saves 2022-10-04 16:35:43 -05:00
Avi B 48d4dbcfe5 Support for WifiManager as ESP-IDF component (#1489)
Enables support for WifiManager as an ESP-IDF component.  ESP-IDF is a popular development framework for ESP32 chips.

This file is based on the CMakeLists.txt file from the popular Adafruit-GFX-Library library.
2022-10-03 20:55:56 -05:00
Shawn A 9e4b7cb66d Update README.md 2022-09-25 11:48:03 -05:00
tablatronix 7fa6387d99 #1504 2022-09-21 11:55:56 -05:00
Thiti Yamsung 993b1ad9a9 fix: not found getChipModel method for ESP8266 (#1503) 2022-09-21 06:54:31 -05:00
tablatronix 696b920273 update rtc for resetreasons on multiple models 2022-09-20 22:11:52 -05:00
tablatronix 4ff7d7049a add chip model etc to debugging 2022-09-20 22:11:35 -05:00
tablatronix 30efa2e028 add esp model and wifi mode status to info page headers 2022-09-20 22:11:15 -05:00
tablatronix 6d23d7591f remove hall sensor, fix temp 2022-09-20 22:09:57 -05:00
tablatronix 9eee18ab32 add esp32 temp sensor back 2022-09-20 22:08:54 -05:00
tablatronix 0ae78ee339 add heaadings to template 2022-09-20 22:07:50 -05:00
tablatronix 15459925b0 ver bump 2022-09-20 19:39:50 -05:00
tablatronix d5536fbc69 remove workardound for arduino 2.0.5 #1482 2022-09-20 19:37:26 -05:00
tablatronix ac2cd86f21 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-09-16 10:22:48 -05:00
tablatronix 3545410ba4 remove captive portal check on ota done, remove serial debug 2022-09-16 10:22:34 -05:00
tablatronix dda1c45fa9 disable captive portal checks on ota uploades 2022-09-16 10:21:52 -05:00
tablatronix 297a1af260 clean up 2022-09-16 10:21:34 -05:00
Thiti Yamsung c34770ec32 feat(callback): add config portal timeout callback for handle config portal timeout (#1497) 2022-09-15 07:07:55 -05:00
tablatronix 1b5d71bac7 workaround for #1482 2022-09-12 16:06:23 -05:00
tablatronix 6fb63f834a remove wifiissaved check 2022-09-12 16:05:16 -05:00
tablatronix 2b24b91f88 fixes #1490
Does not fix wifi not init yet thanks @erriez
2022-09-12 12:06:40 -05:00
tablatronix b676daf37c oops #1403 2022-09-12 11:23:04 -05:00
tablatronix 7bdcfd501e fix esp8266 versioning 2022-09-01 15:27:31 -05:00
tablatronix 60efff754e fix redefine 2022-09-01 11:53:53 -05:00
tablatronix 62d951c8e4 try to fixup arduino version debugging info 2022-09-01 10:43:44 -05:00
tablatronix bb8aec4ce5 remove reset from basic 2022-09-01 10:43:19 -05:00
tablatronix 201ad2e838 Disable temp sensor for all esp32 until can find a better check 2022-09-01 07:54:41 -05:00
tablatronix d04d1f677b enabling #538
Turning on wifi scan preload and async scanning, with hardcoded cachetime of 30seconds. Should make wifi page load faster, and make interface seem smoother. Will have to test with various enviroments and on S2/x3 chips
2022-08-31 16:40:01 -05:00
tablatronix 9abf5abdf6 fixes #1206 2022-08-31 15:34:20 -05:00
tablatronix 5820298640 cleanup dev example 2022-08-31 14:36:30 -05:00
Shawn A 4dcf0cc78b Update discord link 2022-08-24 18:10:55 -05:00
tablatronix 94bb90322b #1403 try to increase hostname reliability and keep connect times low 2022-08-18 22:10:41 -05:00
tablatronix b90af1ac4d fixes #1068 esp32 S2
Esp32 has seeveral variations on when you can sethostname, might vary with versions so will try to add a best practice for all
2022-08-17 19:24:45 -05:00
tablatronix e0c5fb7daf Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-08-09 11:04:19 -05:00
tablatronix e9dec77a83 beta ver bump 2022-08-09 11:04:07 -05:00
John 8e0a17e5c8 Change test action to install from local directory (#1473)
* Change test action to install from local directory

* Update GH action for ESP8266 as well
2022-08-09 11:00:03 -05:00
tablatronix 58baeaba6f adds temporary fallbacks for esp32 set country
Find better way to check version feature check, arduino ver is not always available.
2022-08-09 10:59:33 -05:00
John 5ded0c9ef8 Use esp_wifi_set_country_code for ESP32 (#1470)
Replaces the use of esp_wifi_set_country() with esp_wifi_set_country_code() for ESP32 in order to both solve a crash under Arduino 2.x and remove the requirement to independently maintain country-specific channel settings
2022-08-09 10:44:06 -05:00
JoergAJ 7d498ed50a Added links in readme file (#1446)
* Update README.md

Updated links to examples

* Update README.md

Updated links

* Update README.md

* Update README.md

* Update README.md

* Update README.md

added placeholder links for buttons

* Update README.md

added links to the action workflow (compile_library /examples) + expressif links to the product pages
2022-07-15 11:59:12 -05:00
tablatronix f2ed2cb997 #1452
Possible fix
2022-07-13 22:14:58 -05:00
tablatronix b8205e71f3 add connection fixes for esp32 wifi not started yet 2022-06-30 13:40:38 -05:00
tablatronix 605d1e897a add missing debug toggle 2022-06-30 12:14:23 -05:00
45gfg9 01bd8a398b Update WiFiManager.cpp (#1443)
Avoid constructing two String objects and adding them together. Just concatenate c-strings.
2022-06-28 13:14:06 -05:00
tablatronix 65fec94317 fix compiler warnings #1421 2022-06-26 23:22:10 -05:00
tablatronix 06c63720f6 #1421
remove temp
2022-06-26 16:39:33 -05:00
tablatronix 14aeb7575f Fix hostname for esp8266, needs to run after sta ughh 2022-06-24 23:44:03 -05:00
tablatronix afd328b3b2 Fix hostname #1403 2022-06-24 20:07:17 -05:00
tablatronix 9e408e41a8 LittleFS Basic example 2022-06-22 10:50:47 -05:00
tablatronix 6522cb30a8 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-06-21 08:22:00 -05:00
tablatronix 260a9abee8 add input type example 2022-06-21 08:21:58 -05:00
tablatronix 3c2a05312b Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-06-20 22:14:12 -05:00
tablatronix b05a71b618 add comments for httpupdate callbacks 2022-06-20 22:13:30 -05:00
tablatronix f9a47786b7 adds otacallback and progress example callback for Update lib #1435 2022-06-20 22:12:52 -05:00
tablatronix a2c33744f6 rename wifi callbacks 2022-06-17 14:21:13 -05:00
tablatronix 317c026952 adds setPreSaveParamsCallback
//called when saving params before anything else happens
    void          setPreSaveParamsCallback( std::function<void()> func );
2022-06-17 14:07:11 -05:00
tablatronix b5671834e4 Moves presavecallback after static ip copy
#1429
2022-06-17 13:50:33 -05:00
tablatronix 7078bd1786 add template js #1430 2022-06-17 12:35:53 -05:00
Martijn Hendriks 1af8f4540d Update strings_en.h (#1430)
show/hide wifi password during input
2022-06-17 12:35:17 -05:00
tablatronix b257590e98 comments 2022-06-17 11:46:49 -05:00
tablatronix ca4b63220c remove double non blocking timeout handler 2022-06-17 11:36:21 -05:00
tablatronix 0ab747c62a going through todos 2022-06-17 11:13:39 -05:00
JoergAJ c6e2b1b349 Updated links in README.md (#1431)
* Update README.md

Updated links to examples

* Update README.md

Updated links

* Update README.md

* Update README.md

* Update README.md
2022-06-16 15:33:51 -05:00
tablatronix 9c7fed4fe1 update template 2022-05-15 08:29:51 -05:00
tablatronix c56eec9018 change css disabled for all 2022-05-15 08:26:04 -05:00
Perry e7bb9bc28e Change Stream to Print (#1307)
* Change Stream to Print 1/2

Update WifiManager to use base class Print instead of Stream.

I debug into a custom buffer, and that buffer implements Print, but not Stream.

* Change Stream to Print 2/2

Update WifiManager to use base class Print instead of Stream.

I debug into a custom buffer, and that buffer implements Print, but not Stream.
2022-05-08 09:30:33 -05:00
Michael Ammann 137410e184 Silence debug output (#1404)
This is probably a left over from debugging, can we remove or at least move it to a DEBUG_WM
2022-05-08 09:28:07 -05:00
Anthony Bryant 86e413dc2a Escape single quotes in htmlEntities() (#1413)
This should allow SSIDs that contain single quotes to populate data-ssid correctly. Without this patch, clicking on an SSID containing a single quote will either:
* Not use the whole SSID, in cases where there's text before the quote:
  `foo'bar` will appear in the SSID box as just `foo`
* Fall back to innerText, in cases where the quote is the first character in the SSID:
  `'); DROP TABLE WIFI; --` will appear in the SSID box as a version that has spaces converted to non-breaking spaces, causing the connection to eventually fail with WL_NO_SSID_AVAIL.
2022-05-08 09:27:17 -05:00
tablatronix 8d34744b29 fixes #1414
added a prefix to macros
2022-05-08 09:24:28 -05:00
alexmaurer-madis 833420fe99 WM_VERSION_STR correction (used in About section) (#1407)
From  "v1.0.11-beta" to "v2.0.11-beta"

I think the major version was forgotten to be updated.
2022-05-03 09:38:44 -05:00
tablatronix b7ca079d9d add favicon example 2022-04-19 20:55:24 -05:00
tablatronix 13b43076f9 bump beta 2022-04-14 12:08:37 -05:00
Ovidiu Pruteanu cd01cbf77d Add .idea to .gitignore for JetBrains IDEs (#1391) 2022-04-12 08:11:31 -05:00
tablatronix 483b83489b Fix #1383 2022-04-11 20:23:43 -05:00
tablatronix 7bffda3fe6 adds option to keep cfgp open on wifi save
// if true (default) then stop the config portal from autoConnect when wifi is saved
    void          setDisableConfigPortal(boolean enable);

Name will change
2022-04-08 20:44:08 -05:00
tablatronix 590e212ddb better fix $1386 2022-04-07 08:41:57 -05:00
tablatronix 379ffee475 clean up variable declarations 2022-04-07 08:38:23 -05:00
tablatronix 1e628625aa fixes #1386
8
2022-04-07 08:37:43 -05:00
tablatronix c9393744a4 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-03-29 14:46:49 -05:00
tablatronix 918e02ddfd add resetsetting delay, some complaints its not working shrug 2022-03-29 14:46:42 -05:00
tablatronix 9cd81e3af9 debug 2022-03-29 14:46:08 -05:00
tablatronix ba6336587e Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-03-29 13:35:00 -05:00
tablatronix 6a85acdf85 add customMenuHTML 2022-03-29 13:34:58 -05:00
tablatronix 88b97c7caa #1383 fix 2022-03-29 13:31:41 -05:00
John ea4ee025f2 Output "Unknown" if Arduino/ESP-IDF version is unknown (#1382)
Closes #1381
2022-03-28 20:41:08 -05:00
tablatronix 278c57b4ec fixes #1379 2022-03-28 08:23:16 -05:00
tablatronix 91826229cb oops 2022-03-26 13:01:01 -05:00
tablatronix 9cec5a25a8 bump version 2022-03-25 14:41:03 -05:00
tablatronix da02b59a21 update template styles, add versionng to info 2022-03-25 14:40:52 -05:00
tablatronix e9a02d4668 add some button feedback 2022-03-25 14:36:46 -05:00
tablatronix b4368308ca remove bad example 2022-03-14 06:43:23 -05:00
tablatronix 47ce0110af Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-03-13 21:36:32 -05:00
tablatronix eb5ba12df1 #1371 2022-03-13 21:36:25 -05:00
tablatronix d70f358f3e add check to dissallow starting cp if already running
This will avoid support inquiries and add a log
2022-03-13 21:34:26 -05:00
tablatronix 1f3b2e34ae typo 2022-03-13 21:26:13 -05:00
tablatronix 0994c4b3f8 regression, webserver callbacks before reset crashes
any webserver event handlers bound before the webserver new reset would cause memory access issues when triggered.

Should remove all events on reset or make memory safe, not sure if this is the correct way to be reseting the webserver, but there were issues with the ports not releasing etc.
2022-03-11 08:34:08 -06:00
tablatronix 0d61a6b55f esp32 crashes on cb route shared pointer 2022-03-11 00:05:01 -06:00
tablatronix e830fa26e3 Adding a data attribute for ssid for input value
so it has nothing to do with the html , and can have different encoding, we could also just use IDs but scan cannot change, or use bssid

#1370
2022-03-11 00:04:21 -06:00
tablatronix acdad80a43 add callback debuggin 2022-03-10 22:34:03 -06:00
tablatronix 8f2c7ae870 remove test 2022-03-10 15:45:49 -06:00
tablatronix 713fcfc740 disable country in example 2022-03-10 15:41:07 -06:00
tablatronix e6d21b8436 use macro for webserver routes fstring helper 2022-02-24 12:15:11 -06:00
tablatronix 0aecb22904 Fix old sdk esp8266 error w softapssid 2022-02-24 11:50:08 -06:00
tablatronix fd7f400b25 Revert "Both infoids and _ap_password are intialized by check time. (#1344)"
This reverts commit 9f6dcad791.
2022-02-24 11:44:45 -06:00
tablatronix d8c81ecca1 macro test 2022-02-24 11:43:42 -06:00
tablatronix 8ecf0575a1 remove old content length headers 2022-02-24 10:45:06 -06:00
tablatronix e9d0012cce abstract httpserver setup 2022-02-23 16:46:24 -06:00
tablatronix c987ee93c8 abstract httpsend 2022-02-23 16:36:52 -06:00
Andy Piper 8279c5be2a Fix "Acccess" typo (#1366) 2022-02-23 13:08:30 -06:00
tablatronix 5acc7cc9aa css tweaks for inputs including select,checkbox
added vertical margins to inputs
2022-02-22 13:41:27 -06:00
tablatronix 14cf6b81d4 bump 2022-02-15 20:59:27 -06:00
tablatronix 36ed8c1af6 undo dashes, no clue
I will have to figure out why this causes ap not found on save, the string looks clean but there must be something going on, scan result not const?
2022-02-15 20:03:22 -06:00
tablatronix a581de29f3 bump ver bugfix 2022-02-15 08:26:55 -06:00
tablatronix 4ab63aa1e9 remove esp32 softapssid, ver check not working correctly 2022-02-15 08:26:42 -06:00
tablatronix c2081aaae7 bump releaase 2022-02-13 15:36:20 -06:00
tablatronix abd52d4754 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-02-04 22:04:22 -06:00
tablatronix 5052c675be version debug 2022-02-04 22:04:21 -06:00
tablatronix 755aca1643 #1348 just change _hostname to string ? 2022-02-04 22:04:10 -06:00
Shawn A 068c32ad27 oops 2022-02-04 18:12:14 -06:00
tablatronix fa76838ee5 fix esp32 softapssid 2022-02-04 17:54:50 -06:00
tablatronix 4d999b1456 fix #1353 #1354 2022-02-04 12:35:10 -06:00
Shawn A 78ca3ee39a badgers 2022-02-02 20:57:56 -06:00
tablatronix 68f5195260 add seminqignal to example dev 2022-01-24 14:13:36 -06:00
tablatronix 4086e46f6c fix param out of scope check, avoids some exceptions 2022-01-24 14:13:03 -06:00
tablatronix cf9d85fd6d add dashes to htmlentities 2022-01-24 14:12:42 -06:00
tablatronix 7c05228def debug logging 2022-01-24 14:12:21 -06:00
tablatronix 924cc06bb2 remove empty ssid, no idea what these are 2022-01-24 14:11:01 -06:00
tablatronix c3c741a2c0 add flash warning 2022-01-24 10:48:35 -06:00
Shawn A 6e057dfbb2 add connect timer log 2022-01-23 20:48:37 -06:00
Shawn A c8a8cc2f31 remove event debug 2022-01-23 20:45:37 -06:00
Shawn A c12d3c4a6e add aggressive recon options 2022-01-23 20:39:15 -06:00
Pedro Gabriel Planel 9f6dcad791 Both infoids and _ap_password are intialized by check time. (#1344)
Comparing it to NULL raises operation overload.
2022-01-23 20:01:05 -06:00
Shawn A 62ba184cc8 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2022-01-22 10:15:59 -06:00
Shawn A cfe2619069 add debugging 2022-01-22 10:15:58 -06:00
tablatronix 810f144cff keep portal open if connectonsave is false
Not sure if this is a good idea or bad one.. probably better than closing it automatically.
2022-01-21 16:14:11 -06:00
tablatronix 553ae00bac #1327 2022-01-21 14:02:59 -06:00
ricardollreis d0bdf7bdaa Enable Portal Timeout in not Blocking Portal (#1331)
Enable the use of setConfigPortalTimeout( ) & setConfigPortalBlocking(false) at same time, by calling process()
2022-01-06 11:04:13 -06:00
tablatronix 8452df79bb patch for arduino 2.0 event names 2021-11-09 08:24:14 -06:00
Shawn A 72b5331610 possible fix #1306 2021-10-30 16:51:39 -05:00
Shawn A 9d061ab24e fixes #1295 2021-10-01 21:17:37 -05:00
tablatronix 927e3e8db0 comment example 2021-09-29 13:47:02 -05:00
tablatronix deeff9fa89 fixes #1297 2021-09-29 13:46:21 -05:00
tablatronix 654d692025 move version to top 2021-09-29 13:07:35 -05:00
Shawn A f1779c97a1 Update titles 2021-09-17 15:31:02 -05:00
tablatronix 9553022b40 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-09-17 10:05:16 -05:00
tablatronix c77ab9e62c flip the --board args, although it was working already 2021-09-17 10:05:04 -05:00
Shawn A 2c28203c29 add discord 2021-09-17 10:02:30 -05:00
Shawn A 05807f56d8 Update README.md 2021-09-17 09:50:18 -05:00
Shawn A fd30eff2bf Update README.md 2021-09-17 09:49:27 -05:00
Shawn A aa20fbc789 swap CI badge 2021-09-17 09:49:03 -05:00
tablatronix ac089992e8 oops forgot this second section 2021-09-17 09:42:37 -05:00
tablatronix 2001438d6f fixing examples and actions 2021-09-17 09:37:07 -05:00
tablatronix 5928293c89 moved non blocking to advanced, accidently put in basic 2021-09-17 09:33:31 -05:00
tablatronix 5e9b0091da wrong case path 2021-09-17 09:22:16 -05:00
tablatronix aa59dcfe0f removed double author from arduino manifest, seems to mess up library searching 2021-09-17 09:17:39 -05:00
tablatronix 5bab658031 oops removed another example 2021-09-17 09:08:35 -05:00
tablatronix 08b2f4d83d change actions compile examples 2021-09-17 09:08:07 -05:00
Dmitriy Shafranskiy 2d2b9f82f3 CI / DC Update - Library Build, Linting, Examples Json Fix (#1264)
* Create main.yml

added onPush & onPull

* Update examples_esp8266.yml

added on push & on pull

* Delete main.yml

* Create examples_esp32.yaml

* CI/DC update

* CI/DC update

* CI/DC update

* hardcoded json lib version

* hardcoded json lib version

* hardcoded json lib version
2021-09-17 09:02:53 -05:00
tablatronix ef8bef1f4d Move spiffs examples, restructure params examples 2021-09-17 08:59:42 -05:00
tablatronix ef09264b6d remove empty example 2021-09-17 08:56:49 -05:00
tablatronix f9091951be add non blocking to basic 2021-09-17 08:56:28 -05:00
tablatronix 925eb79066 clean up spiffs examples 2021-09-17 08:43:01 -05:00
Ruan de Villiers 917f8bbfb0 Auto check ArduinoJson rather than using a #define 2021-09-17 08:32:41 -05:00
tablatronix 620ca70086 Merge branch 'master' into esp32s2 2021-09-09 10:18:58 -05:00
tablatronix 55d7ccbd7a Add better handling of arduino ver checking 2021-09-09 10:18:40 -05:00
tablatronix f199906e9d Testing fixes 2021-09-08 16:41:34 -05:00
Mollayo 70776a0a05 Using __FlashStringHelper for customHTML (#1292)
* Add callback for OTA update

* Using __FlashStringHelper for customHTML
2021-09-08 10:52:21 -05:00
tablatronix 94754e60b5 Merge branch 'master' into esp32s2 2021-09-08 10:49:10 -05:00
Mollayo 8ce698427d Add callback for OTA update (#1286) 2021-09-03 21:23:37 -05:00
tablatronix 8984863fe6 update example action 2021-06-21 11:15:56 -05:00
Dmitriy Shafranskiy cdd8a406a8 Added Github Action to Compile Examples on ESP8266 (#1258)
* Create examples_esp8266.yml

Init add of examples compilation

* Update examples_esp8266.yml

* Update examples_esp8266.yml

* Update examples_esp8266.yml

* Update examples_esp8266.yml

* Update examples_esp8266.yml

* Update examples_esp8266.yml
2021-06-21 11:11:39 -05:00
Shawn A d395e496a1 update travis url 2021-06-21 11:04:20 -05:00
tablatronix e87141eb04 bump arduinojson CI 2021-06-21 10:57:47 -05:00
tablatronix 8c1e890c36 remove uneeded test 2021-06-21 10:54:49 -05:00
tablatronix 109a618c1f Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-06-21 10:42:36 -05:00
tablatronix ce37e5c8ff file was named wrong 2021-06-21 10:42:34 -05:00
Shawn A 8503260101 Merge pull request #1005 from flavio-fernandes/constWiFiManagerParameter
trivial: WiFiManagerParameter get accessors should work on const
2021-06-21 10:28:52 -05:00
tablatronix 2ce0850d80 Renamed example folders 2021-06-21 10:06:46 -05:00
tablatronix 3bf0d4bed3 fix presavecallback called twice if params in wifi 2021-06-21 09:49:39 -05:00
tablatronix 69c60e8e4e drop debug back to verbose 2021-06-12 10:21:46 -05:00
tablatronix a83ac6e926 debugging, bypass loop if portalstopped
I really have to fix this state handling
2021-04-24 12:06:34 -05:00
tablatronix 14f70dde76 Switched to abort for #1243 2021-04-24 10:49:19 -05:00
tablatronix 5fa729170a oops 2021-04-24 09:14:00 -05:00
tablatronix b78efd36df oops #1243 2021-04-22 17:18:36 -05:00
tablatronix 8448d66ea7 #1243 clean 2021-04-22 17:16:34 -05:00
tablatronix bcf1dd69ff oops, fix comemnt 2021-04-22 11:09:19 -05:00
tablatronix 7820fb72e7 #1243 setSaveConnect()
can disable connect when save, does not alter return codes!
2021-04-22 11:06:12 -05:00
tablatronix 3bec5ade1a Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-04-13 14:40:08 -05:00
tablatronix 4d37843af8 fix #1241 maybe 2021-04-13 14:40:06 -05:00
tablatronix 87fcf08ee0 remove content-length heasders #1235 2021-04-13 14:35:27 -05:00
tablatronix f5dd402ba2 Fix ota title 2021-04-08 17:01:47 -05:00
tablatronix 960ef96805 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-04-05 10:05:15 -05:00
tablatronix d157694b12 minor whitespzce 2021-04-05 10:05:14 -05:00
Shawn A 1e90d22d3b removed development branch 2021-03-31 22:07:51 -05:00
Shawn A f16af759d1 Update ISSUE_TEMPLATE.md 2021-03-24 12:57:42 -05:00
tablatronix e8297f9b8f Merge branch 'master' into esp32s2 2021-03-18 16:56:35 -05:00
tablatronix 8bfc228695 fix for numretries not bailing 2021-03-18 16:56:25 -05:00
tablatronix 9b100c34dc missed one #1226 2021-03-18 14:28:04 -05:00
tablatronix c47fc907a9 fix array sizes for info 2021-03-17 14:52:11 -05:00
tablatronix 34e30277d7 double debug 2021-03-17 14:50:15 -05:00
tablatronix cd9e2070c3 fix bug in setconnecttimeout 2021-03-17 14:41:54 -05:00
tablatronix 1431ca7615 Revert "Merge pull request #1206 from cpainchaud/patch-1"
This reverts commit 65d3affda3, reversing
changes made to fe8d2970a0.
2021-03-17 13:46:00 -05:00
tablatronix a9507c98b5 test fixes for v3 esp32 S2 2021-03-16 08:53:17 -05:00
Shawn A 65d3affda3 Merge pull request #1206 from cpainchaud/patch-1
fix potential memory leak in  WiFiManagerParameter::setValue
2021-03-11 13:25:27 -06:00
tablatronix fe8d2970a0 better checking 2021-03-10 11:59:11 -06:00
tablatronix d805cbdc0c oops fix syntax 2021-03-10 11:58:51 -06:00
tablatronix 3e8560c570 fix for esp32 will have to shim 2021-03-09 14:15:34 -06:00
tablatronix 848a107b16 reorder info page 2021-03-09 14:09:14 -06:00
tablatronix 5578cb85c6 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-03-09 11:35:22 -06:00
tablatronix e24108fa45 debugplatform 2021-03-09 11:35:20 -06:00
tablatronix 2dd2eb1d7e fix omit param page if no params 2021-03-06 20:48:16 -06:00
tablatronix 04a39c2917 fix title on ota 2021-03-06 20:10:54 -06:00
tablatronix dac0018d77 Add ability to set custom titles, change page header titles
Replaces root WiFiManager title with cusotm as well as page title, Also swaps headers, title first then domain - ip
2021-03-06 20:09:12 -06:00
tablatronix c48173e32a Add ability to customize debug prefix 2021-03-06 11:25:38 -06:00
tablatronix 133dd8cd52 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-03-06 11:12:08 -06:00
tablatronix 0dbffbb730 adds wifi config tests 2021-03-06 11:12:01 -06:00
tablatronix 8aca0beccb fixup some debugs for portal timeout 2021-02-22 16:04:56 -06:00
tablatronix 77bd201d13 fixes #1210
Moves dns server out of webportal setup as it is only needed for softap and captive portal, still enabled for portal so cp can be toggled on and off
2021-02-22 16:04:37 -06:00
tablatronix 0780e4fe02 adds preloadWiFi default ssid pass 2021-02-05 16:23:44 -06:00
tablatronix c710e9ecbe add br to no networks error 2021-02-05 15:47:13 -06:00
tablatronix 2fdba90efb Remove links from help for dangerous items 2021-02-05 11:09:02 -06:00
Christophe Painchaud 9d9d314a0c fix syntax error 2021-02-05 17:50:34 +01:00
Christophe Painchaud bd59d98b91 fix potential memory leak in WiFiManagerParameter::setValue 2021-02-04 23:29:25 +01:00
tablatronix f122cc9509 fix ota debug 2021-02-04 13:23:48 -06:00
Shawn A 1c72f4c944 Merge pull request #1204 from cpainchaud/patch-1
fix  debug message in WiFiManager::handleParamSave
2021-02-04 12:05:40 -06:00
Christophe Painchaud 42532f995b fix debug message in WiFiManager::handleParamSave
DEBUG_WM(DEBUG_VERBOSE,F("<- HTTP Wifi save "));  while it's obviously Params instead of Wifi
2021-02-04 19:01:04 +01:00
tablatronix f714000fb9 Fixup ota 2021-02-04 10:25:30 -06:00
tablatronix 83e9bbc9db fix esp32 ota size 2021-02-03 16:18:19 -06:00
tablatronix ef8e26c87e debugger adjustments 2021-02-03 12:34:14 -06:00
tablatronix 0d04a14352 fix esp32 country err handle 2021-02-03 11:25:59 -06:00
tablatronix f9b86f6870 Changed ssid psk gets to peristent
Status would not show existing saved ssid psk or status if connect failed, as current config is empty if conx fails, this might break something not sure what else I am using non persistent checking for
2021-02-03 10:01:10 -06:00
tablatronix e933a20d20 Fixes #1203
Psk placeholder should not show if no psk is saved
2021-02-03 09:59:20 -06:00
tablatronix 6119a9efdf refactor #1199 2021-01-28 12:15:57 -06:00
Shawn A 9eac697606 Merge pull request #1199 from cpainchaud/master
adding WifiManager::isConfigPortalActive() abd WifiManager::isWebPortalActive()
2021-01-28 12:06:55 -06:00
Christophe Painchaud 87ec3c8d8d adding WifiManager::isConfigPortalActive() abd WifiManager::isWebPortalActive() 2021-01-28 18:13:09 +01:00
tablatronix 73b465329c clean up redundant debug blocks 2021-01-26 11:18:50 -06:00
tablatronix 245d24b31b fix comments for callbacks 2021-01-25 15:52:11 -06:00
tablatronix 1fc27318d3 Remove branch references 2021-01-25 10:28:39 -06:00
tablatronix 6eb463d646 Merge branch 'master' of https://github.com/tzapu/WiFiManager 2021-01-15 13:33:01 -06:00
tablatronix fcc662c70a add setDarkMode alias 2021-01-15 13:32:59 -06:00
tablatronix 60c1b8617d adding ota error 2021-01-09 11:26:05 -06:00
tablatronix 28a0dcbf13 Merge branch 'master' into development 2021-01-04 11:21:26 -06:00
tablatronix 0602cdcb41 Update .gitignore 2020-12-22 08:44:00 -06:00
Shawn A 6205ddc3d8 Delete .DS_Store 2020-12-22 08:41:41 -06:00
tablatronix e759a48847 esp temp and hall test 2020-12-18 16:26:34 -06:00
tablatronix b3d45031a5 update esp info page 2020-12-18 14:52:23 -06:00
tablatronix db74856951 Fix warning 2020-12-18 14:52:03 -06:00
tablatronix 0b68256215 #1158 2020-12-18 13:26:47 -06:00
tablatronix 6e05a9ff27 fix bad code, this was not supposed to be commited, sorry 2020-12-16 16:37:05 -06:00
tablatronix 41cb00ecaa fixes #1177 oops 2020-12-16 16:23:30 -06:00
Shawn A 4d2a6b2bac Merge pull request #1175 from egrekov/development
Fix. The library is not assembled under ESP8266
2020-12-16 09:32:16 -06:00
Evgenii Grekov 1e85c0e35e Fix. The library is not assembled under ESP8266 2020-12-16 15:17:38 +05:00
Shawn A 82701d9ec7 Update README.md 2020-12-15 20:22:33 -06:00
tablatronix e071e3ad8f debugging testing country esp32 2020-12-14 22:48:10 -06:00
tablatronix e394283fda fix ota handler string 2020-12-14 17:26:44 -06:00
tablatronix 4e4942b511 fixes #1169 for now 2020-12-12 18:25:08 -06:00
tablatronix 1fb70a9b44 fixes #1164 thanks @fretzbiz 2020-12-09 20:50:48 -06:00
Shawn A f0d3a24c11 badgers? 2020-12-08 14:03:07 -06:00
Shawn A 86a97d7669 gitter 2020-12-08 13:38:31 -06:00
tablatronix 506b3c48f3 Merge branch 'development' into ota 2020-12-08 12:59:00 -06:00
tablatronix 16bd0f4f3c dev v2.04 beta 2020-12-08 12:57:33 -06:00
tablatronix 78f00ffe0a v 0.16 2020-12-08 12:54:46 -06:00
Shawn A a72930eebf Merge pull request #1155 from ivankravets/patch-7
Fix library name
2020-12-08 10:31:44 -06:00
Ivan Kravets 8d967a6dfc Fix library name 2020-12-02 15:08:27 +02:00
tablatronix 321034b99e Moved debug strings no in flash, added WM_NODEBUG 2020-12-01 12:07:06 -06:00
tablatronix d8c7d2a6f0 Remove debug 2020-12-01 11:36:41 -06:00
tablatronix fc48649129 nother 2020-12-01 11:33:44 -06:00
tablatronix 12c114d11b missed one 2020-12-01 11:31:31 -06:00
tablatronix 2c84651286 clean up debug lines 2020-12-01 11:27:58 -06:00
tablatronix b34efd0206 testing basic auth 2020-12-01 10:09:15 -06:00
tablatronix 54904d316b add info page ota update 2020-12-01 10:09:01 -06:00
tablatronix 35e9f41b8b Merge branch 'development' into ota 2020-11-23 13:07:59 -06:00
Shawn A b5508762ef Merge pull request #1151 from brewpi-remix/development
Use constrain properly
2020-11-22 10:05:18 -06:00
Lee Bussy 3a66412db4 Merge pull request #1 from brewpi-remix/fix-constrain
Use constrain properly
2020-11-22 07:58:31 -06:00
Lee Bussy 5def8f84d4 Use constrain properly 2020-11-22 07:58:02 -06:00
tablatronix e1a263b47f forgot to clamp 0 2020-11-19 14:42:38 -06:00
tablatronix 3828790109 remove warnings 2020-11-19 14:25:21 -06:00
tablatronix a7fb6d5caf adds #1137 connect retries
setConnectRetries()
2020-11-19 14:25:12 -06:00
Flaviof 08fbe310b7 Merge branch 'development' into constWiFiManagerParameter 2020-11-19 14:32:36 -05:00
Shawn A 9e29835ac8 Merge pull request #1106 from davefiddes/fix-warning-in-debugplatforminfo
Fix warning in WiFiManager::debugPlatformInfo for ESP32
2020-11-19 13:11:32 -06:00
tablatronix e454c9969a remove oled stuff 2020-10-17 21:44:55 -05:00
tablatronix 08efbfcfe7 remove country debug 2020-09-15 10:18:43 -05:00
tablatronix 726bdfae46 #1125 remove country from 2.3.0 2020-09-15 09:54:45 -05:00
tablatronix 61916627ed example compile issue 2020-09-14 10:23:09 -05:00
tablatronix d1656421bb remove getheapstats, not exist in 2.3.0 2020-09-14 10:23:00 -05:00
David J. Fiddes fac59e1982 Fix warning in WiFiManager::debugPlatformInfo for ESP32
This fixes an unused variable warning as the call to
heap_caps_get_free_size() is not required.

Tests:
 - Enable debug mode and verify free heap and ESP SDK
    version are correctly displayed
 - Cross check with the free heap reported via the captive
    portal info page
2020-08-13 18:19:55 +01:00
tablatronix 31be25d54b Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2020-08-04 23:24:29 -05:00
tablatronix 994609f1e0 add logging 2020-08-04 23:24:28 -05:00
Shawn A 4319a66da9 Merge pull request #1073 from adrianjost/patch-1
swap comments
2020-06-07 13:58:21 -05:00
Adrian Jost 998243c60c swap comments 2020-06-07 20:26:03 +02:00
tablatronix 9af72535ef I messed up 2020-05-25 11:42:31 -05:00
tablatronix 2cedf7b368 2.0.2 2020-05-24 14:11:25 -05:00
tablatronix af3c3671a2 oops, remove js alert debug 2020-05-24 13:19:00 -05:00
tablatronix 80a8dfd554 Merge branch 'master' into hotfixes 2020-05-22 10:09:56 -05:00
tablatronix bc06bb0a1b clean up dev example a little 2020-05-19 23:26:08 -05:00
tablatronix 57a9f17335 add mdns update to process 2020-05-19 23:25:54 -05:00
Shawn A b2f87abd1b Update README.md
Title..
2020-05-19 16:18:44 -05:00
tablatronix 01538e69c1 cleaning up .h 2020-05-19 11:55:58 -05:00
tablatronix 3c0c3ff93e adds green status S, adds test back button 2020-05-19 11:34:31 -05:00
tablatronix f99eda8a9f Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2020-05-19 10:58:12 -05:00
tablatronix d71a14194b Fix MDNS
stupid c++ macros
2020-05-19 10:58:10 -05:00
Shawn A 95d116cea3 Update README.md
:warning
2020-05-18 16:34:27 -05:00
Shawn A f4a577bbc2 Update README.md 2020-05-18 16:31:13 -05:00
tablatronix 634fac4be0 fix travis esp32 2020-05-18 15:49:24 -05:00
tablatronix b67d1656d8 Fix esp32 mdns 2020-05-18 15:46:44 -05:00
tablatronix 01b909a1d2 version alpha release 2020-05-18 15:36:15 -05:00
tablatronix 5edf38550a update 2020-05-18 15:35:50 -05:00
tablatronix 7458674c7b Merge branch 'development' into ota 2020-05-15 16:53:13 -05:00
tablatronix 0486034c6a some comments etc 2020-05-14 21:56:33 -05:00
tablatronix 6029a39f05 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2020-05-14 21:55:49 -05:00
tablatronix 3e9f9a103e #1050 prevent copy assignment of param constructor 2020-05-14 21:55:47 -05:00
Shawn A 062e66bb3c Merge pull request #1053 from dontsovcmc/readme_dns
Readme: fill DNS server if setSTAStaticIPConfig
2020-05-14 08:21:00 -05:00
doncov.eugene 7b52e709db Readme: fill DNS server if setSTAStaticIPConfig 2020-05-14 15:50:39 +03:00
tablatronix 135e872caa remove debug 2020-05-11 21:29:46 -05:00
tablatronix 6515190124 fixes #1046 2020-05-11 17:23:20 -05:00
tablatronix 32075b32cd fixes #1040, adds http port
`setHttpPort`
2020-05-11 12:39:50 -05:00
tablatronix 6b6a960075 Merge branch 'development' into ota 2020-05-10 14:00:22 -05:00
tablatronix 5aebb1dd51 Some hostname testing 2020-05-08 23:31:02 -05:00
tablatronix 293f705b0f #1039 2020-04-19 00:53:18 -05:00
tablatronix e9d75a08b8 Disables usermode restore
I may add optionals later for this, right now sta mode is the default, and sta mode will always be the only mode on after using WM, if you were using ap mode you have to turn it back on yourself until I have a better solution or documentation.
2020-04-10 10:06:11 -05:00
tablatronix 709cfffb95 adds embedded logo example 2020-04-07 11:42:01 -05:00
tablatronix 6c08094e41 Skip autoconnect when there are no creds saved 2020-03-13 11:35:04 -05:00
tablatronix 4a98ba0e29 Update OnDemandConfigPortal.ino 2020-02-27 11:34:31 -06:00
tablatronix 3f93afe9c2 change debug saves logs 2020-02-25 16:31:45 -06:00
tablatronix eb771a0608 Merge branch 'development' into ota 2020-02-19 12:54:04 -06:00
tablatronix 89fcfe9680 adds to dev example 2020-02-18 16:25:17 -06:00
tablatronix b61bc261bf disable clean connect, OPTIONAL setter
setCleanConnect(bool enable); // default false

This was originally intended to improve connection stability, but it is now causing problems , this is now disabled and can be reenabled optionally.
Possible race condition diconnecting while auto connecting or async setmode delays
2020-02-18 16:14:45 -06:00
tablatronix decd2942c5 fix param out of scope check in doparamsave 2020-02-18 15:09:42 -06:00
tablatronix dd8bbea8c5 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2020-02-18 13:31:49 -06:00
tablatronix bdb1ab3c32 comments, dev example tests 2020-02-18 13:31:40 -06:00
Shawn A e173946284 Merge pull request #1011 from marcovannoord/patch-1
Update WiFiManager.cpp
2020-02-18 13:29:28 -06:00
Marco f7d4c166ae Update WiFiManager.cpp
Fixed bug where, after clicking "Save", it would display an empty page to the user, instead of the wifi save page. (due to local variable)
2020-02-18 11:02:56 +01:00
Flavio Fernandes 893568052a trivial: WiFiManagerParameter get accessors should work on const instances
Enhancement: It should be okay to invoke getID() and getValue() in a
const instance of the WiFiManagerParameter class.

See: https://github.com/flavio-fernandes/persistWifiSetting/commit/135adb1c7e436db1ed92ccd5eb522b9ae418b216
2020-02-07 07:39:46 -05:00
Shawn A 9967d27148 Merge pull request #993 from Ruandv/issue654
Fix ArduinoJson (Using ARDUINOJSON_VERSION_MAJOR)
2020-01-27 14:28:25 -06:00
tablatronix cc4acba4ab add shouldbreakafterconifg workaround to readme 2020-01-22 10:51:27 -06:00
tablatronix 87009dc443 fixes #987 2020-01-22 10:42:08 -06:00
tablatronix 2f76338ec7 merge and release hotfixes 2020-01-22 09:05:41 -06:00
tablatronix f3c1964e1c Merge branch 'hotfixes' 2020-01-22 09:04:39 -06:00
tablatronix 13132edd9e Easier debugging autoconnect 2020-01-22 09:02:02 -06:00
Shawn A 0a7d7469fd Merge pull request #995 from revolter/patch-1
Add missing line to code sample
2020-01-22 08:58:43 -06:00
Iulian Onofrei 725f824e58 Add missing line to code sample 2020-01-19 18:35:06 +02:00
Ruan de Villiers a6438edb3c Auto check ArduinoJson rather than using a #define 2020-01-15 07:24:28 +02:00
Ruan de Villiers 9669bfd1a3 Added functionality to toggle between ArduinoJson 5 and 6 2020-01-14 21:20:51 +02:00
Ruan de Villiers 210b4c5d01 Updated AutoConnectWithFSParameters to toggle between ArduinoJson5 and ArduinoJson6 2020-01-14 21:07:38 +02:00
tablatronix ef962adc57 Merge branch 'development' into ota 2019-12-12 12:41:27 -06:00
tablatronix c9665adfaf oops remove mdns test 2019-12-03 23:00:40 -06:00
tablatronix 12fde678e5 bump arduino ide 2019-12-03 22:55:59 -06:00
tablatronix 351761b9a7 travis failing shrug
`home/travis/.arduino15/packages/esp8266/hardware/esp8266/2.6.0/cores/esp8266/debug.h:8:26: error: '::printf' has not been declared`
2019-12-03 22:15:03 -06:00
tablatronix 0fd0c33222 remove serial1 2019-11-29 20:06:41 -06:00
tablatronix 636027cabc rework #974
make compatible with params page
2019-11-29 20:04:31 -06:00
tablatronix 7882c0e9a9 fixes #975 2019-11-29 19:54:02 -06:00
tablatronix 9d6ce13b92 fix for #740 confusion 2019-11-29 19:29:56 -06:00
tablatronix 72bcbd8a80 fixes #974 password placeholder
showPassword()  optional
2019-11-29 18:32:10 -06:00
tablatronix 56ad40d083 Fixes #970 I broke constructor 2019-11-17 12:20:30 -06:00
tablatronix 22e35b2a03 #667 remove compile warning
Still not sure what the issue was here.
2019-11-14 00:37:41 -06:00
tablatronix f93d444966 remove otaflag probably not needed 2019-11-14 00:24:11 -06:00
tablatronix d90f6854e9 Update OnDemandConfigPortal.ino
adds ota to dev example suite
2019-11-13 23:11:05 -06:00
tablatronix a4993a8441 comments 2019-11-13 23:10:43 -06:00
tablatronix 768ead409e add support for build debug flags
WM_DEBUG_LEVEL
WM_DEBUG_PORT
closes #965
2019-11-13 22:47:55 -06:00
tablatronix fb29462e73 add heap frag logging to esp32 2019-11-13 09:12:23 -06:00
tablatronix 2447a3fd74 oops double debug titles 2019-11-12 22:56:46 -06:00
tablatronix e45bdb1831 Update WiFiManager.cpp
adds more heap debug debug_level DEBUG_MAX to enable
#961 #518
2019-11-12 22:54:45 -06:00
tablatronix a2355889ba fixes #956
Not tested, not sure if captive portal works with hidden ap, test please.
adds wm.setWiFiAPHidden(bool);
2019-10-30 08:55:24 -05:00
Shawn A 4014daeb71 Merge pull request #958 from LongLiveCHIEF/add-platformio-install-info
Add PlatformIO installation docs
2019-10-27 20:13:11 -05:00
Brian vanderbusch 7d7e228b9e Add PlatformIO installation docs 2019-10-27 15:06:44 -05:00
tablatronix 9a85b107fa spiffs erase #949 2019-09-26 13:56:48 -05:00
tablatronix 8190ec6077 Merge branch 'development' into ota 2019-09-25 12:43:49 -05:00
tablatronix 3771a79a55 dev example country and bounce 2019-09-13 11:28:05 -05:00
tablatronix 4d94476fa3 add string guards 2019-09-13 11:27:20 -05:00
tablatronix 5d9a51f671 adds country support for esp8266 #667 2019-09-13 11:27:05 -05:00
tablatronix e50d30cd5e uppercase default ap name
This should match the default in sdk now
2019-09-12 14:49:38 -05:00
tablatronix 6e1e698cf9 comments 2019-09-12 09:57:56 -05:00
tablatronix f06f4ea5dc adds async cache time _scancachetime adds async flag 2019-09-12 09:57:35 -05:00
tablatronix 646af21d30 changed dev example non delay 2019-09-12 09:56:55 -05:00
tablatronix 3f8f3eb1ad fixes #936, adds setWiFiAPChannel 2019-09-12 09:56:37 -05:00
tablatronix bd8320a45a fixes #935 disables password ofr open ap selects
Only works if htmk class l is not removed and html not changed, js will have to be updated if changed
2019-09-12 09:53:49 -05:00
tablatronix 58428ec1f8 fixup some calls
I think these should work, will have to test for empty strings and not actual info and fix
2019-09-11 12:22:31 -05:00
tablatronix 999da6d1a1 fixes #924 wifi info getters
gets ssid and psk with persistent param, needs testing
2019-09-11 12:00:09 -05:00
tablatronix 368ea928f0 arduino wont pickup this release
trying a different format
2019-09-09 08:46:45 -05:00
tablatronix 7acc77bcb1 fixing comments for disableipfields 2019-08-30 10:48:43 -05:00
tablatronix 2e7af253ab V0.15-beta
I think this works for library managers..
2019-08-30 09:44:20 -05:00
tablatronix d0e70fdd6b fixes #336 2019-08-30 09:36:44 -05:00
tablatronix 8f9edd18a6 fixes #708 2019-08-30 09:19:20 -05:00
tablatronix 89eb952d18 hotfix #576 2019-08-30 09:14:54 -05:00
Shawn A d1e395e78f Merge pull request #615 from xnorbi/master
Fixed: Waiting for connection result with time out issue
2019-08-30 09:02:19 -05:00
Shawn A 286e5d13d9 Merge pull request #772 from dontsovcmc/issuu_#644_utf-8_correct
separate charset UTF-8 and viewport meta
2019-08-30 09:01:09 -05:00
Shawn A ff26ed4e4c Merge branch 'master' into issuu_#644_utf-8_correct 2019-08-30 09:00:57 -05:00
Shawn A edce3fc84c Merge pull request #928 from d-a-v/head
hotfix: rename internal HTTP_HEAD to HTTP_HEADER
2019-08-30 08:52:52 -05:00
David Gauchard f26638e38b hotfix: rename internal HTTP_HEAD to HTTP_HEADER 2019-08-30 15:38:36 +02:00
tablatronix 1b8d870c22 add explicit mode to all examples
So people stop complaining when ap starts by default cause they dont know how esp works.
2019-08-14 13:40:19 -05:00
tablatronix 34d9a975b5 remove reeadme self reffeential link 2019-07-29 16:59:50 -05:00
tablatronix e2d7ae7533 ESP32 DEFINE LED_BUILTIN 2019-07-29 16:33:59 -05:00
tablatronix 41810a344a bump arduino 1.8.8, install boards esp32 2019-07-29 16:06:57 -05:00
tablatronix 6e1104efbf esp8266 build passing, work on esp32 2019-07-29 15:08:34 -05:00
tablatronix 422ce3e165 not sure how this all got changed 2019-07-29 14:13:39 -05:00
tablatronix 7f414f5224 dumb 2019-07-29 14:10:01 -05:00
tablatronix 5b997e0597 trying to fix travis again 2019-07-29 14:02:47 -05:00
tablatronix 6335512ded Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2019-07-29 13:49:17 -05:00
tablatronix 7446edf547 remove esp32 travis 2019-07-29 13:48:53 -05:00
tablatronix 4775b1df51 ok maybe not 2019-07-19 09:19:39 -05:00
tablatronix 8a8e363cc3 Can i just do esp32 boards install now ? 2019-07-19 08:23:21 -05:00
tablatronix b5218d1b93 fix travis compile on esp32 2019-07-19 08:04:46 -05:00
tablatronix e0e0150f78 why did they change every flag????? 2019-07-13 07:34:57 -05:00
tablatronix 5685e7d9b4 ugh boards is so whack 2019-07-13 07:21:19 -05:00
tablatronix 35a1ab2e8d remove crytalfreq 2019-07-13 07:18:23 -05:00
tablatronix 8483118860 all jacked up 2019-07-13 07:15:32 -05:00
tablatronix 49c6cec998 ugh wtf 2019-07-13 07:08:35 -05:00
tablatronix a1c53d785f travis fqbn updates
just removing bad ones for now, will fix later
2019-07-13 07:00:13 -05:00
tablatronix debb20e41b Revert "remove geenric from travis for now"
This reverts commit d20b85a7b8.
2019-07-13 06:56:20 -05:00
tablatronix d20b85a7b8 remove geenric from travis for now 2019-07-13 06:53:58 -05:00
Shawn A c3ff582374 Merge pull request #894 from mikdatdogru/patch-1
signal class value has been wrapped to int()
2019-06-03 11:38:29 -05:00
Shawn A cccc7c9ae6 Merge pull request #895 from mikdatdogru/patch-2
Update WiFiManager.template.html
2019-06-03 11:32:38 -05:00
Mikdat DOĞRU 318742e183 Update WiFiManager.template.html
parse.js parsing error fixed
2019-06-02 18:58:13 +03:00
Mikdat DOĞRU 7fbb941383 Update WiFiManager.cpp
i wrapped to int() function, because cannot match on css because the incoming data is decimal
2019-06-02 18:27:50 +03:00
tablatronix 4873c7c632 silence event debug 2019-02-26 21:37:57 -06:00
tablatronix f0441f65b7 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2019-02-26 21:36:27 -06:00
tablatronix ea1a09130f fix #771 again, I never set hasbegun to true!
should fix esp32 events not working, namely async scannetworks
2019-02-26 21:36:25 -06:00
tablatronix 8b685d6826 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2019-02-25 08:46:29 -06:00
tablatronix 621ac63154 Update .travis.yml 2019-02-25 08:46:10 -06:00
tablatronix d6cf147e5b fixing up travis, not sure why cpufreq is throwing errors or debug ? 2019-02-24 08:41:33 -06:00
tablatronix 30fd2b13a6 remove extra define init() 2019-02-24 08:30:57 -06:00
tablatronix 6131c2d38a update basic.ino 2019-02-24 08:29:20 -06:00
tablatronix bbc98a7e74 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2019-02-19 22:06:18 -06:00
tablatronix 9353fb01d3 added debugging log 2019-02-19 22:06:16 -06:00
Shawn A 8f6950d3eb Merge pull request #803 from sidey79/define-hardware
wifimanager.cpp / wifimanager.h
2019-02-14 11:52:42 -06:00
tablatronix 0865a36a5e fix for #782 2019-01-31 16:49:13 -06:00
tablatronix c6591ce7b9 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2019-01-26 18:07:24 -06:00
tablatronix 0e75b669b7 change var name 2019-01-20 10:11:24 -06:00
tablatronix 3717e323b9 adds password debugging 2019-01-10 15:37:12 -06:00
sidey79 1282c4d5b5 wifimanager.cpp / wifimanager.h
added define that checks on esp32 or esp8266. If another hardware is selectec, then do not try to compile this code.
2019-01-08 23:33:56 +01:00
tablatronix 862e2dbde2 stupid shit wont compile
other stuff says not in scope , makes no sense
2019-01-04 14:54:31 -06:00
tablatronix aaf2544c93 add sample oled support to DEV example 2019-01-04 14:50:38 -06:00
tablatronix e25277b20c make getRSSIQuality public 2019-01-04 09:37:07 -06:00
tablatronix 944450840a applies #772 to dev 2018-12-20 10:56:55 -06:00
tablatronix 540ee694fe Merge branch 'development' into ota 2018-12-20 10:47:11 -06:00
david gauchard 71f997b5c7 Merge branch 'master' of https://github.com/tzapu/WiFiManager into loop 2018-12-08 23:42:48 +01:00
doncov.eugene fd6bf74720 separate charset and viewport meta 2018-11-26 17:03:20 +03:00
tablatronix 65ad141008 Update WiFiManager.cpp
tentative fix for #771
2018-11-24 19:16:25 -06:00
tablatronix 4add3127d4 Update WiFiManager.cpp
tentative fix for #771
2018-11-24 19:12:33 -06:00
tablatronix 3e2f8ae9d8 fix update menu bug 2018-11-18 10:32:13 -06:00
tablatronix bbe984c93b sampe update 2018-11-13 16:49:43 -06:00
tablatronix cf1b1a93a6 remove width to make buttons back to small width 2018-11-13 16:36:21 -06:00
tablatronix 0ec7a58b7b add upload note 2018-11-13 16:35:26 -06:00
tablatronix 7da803389c add js to firmwaree upload
hide upload until selected, update return msg box
2018-11-09 16:43:54 -06:00
tablatronix 5a3829abf9 Merge branch 'development' into ota 2018-11-09 15:38:19 -06:00
tablatronix 6459e4fd4d add variable css to template 2018-11-09 15:37:27 -06:00
tablatronix df38c54a66 Merge branch 'development' into ota 2018-11-09 15:26:52 -06:00
tablatronix 65cb95585d more css consolodating 2018-11-09 15:25:56 -06:00
tablatronix 9d3cc69b56 rework css
shrink css, add file upload input styling
2018-11-09 15:16:19 -06:00
tablatronix 5dab5a4685 adds accept filter for ota .bin
#727
2018-11-09 14:20:35 -06:00
tablatronix 69e08e7871 add input accepttype 2018-11-09 14:19:30 -06:00
tablatronix c9af1b11a7 clean up some ota stuff disable renable timeouts 2018-11-08 14:11:56 -06:00
tablatronix cac71e368e update todo 2018-11-08 13:36:13 -06:00
tablatronix 2267f34fb5 fix wrong urls 2018-11-08 13:35:33 -06:00
Shawn A 205d30e958 Merge pull request #587 from sidey79/dev-ota-updater
WIP: Added OTA updater option from esp8266
2018-11-08 12:51:02 -06:00
Shawn A 7dc75eacde Merge branch 'ota' into dev-ota-updater 2018-11-08 12:50:14 -06:00
tablatronix 9a4c0f1580 hotfix #576 2018-11-08 12:20:01 -06:00
tablatronix ccfca4b663 adds customhtml input example 2018-11-06 12:04:18 -06:00
tablatronix 41214ad7eb Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-11-02 10:13:09 -05:00
tablatronix 501c824993 supports stopConfigPortal if blocking , flag abort 2018-11-02 10:13:07 -05:00
tablatronix 73f2a8c366 adds empty param constructor 2018-10-31 14:23:39 -05:00
tablatronix 38b6c878a2 chaange setCaptivePortalClientCheck to setAPClientCheck 2018-10-31 14:15:02 -05:00
tablatronix 370be061e4 adds custom param examples to advanced 2018-10-31 14:03:26 -05:00
tablatronix 2209f987b7 removed placeholder and added temlplace comments 2018-10-31 14:02:16 -05:00
tablatronix 7f0bd1e41f changed placeholder to label
deprecated getPlaceholder with getLabel
2018-10-31 13:47:05 -05:00
tablatronix 55577692fe add ntp time to dev example 2018-10-18 16:47:52 -05:00
tablatronix 2d021bbab8 adds nonblocking params example 2018-10-13 15:57:00 -05:00
tablatronix 256c889715 comments 2018-10-12 16:08:31 -05:00
tablatronix c3fd7d9622 #461 testing
adds new callback and moved webserver to public
2018-10-12 15:57:35 -05:00
tablatronix 3c280b12a8 moved apcallback after webserver is available 2018-10-12 15:16:59 -05:00
tablatronix 080f7751e0 moving apcallback after everything 2018-10-12 14:52:10 -05:00
tablatronix 1d0970a882 moving apcallback after sosftap()
apcallback used to only indicate that mode was softap, moved untikl after actually starting the ap, so it can be used to check status and get ip etc.
2018-10-12 14:10:16 -05:00
tablatronix bef46b9e72 adds setSaveParamsCallback
clean up examples
2018-10-11 15:23:48 -05:00
tablatronix 4f1196aa69 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-10-06 14:11:22 -05:00
tablatronix ea67dc22c0 remove resetsettings 2018-10-06 14:11:20 -05:00
tablatronix b091ee00d8 working on readme 2018-10-05 15:04:25 -05:00
tablatronix ec1d474d7b readme and comments 2018-10-05 14:29:11 -05:00
Shawn A 7d01b99e72 Merge pull request #378 from gmag11/resetConfigCallback
Add a callback when reset settings is triggered, changed to development branch
2018-10-05 09:21:36 -05:00
Shawn A 29bb8a7d22 Merge branch 'development' into resetConfigCallback 2018-10-05 09:21:14 -05:00
Shawn A b95cadbe9a Merge branch 'master' into resetConfigCallback 2018-10-05 08:43:26 -05:00
Shawn A e1e061e46a Merge pull request #734 from irwanayeah/development
add callback before save config wifi or params
2018-10-05 08:41:57 -05:00
Shawn A 686f7f74ee Merge pull request #718 from fllaca/get_parameters_method
Implements #717:  Added getParameters and getParametersCount methods.
2018-10-03 10:29:45 -05:00
tablatronix 669dad4206 starting readme updates 2018-10-01 12:28:37 -05:00
Shawn A 8e7b43a029 rename example 2018-09-27 13:39:12 -05:00
Shawn A fe772f6bf5 fix example 2018-09-26 09:47:59 -05:00
Shawn A 193fdf177c fix example 2018-09-26 09:45:03 -05:00
Shawn A 613ec354bd param defvalue mismatch checking 2018-09-26 09:44:59 -05:00
Shawn A 6dbc0017ba Merge pull request #743 from dontsovcmc/setValue
Set value
2018-09-26 10:28:33 -04:00
Shawn A 37e100672a Merge pull request #741 from dontsovcmc/waterius_development
WiFiManagerParameter init() to protected from private
2018-09-26 10:27:51 -04:00
Dontsov Evgeny 7d42423894 value limit is length 2018-09-24 04:19:21 +03:00
Dontsov Evgeny 85b2319b59 correct your idea about deflength 2018-09-24 03:45:49 +03:00
Dontsov Evgeny dbf91a4e8c example: custom paramaters with load/save settings 2018-09-24 03:28:03 +03:00
Dontsov Evgeny aad1a8d9d2 WiFiManagerParameter init() to protected 2018-09-23 23:19:17 +03:00
Shawn A c0f29a6fc3 Merge branch 'master' into hotfixes 2018-09-20 12:15:44 -05:00
Shawn A 34e1516524 charset utf-8 2018-09-20 12:15:02 -05:00
Shawn A 740005b21e Merge pull request #687 from dontsovcmc/utf-8
issuu #644 add utf-8 charset to head
2018-09-20 12:08:39 -05:00
Shawn A b42b2f23c2 Merge pull request #722 from rodri16/patch-2
Swapping enableAP and softAPConfig
2018-09-20 12:05:21 -05:00
Shawn A 0e4af48d54 fix example 2018-09-19 09:54:17 -05:00
Shawn A 9d00937f34 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-09-18 11:35:57 -05:00
Shawn A 0cd0b75d9e added custom html param example pattern 2018-09-18 11:35:55 -05:00
tablatronix c88df86313 syntax error in examples 2018-09-17 13:44:06 -05:00
Fernando Llaca 1c191c1d14 Rename "Old Examples" folder to "Old_Examples", to avoid errors when iterating examples folder. 2018-09-16 23:16:25 +02:00
Fernando Llaca 12fc6516d2 Missing semicolon 2018-09-16 22:57:01 +02:00
Fernando Llaca 448e079bc8 Use a especific version of ArduinoJson 2018-09-16 22:49:40 +02:00
Fernando Llaca b4cc27cb56 Added getParameters and getParametersCount methods.
Useful for iterating over WiFiManager parameter list
2018-09-16 21:34:24 +02:00
ayeah f9d1c9bd6f reformat 2018-09-17 01:19:18 +07:00
ayeah d9c27b98d4 add listener setPreSaveConfigCallback
this listener required for action before save process behind wifi or params.
2018-09-17 01:10:37 +07:00
Shawn A 4f0a87a0a5 adds esp32 core temp, not enabled
the core temp sensors are not calibrated in production atm, they are large offsets form chip to chip and are useful for relative temp swings only. Until the IDF comes up with a new temp sense, this is commented out.
2018-09-12 13:19:53 -05:00
Shawn A 9ce498c5b6 remove sleep mode 2018-09-12 10:55:04 -05:00
Shawn A 393e7e45df bug fixes #726 2018-09-12 09:56:20 -05:00
Shawn A 1e10ffa49a reworkgin examples 2018-09-07 16:16:44 -05:00
Shawn A 2610dcb2c5 change simple to basic clean up 2018-09-07 15:52:52 -05:00
Shawn A ed80635e32 non blocking examples 2018-09-07 15:43:43 -05:00
Shawn A c52186079a stopconfigportal public 2018-09-07 15:43:21 -05:00
Shawn A 7f12e202d4 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-09-07 14:53:11 -05:00
Shawn A 97e7d30c66 esp8266 2.3.0 compatability restored #576
asyncscannetworks not available in esp8266 2.3.0, adjusted server on to take cstr for backwards compatability
2018-09-07 14:53:08 -05:00
Shawn A 04552e40d8 some testing 2018-09-07 14:51:27 -05:00
tablatronix 0d8b96ebf3 update docblock to reflect setConfigPortalBlocking ignored configportaltimeout 2018-09-06 20:45:38 -05:00
Rodrigo Jose Carbajales 5827c2f8cb Swapping enableAP and softAPConfig
Swapping enableAP and softAPConfig for static IP STA
2018-09-06 12:11:38 +02:00
Shawn A 8871bdd311 logging 2018-09-04 16:39:16 -05:00
Shawn A 338544bc6a do savecallback on parmsave fo rnow #714 2018-09-04 16:39:00 -05:00
Shawn A 43051f9f51 fix 2018-09-04 16:37:14 -05:00
Shawn A 7ab5f6d5b2 clear wifi strings 2018-09-04 16:36:58 -05:00
Shawn A 3a0723cf66 skip connect if wifi empty 2018-09-04 16:36:47 -05:00
Shawn A 103c37d71f Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-09-04 08:14:12 -05:00
Shawn A 42241d6e36 fix nvs erase log 2018-09-04 08:13:30 -05:00
tablatronix b17c328f0f more debugging 2018-09-03 17:19:25 -05:00
tablatronix c1f018ca7c tentative fix for #720 2018-09-03 08:49:13 -05:00
Shawn A d6e091f587 test fix #702 2018-08-29 12:06:55 -05:00
Shawn A 8b579bb8a7 debug 2018-08-29 11:22:05 -05:00
Shawn A b2f6ff4a1f formatting 2018-08-29 10:39:28 -05:00
Shawn A 805072c4c4 adds checkboxes 2018-08-29 10:37:28 -05:00
Shawn A 247aecb2fc update requirements esp8266 2.4.0 2018-08-28 09:00:24 -05:00
Shawn A c78b76ba2e scan timing debugging 2018-08-27 12:30:28 -05:00
Shawn A 85d7f2a549 esp32 fix event cb to std::bind, adds async preload
esp32 does not have scan cb, must use event system and oncomplete to get scan count
2018-08-27 12:17:37 -05:00
Shawn A 16c37e5389 remove npt example, not esp32 compat 2018-08-27 12:16:14 -05:00
tablatronix b963e7f95a fix esp32 fatal, disabled async 2018-08-25 14:55:51 -05:00
tablatronix 1bf3fc04ea fixes #707 2018-08-24 13:37:15 -05:00
tablatronix 4f5e21647f fix res error 2018-08-24 13:02:34 -05:00
tablatronix f2bbb5f4e2 comments 2018-08-24 12:21:20 -05:00
tablatronix 34b7d1ea03 scan preload async
This changes the preload wifiscan to async and adds async support for wifi scans. preload async occursd on cp stsart and root loads(throttled)
2018-08-24 12:19:26 -05:00
tablatronix 28cf8eed16 adding async scannetworks 2018-08-23 16:46:17 -05:00
tablatronix 51432d0ef7 remove tests from example 2018-08-23 15:04:31 -05:00
tablatronix c651ab4b62 cleanup 2018-08-23 13:46:13 -05:00
tablatronix 3123eac5c8 typo 2018-08-23 13:36:08 -05:00
tablatronix 8f03b5df10 testing sta ap modes 2018-08-23 13:35:07 -05:00
tablatronix 2911bb33ee status debug 2018-08-23 13:04:18 -05:00
tablatronix 2074d85da7 cleanconnect 2018-08-23 12:54:48 -05:00
tablatronix 593eda9b87 oops again 2018-08-23 12:16:01 -05:00
tablatronix 3579733f5c refix #702 2018-08-23 12:09:46 -05:00
tablatronix 6d4c971b49 test for #702 2018-08-23 11:55:31 -05:00
tablatronix 1b8ce61522 well shit 2018-08-17 19:38:53 -05:00
tablatronix f1a1f44a08 #700 2018-08-15 19:11:53 -05:00
tablatronix 915023ccb9 fixes #619 unconfirmed needed 2018-08-10 13:49:15 -05:00
tablatronix 792ed84f4b debugging 2018-08-10 11:51:31 -05:00
tablatronix 5ee1ae78c0 fix callback order 2018-08-10 11:45:25 -05:00
tablatronix 4cceb95a42 debugging 2018-08-10 11:42:09 -05:00
tablatronix c6027058c9 added some debugging and testing 2018-08-09 15:21:12 -05:00
david gauchard 493a73c205 Merge branch 'master' of https://github.com/tzapu/WiFiManager into loop 2018-08-08 23:04:30 +02:00
tablatronix e9c4cdb2c6 disable setvalue on customhtml params 2018-08-07 14:06:31 -05:00
tablatronix 768a965810 remove custom ip from example 2018-08-07 13:57:10 -05:00
tablatronix c6ecad1b3a fixes #678 2018-08-07 13:55:45 -05:00
tablatronix 5a5f1c631b fix warning 2018-08-07 13:55:14 -05:00
tablatronix 573f8113ef fixes #691 2018-08-07 12:48:00 -05:00
tablatronix 440f312575 v 0.14 2018-08-05 11:06:15 -05:00
tablatronix dd7a686181 Merge branch 'hotfixes' 2018-08-05 11:05:56 -05:00
tablatronix 6a139688f3 ver .13 2018-08-05 11:03:39 -05:00
tablatronix b855c0a440 updating library managers 2018-08-05 10:48:23 -05:00
dontsovcmc 02de95c529 issuu #644 add utf-8 charset to head 2018-08-04 20:29:55 +03:00
Shawn A e18bc49a2a Wrong case 2018-07-23 07:06:22 -05:00
tablatronix 704a7ae393 hotfix WPS NO_EXTRA_4K_HEAP 2018-07-22 10:47:33 -05:00
tablatronix 2c41af00f5 fixes #671 2018-07-22 10:41:50 -05:00
Shawn A afbad01ee1 dev test sketch 2018-07-20 16:32:43 -05:00
Shawn A cba606b846 password invalid better error msg 2018-07-20 16:23:38 -05:00
Shawn A 8d5e9e3977 esp32 autoconnect is deprecated
https://github.com/espressif/esp-idf/issues/1960
2018-07-20 16:16:08 -05:00
Shawn A 24de319c7e issues with captive portals and preloadscan hammering 2018-07-19 16:54:38 -05:00
Shawn A ad623cb586 oops 2018-07-19 16:03:14 -05:00
Shawn A f2f0aabe3e dark theme tweaks 2018-07-19 14:02:02 -05:00
Shawn A 37cdda33c7 adds setClass(invert) black theme
adds class string to body, invert(black) is built in
` wm.setClass("invert");`
2018-07-19 13:10:37 -05:00
Shawn A c9ca210803 removing US default 2018-07-19 11:33:38 -05:00
Shawn A 2db93d28c7 clean up 2018-07-19 10:05:25 -05:00
Shawn A d140ccff84 adds setCountry, default US
accepts US JP CN, codes must be added to strings and WiFiSetCountry atm
2018-07-19 10:02:53 -05:00
Shawn A a51298ea54 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-07-19 08:40:48 -05:00
Shawn A f1fd553ac6 fix autoreconnect, forgot we use event for other stuff 2018-07-19 08:40:46 -05:00
Shawn A caa32c4bc2 Merge pull request #666 from 0x1abin/path-1
compat MacOS newline
2018-07-19 07:30:58 -05:00
0x1abin 0e6ed38986 compat macos newline 2018-07-19 14:36:18 +08:00
tablatronix a39b96be9c disable autoreconect esp32 2018-07-18 16:25:53 -05:00
tablatronix 713bf957c3 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-07-18 14:01:48 -05:00
tablatronix 74ceba7409 add non blocking example 2018-07-18 14:01:45 -05:00
Shawn A 08bb2322aa Oops 2018-07-16 17:07:31 -05:00
Shawn A 9ab4deaf5b clean up param length
Just changing to not modify argument, spacing
2018-07-16 08:06:03 -05:00
Shawn A 36ad6f80c4 Merge pull request #660 from liebman/do_param_save
Fix crasahes in doParamSave() &  WiFiManagerParameter::setValue
2018-07-16 07:55:39 -05:00
Christopher Liebman 2fac07cbf0 WiFiManagerParameter::setValue used length of default value for i
allocation and not passed length. Changed to use passed length or
length of default value if > passed length.
2018-07-15 14:39:11 -07:00
Christopher Liebman 85dd747949 Use hasParam() instead of checking server.arg() for NULL, it returns a String anyway.
Don't use .c_str() when its being assigned to a String anyway
2018-07-15 10:44:06 -07:00
Shawn A 32495668d8 Update ISSUE_TEMPLATE.md 2018-07-14 16:46:07 -05:00
tablatronix fc84e7a260 trying to fix param issues when param is out of scope
Ideally this should be done entirely different so params can follow wm scope and object lifetime..
2018-07-13 23:52:36 -05:00
tablatronix 933f86720a param was using user length for strncpy, causing overflows 2018-07-13 23:43:07 -05:00
tablatronix abbc110656 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-07-13 18:41:16 -05:00
tablatronix 17f2316ea8 fixes #655 2018-07-13 18:41:14 -05:00
tablatronix 24d317b9da fix #655 2018-07-13 18:27:50 -05:00
Shawn A 40d522d8b6 Merge pull request #649 from vincentVDB/patch-1
Update AutoConnectWithFSParameters.ino
2018-07-09 20:37:52 -05:00
vincentVDB 0f2ba754e2 Update AutoConnectWithFSParameters.ino
Close file !
2018-07-10 02:11:06 +02:00
Shawn A f65972aa55 Merge pull request #647 from liebman/fix_bad_progmem_access
fix bad progmem access
2018-07-08 11:02:49 -05:00
Chris Liebman e235a45d5a value is PROGMEM too.... 2018-07-08 08:32:41 -07:00
Christopher Liebman aeba5478ee fix bad progmem access introduced in https://github.com/tzapu/WiFiManager/pull/608 2018-07-08 07:14:11 -07:00
tablatronix b9f6b472a7 #645 comments 2018-07-07 09:45:24 -05:00
Shawn A b9fcc8fe22 Merge pull request #645 from liebman/only_support_wps_if_no_extra_4k_heap_defined
disable wps by default, enable if its enabled in core
2018-07-07 09:37:28 -05:00
Christopher Liebman 5a06f29c5b In https://github.com/esp8266/Arduino/pull/4889 the core was modified to
disable WPS by default.  Its only enabled if NO_EXTRA_4K_HEAP is defined.
To enable you must re-run the board manager with --noextra4kheap.
This addes #ifdef NO_EXTRA_4K_HEAP arround WPS usage so it won't generate
compiler errors.
2018-07-07 06:26:36 -07:00
tablatronix 4fdefaf67d example work 2018-07-02 10:10:09 -05:00
tablatronix 3a9d70f581 fix example 2018-06-30 13:42:33 -05:00
tablatronix 906a9d89cb advanced example testing 2018-06-29 16:52:20 -05:00
Shawn A c0187a60e1 fix esp32 usermode 2018-06-28 12:54:49 -05:00
Shawn A 0ab6f57239 fix esp32 resetsettings 2018-06-28 12:53:48 -05:00
Shawn A 9917f619b3 reworking examples 2018-06-28 12:53:36 -05:00
Shawn A 8f2791f908 fix esp32 fatal 2018-06-28 11:53:48 -05:00
Shawn A 6d92ae5a1f fixup examples 2018-06-28 11:52:50 -05:00
Shawn A 8d7da2fd8b FIx esp32 updates
Webserver now builtin to esp32 lib, esp32 persistent still not implemented properly, fixes erase again, fixes save again
2018-06-27 16:19:12 -05:00
Shawn A 94115006f6 Merge pull request #571 from liebman/remove_esp32_skiping_examples
enable all example builds for esp32
2018-06-19 12:51:05 -05:00
Shawn A 00b14d5d1c Merge pull request #608 from ohadcn/patch-1
add CORS headers
2018-06-19 12:46:45 -05:00
Shawn A bff3d75f91 Merge pull request #584 from cmarrin/development
Changed setAPCallback and setSaveConfigCallback to take std::function…
2018-06-19 11:35:18 -05:00
Shawn A e3d91a03ff add esp32 persistent test support
persistent support was added via a PR, but not very well, it is buggy.
2018-06-18 15:28:32 -05:00
Shawn A b3e19041ff fix esp32 erase w persistent 2018-06-18 15:27:47 -05:00
Shawn A 10088c71f3 Move all wifi functions out of constructor
Cannot use wifi in constructor on esp32, as it is not available yet,
2018-06-18 15:27:18 -05:00
Shawn A 01a5646317 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-06-18 11:40:05 -05:00
Shawn A 5066b86102 fix esp32 new bugs
esp32 only uses persistent on wifiLowLevelInit
        if(!persistent){
          esp_wifi_set_storage(WIFI_STORAGE_RAM);
        }
which only gets applied during certain functions, namely changing modes, or turning on wifi
2018-06-18 11:40:01 -05:00
Norbert f1e657e2b8 Fixed Waiting for connection result with time out issue 2018-06-04 13:51:29 +02:00
ohad 7f6039a6b7 Merge pull request #1 from ohadcn/patch-2
add CORS headers
2018-05-14 11:50:31 +03:00
ohad 24a25fc687 add CORS headers
this will allow external portal on the network to send credentials via browser.
2018-05-14 11:47:26 +03:00
ohad 128214a159 add CORS headers
this will allow external portal on the network to send credentials via browser.
2018-05-14 11:47:13 +03:00
tablatronix 718a8c8f4c fixing up setmenu docblocks 2018-04-26 20:46:00 -05:00
tablatronix 3c8af53440 comments, debugging 2018-04-25 11:12:12 -05:00
tablatronix 042640924f fix menu output
removed test menu output, removed ref , not sure why I put that there....
2018-04-19 19:01:50 -05:00
sidey79 428c9fcbd5 Updated for ESP32 - compile only tested 2018-04-13 21:51:36 +02:00
sidey79 9e265b44b5 Merge remote-tracking branch 'remotes/origin/development' into dev-ota-updater 2018-04-13 20:53:46 +02:00
sidey79 fe17307e09 Updated include for ota update lib for esp32 2018-04-11 22:11:44 +02:00
sidey79 3fafb3304a HTML Pages and generation for OAT Update adapted to current version of lib
Debug output corrected at some point
2018-04-10 23:07:56 +02:00
tablatronix f8ae461bfd fix savetimeout, too short, made optional 2018-04-09 19:48:31 -05:00
tablatronix d27fa7df61 hotfixing #425
this is a hotfix, there are numerous issues with this, development branch already addressed all of them.
2018-04-09 19:16:12 -05:00
sidey79 16bc717ceb Include Update.h for ESP32 2018-04-09 23:44:27 +02:00
sidey79 8065a1eaa4 Added OTA updater option from esp8266. Code is manly taken from KoljaWindeler but modified in some pieces to fit current library version 2018-04-09 23:08:43 +02:00
Chris Marrin 174bb615e6 Changed setAPCallback and setSaveConfigCallback to take std::function params
This allows Predicates and Lambdas to be passed. Still allows bare function pointers
so this patch is fully backward compatible. Tested on WiFiManager examples for
backward compatibility and on my own project (OfficeClock) for handling lambdas with
captured variables
2018-04-07 09:13:48 -07:00
Shawn A 82309e7a84 comment 2018-04-05 12:38:34 -05:00
Shawn A b682d8996b Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-04-05 12:34:56 -05:00
Shawn A c5b3637350 fixes #581
adds htmlentities to ssid outputs, limited replacements for now
2018-04-05 12:34:27 -05:00
Shawn A 5b3ac4236e fix some error logging 2018-04-05 12:29:42 -05:00
Shawn A 87c2eb42b6 fixup scnanetworks 2018-04-05 12:29:11 -05:00
Shawn A 10f17d0472 workaround for esp32 webserver parsearguments bug 2018-04-05 12:19:46 -05:00
tablatronix 7ec3b99020 clean up defines, removed stuff for memory 2018-03-31 12:42:06 -05:00
tablatronix 49104d4bbb adds chip revision efuse
not sure what use this is, as getChipRevision is usually the same anyway... shrug
2018-03-31 12:41:47 -05:00
Shawn A 41b29fa08c fix erroneous error debug 2018-03-28 09:38:07 -05:00
Shawn A ef70b49e98 fix nvs erase 2018-03-28 08:27:57 -05:00
Shawn A 4a6631511b fix handleerase add softapconfig catch fail 2018-03-28 08:23:04 -05:00
Shawn A a7b992450f Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-03-28 08:14:10 -05:00
Shawn A 10db048d61 getmodestr, handleerase(bool) 2018-03-28 08:13:53 -05:00
Shawn A 3ae0b40ad9 Merge pull request #575 from liebman/allow_disable_portal
allow automatic config portal to be disabled
2018-03-28 08:10:45 -05:00
Christopher Liebman 7495fe2999 add setEnableConfigPortal(boolean enable) - if false dont open condig portal from autoConnect() 2018-03-24 18:29:30 -07:00
Shawn A c9a7112cbb fix parenths #573 2018-03-21 13:46:53 -05:00
Shawn A 32ccac5936 ugh remove test example 2018-03-21 13:32:50 -05:00
Shawn A 32d6f11217 fixes #573 2018-03-21 13:30:53 -05:00
Christopher Liebman 13cd054c15 Merge branch 'master' into remove_esp32_skiping_examples 2018-03-21 10:31:55 -07:00
Shawn A c2cbe3015b refactor connectwifi, adds save timeout
wifi save now no longer uses settimeout timeout
2018-03-21 12:18:00 -05:00
Christopher Liebman 4e71d53c54 Merge branch 'development' into remove_esp32_skiping_examples 2018-03-21 09:13:16 -07:00
Shawn A 02c531a247 spiffs case 2018-03-21 11:05:05 -05:00
Christopher Liebman 6270630d1a enable all example builds for esp32 2018-03-21 07:18:31 -07:00
Shawn A 7279333a17 fix fsparam spiffs examples for esp32 2018-03-21 08:02:15 -05:00
Shawn A 6319955cdc Merge pull request #570 from liebman/fix_travis
Fix travis builds, add esp32 builds
2018-03-20 17:36:34 -05:00
Christopher Liebman 14cd0d563a Merge branch 'development' into fix_travis 2018-03-20 15:36:01 -07:00
Shawn A fd3f5bbb2d Delete OnDemandConfigPortal.ino.cpp
Sigh
2018-03-20 17:30:12 -05:00
Christopher Liebman 9e3061201e Merge branch 'development' into fix_travis 2018-03-20 15:19:40 -07:00
Christopher Liebman 208ae5c7ea Merge branch 'development' into fix_travis 2018-03-20 14:51:41 -07:00
Chris Liebman 56d3e6d737 make travis build again 2018-03-20 13:47:28 -07:00
Chris Liebman 5eea21afa9 add esp32 2018-03-20 13:17:09 -07:00
Chris Liebman e4605775a2 add esp32 2018-03-20 13:09:01 -07:00
Chris Liebman 9e5c1b5fe2 add esp32 2018-03-20 12:55:44 -07:00
Chris Liebman 3891c0a631 add esp32 2018-03-20 12:48:41 -07:00
Chris Liebman fe8f38aa59 add esp32 2018-03-20 12:07:35 -07:00
Shawn A 851a38e7fa ugh 2018-03-20 13:27:50 -05:00
Shawn A 7f6bd107e6 fix debug levels 2018-03-20 13:22:43 -05:00
Chris Liebman 28ed839274 add esp32 2018-03-20 11:16:58 -07:00
Chris Liebman c358378a27 add esp32 2018-03-20 11:16:49 -07:00
Shawn A d090dd3dd7 move menutokens 2018-03-20 13:14:50 -05:00
Chris Liebman 10d6deadc2 add esp32 2018-03-20 10:51:55 -07:00
Chris Liebman 19d578e04b add esp32 2018-03-20 10:43:22 -07:00
Shawn A 881f50fb7e fix compiler warnings 2018-03-20 12:35:01 -05:00
Shawn A 57fc15a20a fix section compile error 2018-03-20 12:31:49 -05:00
Shawn A 941865ec85 datatype fixes 2018-03-20 12:24:28 -05:00
Chris Liebman 6f84964894 fixing travis 2018-03-20 10:16:08 -07:00
Shawn A 88d2cfbff4 change varnames 2018-03-20 12:05:46 -05:00
Chris Liebman 839a421ff1 travis testing 2018-03-20 10:03:54 -07:00
Shawn A 7a57a1395d change setmenu to take vector or array of strnig tokens 2018-03-20 12:00:59 -05:00
Chris Liebman 31d53b18be travis testing 2018-03-20 09:58:34 -07:00
Shawn A 8d4f745abf Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-03-19 12:47:57 -05:00
Shawn A e970686064 fix debug blank 2018-03-19 12:47:56 -05:00
David Gauchard 159674bbba allow user loop while in AP mode 2018-03-17 19:05:11 +01:00
tablatronix 7ad6470adf oops 2018-03-17 10:45:48 -05:00
tablatronix de85162267 add bug workaround for esp8266 softap 2018-03-17 10:11:03 -05:00
tablatronix 8ddc86f470 adds handleClose 2018-03-17 10:10:46 -05:00
Shawn A c9e82ae920 menuids as vector to deal with size
This kind of makes it a pain in the ass for users, not sure how to make this easier, I can take in an array of string ids, with a count arg, makes it easier, but then users can pass nonsense in, this way its enum ids, but damn it sure is convoluted. Welcome to ideas here...

```c++
  std::vector<WiFiManager::menu_page_t> menu = {wm.MENU_WIFI,wm.MENU_INFO,wm.MENU_PARAM,wm.MENU_CLOSE,wm.MENU_SEP,wm.MENU_ERASE,wm.MENU_EXIT};
  wm.setMenu(menu);
```
2018-03-16 15:55:53 -05:00
Shawn A 0741dbde2e debug remove 2018-03-16 14:19:16 -05:00
Shawn A e3b7dc2641 kludge setmenu with size so it works
Prboably going to add a vector for this, I do not want to add the overhead of std::array for something optional
2018-03-16 14:18:48 -05:00
Shawn A d07f73263a showinfoerase toggle 2018-03-16 14:17:58 -05:00
Shawn A f60a1d1b06 adds section hrs 2018-03-16 10:56:28 -05:00
Shawn A 424f48f0a8 add setShowDnsFields, adds edge case force hide ip fields 2018-03-16 10:56:12 -05:00
Shawn A 03a40915ee minor layout fix to config 2018-03-15 16:34:37 -05:00
Shawn A b7d230cc40 remove testing 2018-03-15 16:15:38 -05:00
Shawn A 8cbd0fa54e oops 2018-03-15 16:08:48 -05:00
Shawn A 0749e1bdd7 Update README.md 2018-03-15 16:05:02 -05:00
Shawn A 655db109c1 comments 2018-03-15 15:51:47 -05:00
Shawn A 109dfa5c58 Merge pull request #561 from tzapu/pr560
Added Custom DNS, fix newlines
2018-03-15 15:41:07 -05:00
Shawn A 3cc1fabae7 fix tabs 2018-03-15 15:40:34 -05:00
Deb 81045e6433 Added Custom DNS, fix newlines 2018-03-15 15:29:34 -05:00
Shawn A 84752d8027 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-03-15 13:50:18 -05:00
Shawn A 36840fc712 add WM_RTC def for rtc.h 2018-03-15 13:50:17 -05:00
Shawn A 3378a4a846 Update README.md 2018-03-15 10:37:59 -05:00
Shawn A 21f1016d89 add esp shields 2018-03-15 10:36:26 -05:00
Shawn A 4f86945d7e Update ISSUE_TEMPLATE.md 2018-03-15 07:44:26 -05:00
Shawn A 278c320e22 added debug levels 2018-03-14 17:00:46 -05:00
Shawn A 29edaed0e7 fixes #555 oops 2018-03-14 12:59:51 -05:00
Shawn A 32e51ea37b notes 2018-03-14 12:52:50 -05:00
Shawn A 9346cee76c fix autoreconnect on auth failure 2018-03-14 10:46:08 -05:00
Shawn A 19d6101a1b fix up connection result for ondemand portal 2018-03-14 10:45:50 -05:00
Shawn A 68201cd965 remove serial.prints 2018-03-14 10:06:44 -05:00
tablatronix 1fade32d66 disable ssid input autoformatting
autocorrect='off' autocapitalize='none'
2018-03-08 22:36:14 -06:00
Shawn A 158dac1e68 fixes #551 2018-03-08 14:06:39 -06:00
Shawn A 721bb417bf remove debug 2018-03-07 15:41:47 -06:00
Shawn A 0c5e005866 fix customhtml parameters 2018-03-07 15:40:21 -06:00
Shawn A 0a1bd9f934 init params as null
I started gettting odd exceptions, so I thought this should be null and not on the stack or pointing to garbage. I might be totally in the wrong here.
2018-03-07 13:59:50 -06:00
Shawn A 5e487d6edc remove preallocation of params memory 2018-03-06 16:42:54 -06:00
Shawn A 1f9a13a42e oops fix constructor again 2018-03-06 16:14:13 -06:00
Shawn A 3796af5930 move routes to strings 2018-03-06 16:07:29 -06:00
Shawn A 8af108262c fix constructor 2018-03-06 16:07:18 -06:00
tablatronix b63e8b575b fixup #548 2018-03-05 22:01:47 -06:00
tablatronix a17fabd7fe Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-03-05 20:12:49 -06:00
tablatronix 5a34002d5d fix savecallback #543 2018-03-05 20:12:47 -06:00
Shawn A 6295d128aa adds opt erase flag 2018-03-05 16:35:26 -06:00
Shawn A 724447a654 oops 2018-03-05 16:26:59 -06:00
Shawn A 9f6cc23beb adds nvs erase
// #define WM_ERASE_NVS // esp32 erase() will erase NVS
2018-03-05 16:17:49 -06:00
Shawn A 6e1b2ed32c remove dnsserver from readme 2018-03-05 14:04:41 -06:00
Shawn A 8a17ef9c03 add debugging 2018-03-05 14:03:33 -06:00
Shawn A 3de9a34e3b Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-03-05 12:58:33 -06:00
Shawn A 4db3eca51e adds erase 2018-03-05 12:58:30 -06:00
tablatronix ca5609d8e6 oops #546 2018-03-03 10:42:25 -06:00
tablatronix 53df6ac612 #546 fix?
Since I do not know how to fix the delegated constructors properly, this should fix the issue for now
2018-03-03 10:33:04 -06:00
Shawn A 108af72d5f Update ISSUE_TEMPLATE.md 2018-03-02 12:42:20 -06:00
Shawn A 5ae132a7e9 #542 handler 2018-03-01 13:19:40 -06:00
Shawn A 5a6a365f0a Update CONTRIBUTING.md 2018-02-26 22:11:43 -06:00
Shawn A 92debb4bf8 comments 2018-02-24 10:45:58 -06:00
Shawn A ea9134afd2 fix webserver pointer 2018-02-24 09:13:20 -06:00
Shawn A bce3607504 add preloadscan enable 2018-02-24 08:54:40 -06:00
Shawn A 051966c856 fix order 2018-02-24 08:41:25 -06:00
Shawn A d0ed01433d add wifiscan preloading with cache
This uses core scan object and assumes its lifetime, I am not sure what the scope is or how long it lives, will have to convert to local copy if its being lost, caching for 60s after startweb portal and 10s after root load, refresh bypasses cache
2018-02-24 08:40:01 -06:00
Shawn A 7b4fd38b6b fix menuids 2018-02-24 07:51:07 -06:00
Shawn A 58d23513a1 comments 2018-02-23 23:57:12 -06:00
Shawn A 39da3e6d6c simplify debug 2018-02-23 23:49:23 -06:00
Shawn A 6749122eed change defs 2018-02-23 23:44:36 -06:00
Shawn A f210000c94 adds mdns support 2018-02-23 23:28:19 -06:00
Shawn A 327db84d18 fix resetsettings 2018-02-23 13:14:55 -06:00
Shawn A ff636abea8 fix menu and param save 2018-02-23 12:38:34 -06:00
Shawn A 951b39b088 fix param crash 2018-02-23 11:19:19 -06:00
Shawn A 6ba4a2523c fix up menus 2018-02-23 10:02:09 -06:00
Shawn A dfd48c2c81 add param help 2018-02-22 13:04:55 -06:00
Shawn A 3eb8d39565 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-02-22 08:54:17 -06:00
Shawn A ae95ca2c7b fix template 2018-02-22 08:54:12 -06:00
Shawn A edbaf5acdd finish up menu customization 2018-02-21 20:52:24 -06:00
Shawn A 7c4963fac2 fix bug 2018-02-21 20:12:54 -06:00
Shawn A c2bdbfafb9 adding menu control, in progress 2018-02-21 17:11:57 -06:00
Shawn A 4e57d74e87 fix some minor warnings 2018-02-21 10:52:55 -06:00
Shawn A 5e27194204 Merge branch 'master' into development 2018-02-21 08:41:22 -06:00
Shawn A b516085a3d Merge pull request #536 from d-a-v/warn
remove warning
2018-02-21 08:35:22 -06:00
David Gauchard f333f271e4 remove warning 2018-02-21 12:10:19 +01:00
Shawn A 35bf4a94bd change webserver pointer to using 2018-02-20 12:59:37 -06:00
Shawn A e01101eff1 #534 2018-02-20 11:54:14 -06:00
Shawn A 39f20a6adc #528 WL_DISCONNECTED support for testing 2018-02-20 11:13:46 -06:00
Shawn A 3d7074166c #528
using a static var for esp32 event for now to get this working and test. Probably not the best, not sure what the best option is here for esp32 onevent static member function callbacks
2018-02-20 08:49:54 -06:00
Shawn A 415f98d9fb debuggin esp32 auth fail events 2018-02-19 21:32:17 -06:00
Shawn A e5edf536a5 template update 2018-02-19 14:03:52 -06:00
Shawn A f9a8f5bdab allow empty ssids, bail earlier 2018-02-19 13:32:12 -06:00
Shawn A 64075bc7f9 feature #533 failure details 2018-02-19 13:31:43 -06:00
Shawn A 9eec7f97dd change some uneeded ints 2018-02-19 10:46:55 -06:00
Shawn A 0c6d4df7a7 remove debugging 2018-02-19 10:33:19 -06:00
Shawn A aaad9ca4c3 add result checking #527 2018-02-19 10:32:34 -06:00
Shawn A 7a5a72eed4 remove debugging 2018-02-19 10:12:25 -06:00
Shawn A 89cfdfc67f clean up 2018-02-19 10:04:40 -06:00
Shawn A 374e9f515f stability #527 2018-02-19 09:52:52 -06:00
Shawn A 9d16a68665 doc blocks, reformatting code 2018-02-19 08:37:12 -06:00
Shawn A ea994d5ccd adds getWiFiIsSaved() 2018-02-19 08:21:22 -06:00
Shawn A 97398d7ce2 fix #527 for esp8266 2018-02-18 20:23:04 -06:00
Shawn A 9f4156437b fixes #527 2018-02-18 20:15:55 -06:00
Shawn A cb7cbec1f8 testing #527 2018-02-18 12:27:20 -06:00
Shawn A f3db838ae1 fix info page and adds esp32 aphostname 2018-02-18 10:39:35 -06:00
Shawn A 1d6a7275e7 gitignore
no gitignore? add more stuff
2018-02-18 10:24:03 -06:00
Shawn A 1ee8f5a1a9 #528 adds getLastConxResult 2018-02-18 09:43:52 -06:00
Shawn A 076a355098 Merge pull request #515 from horendus/patch-1
Move more strings to FLASH to free up RAM
2018-02-15 18:15:28 -06:00
Shawn A 14c5169ac9 bugged 2018-02-15 16:59:16 -06:00
Shawn A b09cc31416 oops broke lock icons 2018-02-15 13:11:36 -06:00
Shawn A 41b4717148 more strings progmem 2018-02-15 12:23:20 -06:00
Shawn A d8d26b26c2 change wifiscan detaisl to css for toggling 2018-02-15 10:44:19 -06:00
Shawn A 98c78a2929 documenting source 2018-02-15 09:57:51 -06:00
Shawn A d86351dff4 Update ISSUE_TEMPLATE.md 2018-02-15 09:04:21 -06:00
Shawn A e9cf051cb2 Update ISSUE_TEMPLATE.md 2018-02-15 09:03:50 -06:00
Shawn A 08ae001a83 missed one file header 2018-02-15 08:37:14 -06:00
Shawn A b49849f8c0 file headers 2018-02-15 08:36:21 -06:00
Shawn A 603f2b5631 Merge pull request #490 from tzapu/esp32
Esp32 preliminary support
2018-02-15 08:06:47 -06:00
Shawn A 55b336e6d8 Merge branch 'development' into esp32 2018-02-15 07:49:24 -06:00
Shawn A 625c8e2f9e Merge branch 'esp32' of https://github.com/tzapu/WiFiManager into esp32 2018-02-15 07:48:15 -06:00
Shawn A 26ba373009 move authmode to progmem 2018-02-15 07:48:13 -06:00
Shawn A 8c1e070582 strings 2018-02-14 23:14:01 -06:00
Shawn A 3e66273c3e esp32 strings progmem 2018-02-14 23:08:59 -06:00
Shawn A 9da297f405 moved _wifissidprefix to progmem 2018-02-14 23:03:14 -06:00
Shawn A 18cb6af0e4 dup define 2018-02-14 22:43:55 -06:00
Shawn A a6dc373f5c typo 2018-02-14 22:41:06 -06:00
Shawn A 25b880cf9b comments 2018-02-14 22:39:56 -06:00
Shawn A 5730ce351a left in debug 2018-02-14 22:36:36 -06:00
Shawn A 62f5ce6e0c more string cleanup 2018-02-14 16:42:10 -06:00
Shawn A 91383f9bc1 refix memsketch 2018-02-14 16:03:09 -06:00
Shawn A ca3a726e88 Merge branch 'development' into esp32
Merge branch 'development' into esp32

# Conflicts:
#	WiFiManager.cpp
#	WiFiManager.h
#	strings_en.h
2018-02-14 15:55:29 -06:00
Shawn A 43a035091e more strings cleanup 2018-02-14 14:11:19 -06:00
Shawn A d98a59cca3 editing strings 2018-02-14 14:09:55 -06:00
Shawn A a247a5ecb4 fix sketch size 2018-02-14 14:09:39 -06:00
Shawn A c43551f85a some more strings in progmem 2018-02-14 13:24:00 -06:00
Shawn A cbb32fdd61 cleanup 2018-02-14 12:53:52 -06:00
Shawn A bc4c07f315 defaulting to icons 2018-02-14 12:50:05 -06:00
Shawn A 369b627b3b oops 2018-02-14 12:43:30 -06:00
Shawn A 089c487576 adds toggle for scan quality as percentage
`setScanDispPerc` until we have decent remplating
2018-02-14 12:42:21 -06:00
Shawn A ba3a2c8451 moved all tokens to strings.h 2018-02-14 12:41:38 -06:00
Shawn A 8e7663b52b ugh aliases 2018-02-14 11:13:28 -06:00
Shawn A 78f7de38ad publicized debug helpers 2018-02-14 10:54:04 -06:00
Shawn A 3d3518a10a adds disconnect method for users
non persistent disconnect
2018-02-14 10:50:57 -06:00
Shawn A e342fd9b71 refactor ip form outputs 2018-02-14 10:33:28 -06:00
Shawn A addb045a0c moved strings to flash 2018-02-14 09:36:09 -06:00
Shawn A bab1201dcb fix esp32 esp8266 bug 2018-02-13 11:40:19 -06:00
Shawn A 611246bd75 rename 2018-02-13 07:55:41 -06:00
Shawn A 3dcf3c0927 rename 2018-02-13 07:55:32 -06:00
Shawn A 7f2fdee9c8 Create ISSUE_TEMPLATE.md 2018-02-13 07:42:23 -06:00
Shawn A 1c890c0c49 Create contributing.md 2018-02-13 07:40:55 -06:00
Jasper 5243036dbf Update WiFiManager.cpp 2018-02-13 20:00:17 +08:00
Jasper a94d897ee4 Update WiFiManager.cpp 2018-02-13 19:52:38 +08:00
Jasper aa734eb606 Update WiFiManager.cpp 2018-02-13 17:18:26 +08:00
Jasper a863167b23 Lower RAM usage of library
Place remaining debug messages into Flash using F().
2018-02-13 11:16:37 +08:00
Shawn A 79eb0fee47 Merge branch 'development' of https://github.com/tzapu/WiFiManager into development 2018-02-12 19:23:52 -06:00
Shawn A 3e10f984e1 template 2018-02-12 19:23:51 -06:00
Shawn A 17410d38c2 readme 2018-02-12 13:46:03 -06:00
Shawn A 1f7dc79b20 added webserver precompiler warning
updates readme
2018-02-12 13:03:13 -06:00
Shawn A 95b48454e8 Merge branch 'development' into esp32 2018-02-12 12:31:31 -06:00
Shawn A 4424e66222 infohelp align html 2018-02-12 12:31:16 -06:00
Shawn A 75d007d1c8 Merge branch 'development' into esp32 2018-02-12 11:05:12 -06:00
Shawn A 46929e0ee6 change uptime 2018-02-12 10:59:50 -06:00
Shawn A 8e28011f13 fix some html bugs 2018-02-12 10:57:59 -06:00
Shawn A 617e52cb84 implemented info strings for esp32 2018-02-12 10:54:51 -06:00
Shawn A 2c735ab999 Merge branch 'development' into esp32
Merge branch 'development' into esp32

# Conflicts:
#	README.md
#	WiFiManager.cpp
#	WiFiManager.h
#	examples/OnDemandConfigPortal/OnDemandConfigPortal.ino
2018-02-12 08:47:28 -06:00
Shawn A fc4942db6e all tokens now in strings 2018-02-09 12:35:43 -06:00
Shawn A 3914fee227 converting token strings, in progress broken 2018-02-08 17:05:35 -06:00
Shawn A ffc85a81fe remove reset, no reason for it 2018-02-08 13:18:08 -06:00
Shawn A 1c4011bfb4 adds webclient checking for timeout delay 2018-02-08 12:31:31 -06:00
Shawn A 57ef33a7fc readme 2018-02-08 11:00:54 -06:00
Shawn A 9a76b3d94d camelcase _staShowStaticFields 2018-02-08 09:36:50 -06:00
Shawn A 0af804a2f1 Merge branch 'master' into esp32 2018-02-07 10:13:11 -06:00
Shawn A 4d715890f6 Update README.md
Esp32 warning
2018-02-06 19:16:41 -06:00
Shawn A f5fa886c93 Merge branch 'master' into development 2018-02-06 11:28:51 -06:00
Shawn A e49335d811 Merge pull request #505 from Loufylouf/master
Bug fix for problem discovered when setting length to 1 for additiona…
2018-02-06 11:25:27 -06:00
Shawn A 8e07025e38 fix esp32 wifi.ssid 2018-02-06 10:19:52 -06:00
Shawn A 7cc86e57be fix esp32 examples 2018-02-06 09:50:33 -06:00
Shawn A b22686c8a1 make debug funcs public 2018-02-06 09:50:03 -06:00
Shawn A 2b9ddea331 debugsoftapconfig for esp32 2018-02-06 09:49:49 -06:00
Laurent Louf 6aaa83a266 Bug fix for problem discovered when setting length to 1 for additional parameters
The initialization of the buffer holding the value stopped before the last character and storage did not take into account the extra-byte for end of string.
2018-02-06 14:12:13 +01:00
Shawn A b1b34a3c97 ajax test 2018-02-02 14:38:40 -06:00
Shawn A 44c85a2315 fixup merge 2018-02-01 13:16:26 -06:00
Shawn A da66231e47 Merge branch 'development' into esp32 2018-02-01 11:45:20 -06:00
Shawn A 2e08e7de32 #454 adds WIFI_MANAGER_OVERRIDE_STRINGS
I dont feel like resolving conflicts
2018-02-01 10:05:39 -06:00
Shawn A ebdfa063a7 Merge branch 'master' into development 2018-02-01 09:41:42 -06:00
Shawn A a3a04f1f9a Merge pull request #487 from mtiutiu/master
make WIFI_MANAGER_MAX_PARAMS customizable
2018-02-01 09:40:40 -06:00
Shawn A cfb0d2bc5f doh... 2018-02-01 08:51:08 -06:00
Shawn A e8d1ea17cb fix paramscount, oops 2018-02-01 08:04:34 -06:00
Shawn A 0d5ebde9af more string tokens 2018-01-31 16:44:58 -06:00
Shawn A 6894c89441 moved all html strings out of code 2018-01-31 16:37:53 -06:00
Shawn A b0c61688d6 cleanup 2018-01-31 14:07:38 -06:00
Shawn A 68762e1741 typo 2018-01-31 14:03:33 -06:00
Shawn A a21f8cbc39 moved http strings to include, added token flags 2018-01-31 13:54:54 -06:00
Shawn A 19d533b7d5 adds exit to readme 2018-01-31 13:07:34 -06:00
Shawn A ccfddefaa1 oops 2018-01-31 12:57:49 -06:00
Shawn A 95253e834d Merge branch 'master' into development 2018-01-31 12:50:24 -06:00
Shawn A 53a27f154e Merge pull request #467 from lukepalmer/master
Document that parameter id cannot contain spaces
2018-01-31 12:50:04 -06:00
Shawn A 53c8addfdc debugging clean 2018-01-31 12:48:11 -06:00
Shawn A e5c263c414 fixes paramid issues
paramid must be alphanumeric and adds {I} token support to use ids as input names if we make that optional.
2018-01-31 12:23:25 -06:00
Shawn A e015efe8d0 fixup debugging 2018-01-31 09:30:46 -06:00
Shawn A 5f78d38f46 fix up parameters 2018-01-31 09:30:37 -06:00
Shawn A fa04972cb1 fix tabs 2018-01-30 14:07:21 -06:00
Shawn A 8697cab0ae clean up .h file 2018-01-30 14:02:01 -06:00
Shawn A c8d89db529 oops 2018-01-30 14:00:39 -06:00
Shawn A ff973e1639 clean up parameters 2018-01-30 13:47:13 -06:00
Shawn A d61d9a67b1 Merge branch 'master' into development
conflicts resolved
2018-01-30 13:31:47 -06:00
Shawn A a4795b77f7 Merge pull request #374 from liebman/allocate-params-array
use malloc/free for WiFiManagerParameter* array instead of hard coding.
2018-01-30 12:29:30 -06:00
Shawn A 46a9431475 Merge branch 'master' into development 2018-01-30 12:10:13 -06:00
Shawn A a832af02ca Merge pull request #468 from liebman/param-value-memory-leak
WiFiManagerParameter allocates but never frees __value!
2018-01-30 12:08:31 -06:00
Shawn A d4540f1197 update library.properties 2018-01-29 14:09:18 -06:00
Shawn A d1639e228a update library.json
I thnk think this is correct
2018-01-29 14:05:59 -06:00
Shawn A fdfaecce8a Fix examples 2018-01-29 13:13:14 -06:00
Shawn A 380a63d519 attempt resetsettings fix 2018-01-29 11:36:10 -06:00
Shawn A 7e1455778d adds esp debugplatforminfo 2018-01-28 09:58:52 -06:00
Shawn A 00fb96aa29 Merge branch 'development' into esp32 2018-01-28 09:57:44 -06:00
Shawn A 7fb35a9540 adds debug platform info 2018-01-28 09:57:20 -06:00
Shawn A cb02e72123 fix esp8366 bug 2018-01-27 14:31:28 -06:00
Shawn A 85317530e8 fix esp8266 bug WEBSERVERSHIM 2018-01-27 14:28:07 -06:00
Shawn A e55741f201 Merge branch 'development' into esp32 2018-01-27 11:45:49 -06:00
Shawn A 8595ea5d2c oops 2018-01-27 11:45:38 -06:00
Shawn A 9a3f501a24 Merge branch 'development' into esp32 2018-01-27 11:42:02 -06:00
Shawn A 3b6d5f790a replace esp.reset with restart 2018-01-27 11:41:42 -06:00
Shawn A dbb091d1b7 fix info page 2018-01-27 11:40:05 -06:00
Shawn A 867eb4e689 oops 2018-01-27 08:49:55 -06:00
Shawn A 42cd1aeb8d fix for erase config when STA disabled 2018-01-27 08:31:17 -06:00
Shawn A a3678c6c22 millis typo 2018-01-27 08:19:54 -06:00
Shawn A 0fb86c3d8c fix deprecated warnings 2018-01-25 21:22:02 -06:00
Shawn A 4db69a3790 rework def WEBSERVERSHIM
testing libraries with esp8266 name or webserver
2018-01-25 16:05:55 -06:00
Shawn A 2761656d78 change wifi_ssid ret to string, fix info 2018-01-25 13:58:39 -06:00
Shawn A e56d22cfb1 fix esp32 enablesta toggle 2018-01-25 13:47:00 -06:00
Shawn A c13c076b46 quiet timeout logging 2018-01-25 13:09:19 -06:00
Shawn A f820dc78be fix esp32 SSID tokens 2018-01-25 13:08:56 -06:00
Shawn A af507d798e add bbx10 to authors 2018-01-25 12:48:09 -06:00
Shawn A a52740ecff fix esp32 erase flash 2018-01-24 21:24:21 -06:00
Shawn A 1f691ae35c typo 2018-01-24 17:08:24 -06:00
Shawn A 65c06c6e2b esp32 auto ssid 2018-01-24 16:09:30 -06:00
Shawn A 3777fcc846 esp32 about page 2018-01-24 16:09:17 -06:00
Shawn A de2deb8e69 oops 2018-01-24 15:24:05 -06:00
Shawn A 7189e36c59 clean up defines, remove esp31b 2018-01-24 13:54:58 -06:00
Shawn A 8dbe045655 remove system_event_info_t arg 2018-01-24 13:36:34 -06:00
Shawn A ead2b7353c enable autoreconnect 2018-01-24 13:16:06 -06:00
Shawn A ceaf53f604 adds esp32 autoreconnector
Using static event cb for now, feel free to improve, this functionality should be fixed in core soon
2018-01-24 13:13:25 -06:00
Shawn A e5879b2101 fix esp32 autoconnect 2018-01-24 11:05:28 -06:00
Shawn A 2a50d797a0 fix esp32 softap numclients 2018-01-24 08:50:24 -06:00
Shawn A 2af1c62bd1 redo esp32 disconnect 2018-01-24 08:27:56 -06:00
Shawn A f3be7c7c0b it compiles 2018-01-23 14:07:33 -06:00
Shawn A 90024b8603 adding def blocks, nonworking
adding conditionals for all module types, there has been requests for other module support in addition to esp32, so I ma just gonna go ahead and avoid else fallbacks for now. Not working yet.
2018-01-23 13:28:49 -06:00
Shawn A d883ce8ae1 Merge pull request #489 from tablatronix/development
added some esp abstraction to make ports easier
2018-01-23 11:41:34 -06:00
Shawn A 8364a6a85d added some esp abstraction to make ports easier 2018-01-23 11:39:12 -06:00
Tiutiu Marius Cristian 8c906af563 make WIFI_MANAGER_MAX_PARAMS customizable 2018-01-22 12:42:23 +02:00
Shawn A 5aafb89a3f Merge pull request #313 from tablatronix/development
Development and cleanup
2018-01-17 10:54:37 -06:00
Shawn A b266cd5934 fix open tag on info 2018-01-10 10:52:36 -06:00
Shawn A 1a61362f74 typo 2018-01-10 10:05:07 -06:00
Shawn A 7625680daf adds test of setCaptivePortalEnable to example 2018-01-10 10:04:26 -06:00
Shawn A d7976381e6 fix setCaptivePortalEnable 2018-01-10 10:02:46 -06:00
Christopher Liebman 5c6252fe45 should use delete[] not delete 2017-12-09 08:37:35 -08:00
Christopher Liebman a5ff5cb9e4 Add WiFiManagerParameter destructor to free new'd _value, it was allocated but never free'd 2017-12-09 06:24:15 -08:00
Christopher Liebman d66cd47df8 use realloc() when increasing the size of _params. addParameter() now returns bool
indicating the status of adding the parameter where false indicates it failed to
increase the size of _params and did not add the parameter.
2017-12-09 06:04:07 -08:00
Luke Palmer eb560629d6 Document parameters 2017-12-04 19:54:59 -05:00
Shawn A 0897c5800c update examples w setConfigPortalTimeout 2017-11-28 17:01:27 -06:00
Shawn A 648274ab3d oops left wrap test in 2017-11-21 12:51:43 -06:00
Shawn A 2f4015e797 fix token replace invalid html 2017-11-21 12:24:25 -06:00
Shawn A a702fa6c75 html validation fizes 2017-11-21 11:53:30 -06:00
Shawn A 9a571226cd Added some info panel changes
adds connect info to root info and wifi, minimal wordyness
2017-11-16 14:06:36 -06:00
Shawn A fa05d2c574 fix for configportal on wifisave fail
disocnnect STA on save failures
move reset out of configportal loop
2017-11-16 11:59:22 -06:00
Shawn A 0ae9ca3d55 adds _debugport stream ref
pass stream reference via constructor to use for _debugPort in DEBUG_WM, if someone needs dynamic we can add pointer setter, but seems overkill
2017-11-16 10:02:03 -06:00
Shawn A d6aec20bc3 add debug 2 argument function 2017-11-15 16:14:52 -06:00
Shawn A 3fdf53bf06 adding debug for configportalhastimeout 2017-11-15 11:41:47 -06:00
Shawn A a1050d014f fix some returns 2017-11-03 16:41:17 -05:00
Shawn A 52d5427654 testing erase config polyfill
this is getting rediculous, dev on 2_3_0 has to stop there are so many bugs.
2017-11-01 06:39:30 -05:00
Shawn A e8c0b52470 added ease, stabilize persistent modes, rename some functions 2017-10-28 21:38:13 -05:00
Shawn A 4763783fe1 rename some functions 2017-10-28 11:51:26 -05:00
Shawn A ad6b8bdc86 add local enableSTA for toggling 2017-10-27 20:01:19 -05:00
Shawn A d09aff2f6d fixing some reliability issues, testing 2017-10-27 17:19:43 -05:00
Chris Liebman 0b6341bea4 cleanup readme (removed hint about alternate constructor) 2017-10-26 16:10:34 -07:00
Chris Liebman 6465d72f6e Refactored to use only a default constructor and automatically resize the parameter array each time the size limit is reached.
I used the initial size (WIFI_MANAGER_MAX_PARAMS) as the increment when resizing.
Existing data is coppied to the new array and the old one is free'd.
2017-10-26 15:23:47 -07:00
Chris Liebman 33704176e0 Merge remote-tracking branch 'upstream/master' into allocate-params-array 2017-10-25 18:59:23 -07:00
Shawn A df5857464a adds verbose connection status enum strings 2017-10-18 11:00:02 -05:00
Shawn A eb434a0187 clean up handlexit feature 2017-10-18 09:37:21 -05:00
Shawn A d7e3c8d005 Merge pull request #5 from mrbig/development
uninitialized abort caused immediate exit
2017-10-18 09:02:01 -05:00
Shawn A 3d2453acc5 html for exit 2017-10-18 08:59:35 -05:00
Nagy Attila Gabor 342eacfe37 autoConnect did not return true on successfull connection
This seems like a simple typo to me
2017-10-17 00:20:19 +02:00
Nagy Attila Gabor cf51018512 uninitialized abort caused immediate exit
In some cases this caused the config portal to exit right after
start
2017-10-16 23:16:03 +02:00
Shawn A db2a1336e9 adds exit functionality to shutdown configportal/webportal 2017-09-25 14:11:36 -05:00
Shawn A b151c19b3c add ondemandwebportal example 2017-09-18 12:58:31 -05:00
Shawn A 2aef1344b4 use ip as title if not in captiveportal 2017-09-18 10:19:38 -05:00
Shawn A 4592914fad test ondemand webportal 2017-09-18 08:42:09 -05:00
Shawn A 8e710b9d92 disable ios safari tel links
some numbers might auto link as telephone numbers, this disables it.
2017-09-16 11:07:57 -05:00
Shawn A eee3fb72b2 #418 even more info 2017-09-16 11:02:37 -05:00
Shawn A 12de39135d comments 2017-09-16 10:46:44 -05:00
Shawn A 80470fb553 addd token precheck flags
This helps skip token replacements that are not even used, replace is slow, this is an optimization mostly for large sets of params or aps.
2017-09-16 10:39:51 -05:00
Shawn A 31ab2b67d0 ability to disable captiveportal
Sometimes the redirect to captive portal is unwanted or a nuisance, eg wehn using as a webserver etc.
2017-09-14 17:09:17 -05:00
Shawn A 4d18bfb113 abstracted outputters 2017-09-14 16:34:16 -05:00
Shawn A 37dbd667f4 add staticfield setter 2017-09-14 15:38:42 -05:00
Shawn A e43a7d0b75 modify templates, remove placeholders
adds labels to all inputs, deprecates {p} placeholders, adds {t} to ttitles
2017-09-14 15:38:12 -05:00
Shawn A c6f7ac0012 added uptime to info
still subject to rollover
2017-09-14 10:26:51 -05:00
Shawn A 64798ebbf1 pimped out info pagee
We can simply this later, or make an option string to display specific things
2017-09-10 21:17:07 -05:00
Shawn A 985f8118dd style lists /info 2017-09-08 22:28:13 -05:00
Shawn A 69ddda0ee4 Merge remote-tracking branch 'remotes/tzapu/development' into tzapu/development
removed autoconnect params, still testing valeus are always empty
2017-09-08 17:08:18 -05:00
Shawn A f59c150729 Merge pull request #365 from vyruz1986/master
Allow showing static IP config without predefined value
2017-09-08 16:19:15 -05:00
Shawn A 14ce25081a Merge remote-tracking branch 'remotes/tzapu/development' into tzapu/development 2017-09-08 16:15:20 -05:00
Shawn A 81b37dfffc adds some style, clean up css, adds new tokens
#415
2017-09-08 16:08:35 -05:00
Shawn A 1f4a8fe499 Merge pull request #251 from ayomawdb/development
Adding WiFiManagerParameter implementation with labelPlacement parameter
2017-09-08 15:54:46 -05:00
Germán Martín 7b9804d5a2 Merge branch 'master' into resetConfigCallback 2017-09-04 21:05:49 +02:00
Shawn A a93b601cd7 again 2017-08-31 13:57:23 -05:00
Shawn A 6525a0bd3d fixed comment wording 2017-08-31 13:57:11 -05:00
Shawn A 2c357d7e86 changing non form back to GET
for now #409
2017-08-31 10:21:21 -05:00
Shawn A 5f28843843 Cleaned some html csss 2017-08-30 14:01:37 -05:00
Shawn A 6e43c1eb41 change all forms to POST
#409
2017-08-30 10:24:04 -05:00
Shawn A 66c653ff94 convert to post 2017-08-30 10:00:48 -05:00
Shawn A 606a1c3128 removed escaped quotes 2017-08-30 10:00:29 -05:00
Shawn A 63dd714805 oops missed one pr#244 2017-08-30 09:22:40 -05:00
Shawn A 9160b5bd3b maxlength null string fix
pr#244
2017-08-30 09:15:36 -05:00
Shawn A 04a9dda74b testing mode and persistent presrvation
You should be able to have sta+softap mode with your own softap, and starting config portal will not overwrite your default softap, but i cannot find a way to reconnect other than rebooting the device
2017-08-29 16:31:59 -05:00
Shawn A d1ab6ec6db left in debug 2017-08-28 21:00:15 -05:00
Shawn A b62f488b6b Merge remote-tracking branch 'origin/feature-icons' into development
adds feature icons
2017-08-28 19:18:20 -05:00
Shawn A 8185eaa002 add blocking setter
@todo add example
2017-08-27 11:04:05 -05:00
Shawn A 8592647cbf fraking tabs 2017-08-27 10:57:43 -05:00
Shawn A f2580463e4 fix const char corruptions
#400
 fixing non blocking, non blocking does not handle timeouts for the user
2017-08-27 10:55:26 -05:00
Shawn A c4563802f3 renable blocking 2017-08-27 09:32:31 -05:00
Shawn A 68e3eb5bc8 Merge branch 'master' into development 2017-08-27 09:13:00 -05:00
Shawn A cadf6b4a80 Merge remote-tracking branch 'upstream/master' 2017-08-27 09:05:52 -05:00
Shawn A 75f34d9b59 Merge remote-tracking branch 'tzapu/master' 2017-08-27 08:48:35 -05:00
Shawn A 47d9082e18 testing non blocking portal
calling process in loop not fast enough results in corrupt webpages, not sure why.
2017-08-27 00:11:04 -05:00
Shawn A 0aecffc822 fix configportal loop flow
removed returns for better flow
2017-08-26 23:26:48 -05:00
Shawn A 179c0309a5 comments, autoconnect fix
fix sta+ap mode preservaton in autoconnect
2017-08-26 23:13:37 -05:00
tzapu 89af31245b Merge pull request #398 from Derek123456/Derek123456-patch-1
Fix for issue https://github.com/tzapu/WiFiManager/issues/392
closes #392
thank you very much
2017-08-22 10:12:29 +03:00
Derek123456 68e32a10c0 Update WiFiManager.cpp
https://github.com/tzapu/WiFiManager/issues/392
Increased size of parLength to 5 so the custom parameter length variable can be up to 9999 long.
2017-08-22 10:32:52 +08:00
Derek123456 cee18a7ce3 Update WiFiManager.h
Changed <input ... length={l}>to <input ... maxlength={l}>
2017-08-22 10:30:53 +08:00
tzapu f9c4c87c61 Merge pull request #386 from denisvm/readme-wishlist
Improve wishlist in README
2017-07-13 09:39:40 +03:00
tzapu 06d75bf7b1 Update README.md 2017-07-13 09:39:28 +03:00
Dênis Volpato Martins 9637d9473e Improve wishlist in README 2017-07-12 22:07:33 -03:00
tzapu 0de9d12930 Merge pull request #363 from suculent/fix-content-length
fix for #362 - Setting Content-length explicitly - https://github.com…
2017-07-10 13:41:07 +03:00
tzapu eb4594c8e4 Merge pull request #383 from scop/spelling
Spelling fixes
thanks
2017-07-10 09:38:21 +03:00
Ville Skyttä 58eb7113e7 Spelling fixes 2017-07-09 17:11:31 +03:00
Chris Liebman 898768092c removed un-needed constructor declaration 2017-06-27 16:35:48 -07:00
Chris Liebman c4905c23b7 remove init function as its not needed with one constructor 2017-06-27 16:27:37 -07:00
Chris Liebman 3950a3b859 use single constructor with default value for size 2017-06-27 16:24:23 -07:00
Germán Martín 8f90e0f5d7 Add a callback when reset settings is triggered 2017-06-26 15:04:57 +02:00
vyruz1986 0fc051a445 Merge remote-tracking branch 'refs/remotes/tzapu/master' 2017-06-12 21:21:10 +02:00
tzapu 5e9248651f Merge pull request #334 from camelmasa/fix-broken-links
Fix broken link
2017-06-06 16:04:16 +03:00
Chris Liebman 362a561a35 use malloc/free for WiFiManagerParameter* array instead of hard coding.
add alternate constructor to specifiy max parameter count
origional default constructor uses old hard codded value
2017-06-04 06:41:27 -07:00
Alex Goris 136c0c9cba Also show static IP fields when static IP is passed
Regardless of the boolean, we should always show static IP fields if
actual static IP value is passed. This ensures backwards compatibility
2017-05-04 22:04:05 +02:00
Alex Goris 486ea7db2c Allow showing static IP config without predefined value
Previously a valid predefined static IP had to be passed before the
config page would show the IP, gateway and subnet fields. This did not
allow the config page to show 'optional' static IP fields.
Now a boolean can be passed to the autoConnect() function which will
specify whether the static IP fields should be shown or not.
When this boolean is true but no predefined values are passed and fields
are left blank in config page, wifiManager will revert to DHCP. This
allows user to choose between static IP or DHCP without changing code
2017-05-04 21:59:17 +02:00
Matěj Sychra ada93b721a fix for #362 - Setting Content-length explicitly - https://github.com/tzapu/WiFiManager/issues/362 2017-05-03 14:56:31 +02:00
camelmasa 29b2f02ae4 Fix broken links 2017-03-20 12:58:49 +09:00
Shawn A 004f222f40 do not wait for conx is no ssid 2017-02-10 17:05:07 -06:00
Shawn A 612e18be35 oops deleted a function 2017-02-10 15:40:31 -06:00
Shawn A 0b0eb6159c moving blocks 2017-02-10 15:29:32 -06:00
Shawn A 1a44dd53e6 move apcallback to proper location
This was actually being called before the ap was setup!
2017-02-10 15:21:48 -06:00
Shawn A 65349cb546 fix WL_IDLE_STATUS return values for compatibility
This might need better handling in future, since we only get back a bool
of wether or not we are connected, not if configportal was saved etc.
might be a problem.
2017-02-10 15:13:48 -06:00
Shawn A e9b36f9084 fix breakafterconfig 2017-02-10 15:05:45 -06:00
Shawn A bd9c3b31fb refactoring some larger functions
* broke large functions into smaller , to allow new features to be
hooked in easier
* added persistent test to constructor destructor
* testing turn off sta during portal , causes issues
2017-02-10 14:07:52 -06:00
Shawn A c819d46902 allow for empty password 2017-02-09 17:10:15 -06:00
Shawn A 2edd37eeb8 oops typo 2017-02-09 17:02:33 -06:00
Shawn A 45a325bd34 fix validippassword
abstracted ap password validation
passing a invalid password should be fatal , not fallback to null, but
could be an optional define
2017-02-09 16:57:34 -06:00
Shawn A 9c72bf98f7 cleaning up source, comments 2017-02-09 16:33:10 -06:00
Alex T 628307dbf7 Merge branch 'master' into development 2017-02-09 15:56:51 +02:00
Shawn A c8455f5cd0 Merge remote-tracking branch 'refs/remotes/tzapu/master' 2017-02-08 12:05:04 -06:00
Shawn A 7360be5f60 Merge remote-tracking branch 'refs/remotes/origin/feature_308_configportaltimeouts' 2017-02-08 12:03:32 -06:00
tzapu 3135bc5e89 Merge pull request #310 from tablatronix/feature_308_configportaltimeouts
Feature 308 configportaltimeouts
fixes #308 
thank you very much
2017-02-08 08:55:15 -08:00
Shawn A c810633ee3 reset configportal timeouts after ap disconnect
configportaltimeout now starts at configportalstart if no sta clients,
or after last client disconnects. Will never timeout if ap has sta
client! handle edge case in user code.
2017-02-08 10:34:41 -06:00
Shawn A 0ddb835072 feature #308
only timeout when ap has no client, do not timeout configportal when
user is connected.
2017-02-08 08:18:59 -06:00
Shawn A a8c13a7c96 Merge remote-tracking branch 'refs/remotes/tzapu/master' 2017-02-08 08:07:01 -06:00
Alex T 7a17c98828 Merge branch 'master' into development 2017-02-03 06:17:42 +02:00
tzapu 8ffb4cbfa9 Merge pull request #284 from robertoostenveld/master
use setAPStaticIPConfig instead  of (old?) setAPConfig in first example
2017-02-02 02:57:55 -08:00
tzapu 0cc4487e42 Merge pull request #297 from jorgecis/patch-1
Quotes are missing creating issues.
2017-02-02 02:57:16 -08:00
tzapu b696b2c29a Merge pull request #286 from vyruz1986/master
Don't add custom parameters if array size is exceeded
2017-02-02 02:56:56 -08:00
Jorge Cisneros bd0da6c7a6 Quotes are missing creating issues. 2017-01-16 22:48:09 -06:00
Alex Goris 1f500fddd1 Don't add custom parameters if array size is exceeded
array containing custom parameters is initialised at class
initialization time with a fixed value. When we later try to add more
parameters than the array allows we will now discard the offending
parameters and make a debug logging so the developer knows what's going
on.

Might be further improved as per this answer on StackOverflow:
http://stackoverflow.com/a/12271501
This would allow the array size to be specified at initialisation time,
and would give flexibility to the developer to decide how big the array
should be.

closes tzapu/WiFiManager#285
2017-01-08 23:31:53 +01:00
Robert Oostenveld a231ae5deb use setAPStaticIPConfig instead of (old?) setAPConfig in first example 2017-01-07 22:10:00 +01:00
Ayoma Wijethunga 5f8f1ce5e6 Adding WiFiManagerParameter implementation with labelPlacement parameter 2016-11-26 20:17:41 +05:30
tzapu 022b15d2c8 Merge pull request #250 from ivankravets/patch-5
Update platforms compatibility
Thank you very much
2016-11-22 12:51:52 +02:00
Ivan Kravets 2a0ac55f87 Update platforms compatibility 2016-11-22 12:50:55 +02:00
Alex T abedb61ca1 parameter label 2016-10-15 12:07:48 +03:00
tzapu fd15f986d3 Merge pull request #210 from TaaraLabs/patch-1
startConfigPortal() without any parameters

thank you very much
2016-10-15 08:04:13 +03:00
Alex T 60c22d672f Merge commit 'e0b8acb8dd8e419e378e71abed77fe926c2e5b54' 2016-09-08 13:08:09 +03:00
Alex T 1b261f2371 intial html template parser 2016-09-08 13:07:51 +03:00
TaaraLabs 31887ff36a startConfigPortal() without parameters 2016-08-06 12:45:22 +03:00
TaaraLabs c3d01d33e1 startConfigPortal() without any parameters
startConfigPortal() without any parameters uses auto generated name ESP + ChipID
2016-08-06 12:38:26 +03:00
tzapu e0b8acb8dd Merge pull request #188 from bakrus/patch-1
Fix to allow 5 digit 'mqtt_port'
2016-07-02 15:25:29 +03:00
bakrus 039702327e Fix to allow 5 digit 'mqtt_port'
'WiFiManagerParameter custom_mqtt_port' made consistent with declaration of 'mqtt_port'
2016-07-02 13:27:59 +02:00
Alex T fac1575c96 attempt codecov 2016-06-15 14:35:43 +03:00
tzapu 560d4113f9 Merge pull request #168 from gitgrimbo/staticip-example-improved-comments
Improve comments for AutoConnectWithStaticIP example
thank you very much
2016-05-24 08:32:28 +03:00
gitgrimbo c93cd80f58 Improve comments for AutoConnectWithStaticIP example 2016-05-11 08:21:23 +01:00
Alex T 04d47882a7 ver bump 2016-05-08 11:25:03 +03:00
Alex T 028bdeeb17 removed 204 header response https://github.com/tzapu/WiFiManager/issues/114 2016-05-08 10:14:11 +03:00
Alex T 44e828e77a reverted std::sort that caused problems with isnan and other none namespeced used function calls 2016-05-08 10:07:32 +03:00
Alex T 801ae82ef5 removed extraneous headers 2016-05-08 09:41:06 +03:00
Shawn A 74bccc04f7 adds better retina support
adds template and layer png master
2016-03-25 14:17:28 -05:00
Shawn A fd27cef1ae remove debug 2016-03-25 09:31:07 -05:00
Shawn A 6708ddf37b remove debug 2016-03-25 08:48:49 -05:00
Shawn A 83c271fed4 initial commit, signal meter and secure icons
Adds sprite based icons, added some accessibility support since this
uses background images.

Can use classes `left` or `right` on parent div to align on either side
of SSID, parent div `invert` css filters the icons to white.

base64 image string has been formatted for easy replacement
2016-03-25 08:19:47 -05:00
Shawn A 8a375ec340 Merge remote-tracking branch 'refs/remotes/tzapu/master' 2016-03-18 14:47:57 -05:00
140 changed files with 18520 additions and 2196 deletions
+14
View File
@@ -0,0 +1,14 @@
# Keep local credentials, build output, and test artifacts out of the Docker
# build context. OTA firmware is mounted read-only by compose.ota.yaml instead
# of copied into an image.
.git
.github
.pio
**/.pio
node_modules
**/node_modules
artifacts
test/portal-station.env
test/.env
platformio.local.ini*
**/platformio.local.ini*
+60
View File
@@ -0,0 +1,60 @@
name: Build
on:
push:
branches:
- device-framework
tags:
- "v*"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
documentation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: bash -n scripts/*.sh tools/check-ota-partitions.sh tools/portal-hardware tools/lib/*.sh tools/tests/*.sh
- run: python3 -m py_compile test/portal-harness/tools/ota_fixture_input.py
- run: |
for spec in tests/portal-harness/tests/*.js; do
node --check "$spec"
done
- run: timeout 15s python3 tools/tests/test-capture-serial.py
- run: timeout 15s bash tools/tests/test-ota-fixture-identity.sh
- run: ./tools/check-ota-partitions.sh
- run: ./scripts/check-docs.sh
compile-tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- platform: esp8266
examples: true
ota_fixtures: true
unity: true
- platform: esp32
examples: true
ota_fixtures: true
unity: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19
- run: ./scripts/test.sh compile --platform ${{ matrix.platform }}
- if: matrix.unity
run: ./scripts/test.sh unity --platform ${{ matrix.platform }}
- if: matrix.examples
run: ./scripts/test.sh examples --platform ${{ matrix.platform }}
- if: matrix.ota_fixtures
run: ./scripts/test.sh ota-fixtures --platform ${{ matrix.platform }}
+69
View File
@@ -0,0 +1,69 @@
name: Publish release
on:
push:
tags:
- 'v*'
permissions:
contents: read
jobs:
documentation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: bash -n scripts/*.sh tools/check-ota-partitions.sh tools/portal-hardware tools/lib/*.sh tools/tests/*.sh
- run: |
for spec in tests/portal-harness/tests/*.js; do
node --check "$spec"
done
- run: timeout 15s python3 tools/tests/test-capture-serial.py
- run: ./tools/check-ota-partitions.sh
- run: ./scripts/check-docs.sh
compile-tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- platform: esp8266
examples: true
ota_fixtures: true
unity: true
- platform: esp32
examples: true
ota_fixtures: true
unity: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19
- run: ./scripts/test.sh compile --platform ${{ matrix.platform }}
- if: matrix.unity
run: ./scripts/test.sh unity --platform ${{ matrix.platform }}
- if: matrix.examples
run: ./scripts/test.sh examples --platform ${{ matrix.platform }}
- if: matrix.ota_fixtures
run: ./scripts/test.sh ota-fixtures --platform ${{ matrix.platform }}
publish:
needs:
- documentation
- compile-tests
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME"
- run: ./scripts/release-notes.sh "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md"
- run: >-
gh release create "$GITHUB_REF_NAME"
--title "WiFiManager $GITHUB_REF_NAME"
--notes-file "$RUNNER_TEMP/release-notes.md"
env:
GH_TOKEN: ${{ github.token }}
+40
View File
@@ -0,0 +1,40 @@
# PlatformIO
.pio/
.pioenvs/
.piolibdeps/
.vscode/
.cache/
*.pyc
*.pyo
*.pyd
__pycache__/
# IDE
.idea/
*.sublime-project
*.sublime-workspace
.vscode/
!.vscode/extensions.json
# PlatformIO project overrides
/platformio_override.ini
/build_output/
# OS
.DS_Store
Thumbs.db
# Build artifacts
*.o
*.elf
*.hex
*.bin
*.log
# Misc
node_modules/
# Local portal station handoff credentials and optional direct test artifacts
/test/portal-station.env
/tests/portal-harness/artifacts/
/artifacts/
-33
View File
@@ -1,33 +0,0 @@
language: c
before_install:
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz
- tar xf arduino-1.6.5-linux64.tar.xz
- sudo mv arduino-1.6.5 /usr/local/share/arduino
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
install:
- ln -s $PWD /usr/local/share/arduino/libraries/WiFiManager
# boards manager not working on 1.6.7 - 1.6.8
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs
# install lib arduino json not working in 1.6.5
# - arduino --install-library "ArduinoJson"
- git clone https://github.com/bblanchon/ArduinoJson /usr/local/share/arduino/libraries/ArduinoJson
- arduino --install-boards esp8266:esp8266
- arduino --board esp8266:esp8266:generic --save-prefs
- arduino --pref "compiler.warning_level=all" --save-prefs
script:
- "echo $PWD"
- "echo $HOME"
- "ls $PWD"
- source $TRAVIS_BUILD_DIR/travis/common.sh
- build_examples
# - "cat $PWD/examples/AutoConnect/AutoConnect.ino"
# - arduino -v --verbose-build --verify $PWD/examples/AutoConnect/AutoConnect.ino
# - arduino --verify --board arduino:avr:uno $PWD/examples/IncomingCall/IncomingCall.ino
# - arduino --verify --board arduino:avr:uno $PWD/examples/AdafruitIO_GPS/AdafruitIO_GPS.ino
notifications:
email:
on_success: change
on_failure: change
+80
View File
@@ -0,0 +1,80 @@
# Changelog
## 3.2.5
- Prevent ESP8266 portal firmware uploads from yielding in ESPAsyncWebServer's
SYS callback. The updater now enters asynchronous mode before its first
erase or write, so the real browser upload can complete and restart into
the new firmware image.
- Send the successful portal OTA response before scheduling the restart, so
browsers can observe a completed HTTP exchange on both ESP8266 and ESP32.
- Give ESP32's Wi-Fi radio a five-second hand-off interval before a user scan
retry, avoiding transient scan failures immediately after completion.
## 3.2.4
- Correct profile-backed Wi-Fi hand-off from the embedded web portal: the
station controller now owns attempts started through either portal surface,
preventing the legacy empty-SSID path from reporting success before a
station address is available.
## 3.2.3
- Clarify the public integration boundary, built-in browser protocol, and
portal presentation documentation without coupling the standalone library to
DeviceFramework.
- Refresh the standalone test guidance and pin the packaged DFTE dependency to
the validated 1.2.1 release.
## 3.2.2
- Align the direct ESP8266 and ESP32 test environments with the packaged DFTE 1.2.0 dependency.
## 3.2.1
- Ensure externally supplied station profiles remain authoritative on ESP32 by clearing stale SDK-owned credentials before opening the portal for an empty or invalid external profile set.
- Pin DFTE 1.2.0, the tested template-engine release used by the maintained portal.
## 3.2.0
- Refine the device-hosted portal with a startup Wi-Fi scan, stable loading overlays, clearer connection progress, and a resettable configuration timeout.
- Keep a successful portal-to-station hand-off reachable until the browser acknowledges its redirect, with a bounded fallback for captive or headless clients.
- Rename the presentation field `homeIntro` to `tagline` so portal identity and wording are clearer; update portal bootstrap contract to v3.
- Add focused Basic Portal, Branded Portal, Custom Portal Content, and Station Profiles examples for ESP8266 and ESP32, with real-hardware README captures.
- Strengthen release CI with documentation and clean-consumer/example compilation checks for both supported targets.
## 3.1.0
- Add an opt-in primary/fallback station-profile controller with bounded failover, reconnection, a durable consumer-supplied store, and profile-aware portal APIs. DeviceFramework uses this to persist verified WiFi profiles transactionally.
- Add portable portal branding and presentation hooks, including theme-aware shell and template rendering, without requiring DeviceFramework.
- Pin ESP32 tests to the Arduino 3-compatible pioarduino platform release and resolve DFTE 1.1.0.
## 3.0.6
- Correct async PlatformIO dependency owners to the registry's canonical lowercase identity, so a clean consumer builds WiFiManager and its ESP8266/ESP32 transport dependencies without duplicating them in `lib_deps`. Remove the superseded include-path bridge.
## 3.0.5
- Add a library-owned PlatformIO bridge for the asynchronous web/TCP include paths required when WiFiManager is nested beneath DeviceFramework.
## 3.0.4
- Set the package's deep PlatformIO dependency-discovery mode so WiFiManager's asynchronous web/TCP children remain available when it is consumed through DeviceFramework.
## 3.0.3
- Declare the ESP8266 and ESP32 async TCP libraries explicitly in the PlatformIO package manifest so clean consumers resolve the headers required by the asynchronous portal.
## 3.0.2
- Update the pinned DFTE dependency to the iterator-lifecycle and configuration-safe 1.0.2 release.
## 3.0.1
- Redact WiFi, AP, portal-form, and custom-parameter values from diagnostic logs.
## 3.0.0
- Establish `device-framework` as the independently maintained canonical branch.
- Add safe default parameter construction and allocation-failure handling.
- Pin the DFTE dependency used by PlatformIO builds.
+9
View File
@@ -20,3 +20,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
This is a fork of tzapu/WiFiManager (https://github.com/tzapu/WiFiManager)
Original work Copyright (c) 2015 tzapu
This software has been modified and includes contributions Copyright (c) 2024
Alex Hope-O'Connor (https://github.com/alexhopeoconnor). The original
license and copyright notice above must be preserved in all copies as required
by the MIT License.
+85 -336
View File
@@ -1,365 +1,114 @@
# WiFiManager
ESP8266 WiFi Connection manager with fallback web configuration portal
[![Build Status](https://travis-ci.org/tzapu/WiFiManager.svg?branch=master)](https://travis-ci.org/tzapu/WiFiManager)
WiFiManager gives ESP8266 and ESP32 firmware a polished, self-hosted Wi-Fi setup experience. It reconnects to saved networks and opens a temporary captive portal when it cannot, so users can configure the device from any phone or browser without a cloud service or companion app.
The configuration portal is of the captive variety, so on various devices it will present the configuration dialogue as soon as you connect to the created access point.
## See it on real hardware
First attempt at a library. Lots more changes and fixes to do. Contributions are welcome.
![A short WiFiManager portal tour showing product branding, nearby networks,
application settings, and scan feedback.](docs/assets/readme/portal-tour.gif)
#### This works with the ESP8266 Arduino platform with a recent stable release(2.0.0 or newer) https://github.com/esp8266/Arduino
WiFiManager provides a self-hosted setup portal for Wi-Fi and application
settings without copying portal HTML into each firmware. See the detailed
[portal UI guide](docs/PORTAL_UI.md) for supported branding and content APIs.
## Contents
- [How it works](#how-it-works)
- [Wishlist](#wishlist)
- [Quick start](#quick-start)
- Installing
- [Through Library Manager](#install-through-library-manager)
- [From Github](#checkout-from-github)
- [Using](#using)
- [Documentation](#documentation)
- [Access Point Password](#password-protect-the-configuration-access-point)
- [Callbacks](#callbacks)
- [Configuration Portal Timeout](#configuration-portal-timeout)
- [On Demand Configuration](#on-demand-configuration-portal)
- [Custom Parameters](#custom-parameters)
- [Custom IP Configuration](#custom-ip-configuration)
- [Filter Low Quality Networks](#filter-networks)
- [Debug Output](#debug)
- [Troubleshooting](#troubleshooting)
- [Releases](#releases)
- [Contributors](#contributions-and-thanks)
## Start with a working portal
## How It Works
- when your ESP starts up, it sets it up in Station mode and tries to connect to a previously saved Access Point
- if this is unsuccessful (or no previous network saved) it moves the ESP into Access Point mode and spins up a DNS and WebServer (default ip 192.168.4.1)
- using any wifi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point
- because of the Captive Portal and the DNS server you will either get a 'Join to network' type of popup or get any domain you try to access redirected to the configuration portal
- choose one of the access points scanned, enter password, click save
- ESP will try to connect. If successful, it relinquishes control back to your app. If not, reconnect to AP and reconfigure.
## How It Looks
![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png)
## Wishlist
- ~~remove dependency on EEPROM library~~
- ~~move HTML Strings to PROGMEM~~
- ~~cleanup and streamline code~~ (although this is ongoing)
- if timeout is set, extend it when a page is fetched in AP mode
- ~~add ability to configure more parameters than ssid/password~~
- ~~maybe allow setting ip of ESP after reboot~~
- ~~add to Arduino Library Manager~~
- ~~add to PlatformIO~~
- add multiple sets of network credentials
- ~~allow users to customize CSS~~
## Quick Start
### Installing
You can either install through the Arduino Library Manager or checkout the latest changes or a release from github
#### Install through Library Manager
__Currently version 0.8+ works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__
- in Arduino IDE got to Sketch/Include Library/Manage Libraries
![Manage Libraries](http://i.imgur.com/9BkEBkR.png)
- search for WiFiManager
![WiFiManager package](http://i.imgur.com/18yIai8.png)
- click Install and start [using it](#using)
#### Checkout from github
__Github version works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__
- Checkout library to your Arduino libraries folder
### Using
- Include in your sketch
```cpp
#include <ESP8266WiFi.h> //ESP8266 Core WiFi Library (you most likely already have this in your sketch)
#include <Arduino.h>
#include <WiFiManager.h>
#include <DNSServer.h> //Local DNS Server used for redirecting all requests to the configuration portal
#include <ESP8266WebServer.h> //Local WebServer used to serve the configuration portal
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
```
WiFiManager wifi;
- Initialize library, in your setup function add
```cpp
WiFiManager wifiManager;
```
void setup() {
Serial.begin(115200);
- Also in the setup function add
```cpp
//first parameter is name of access point, second is the password
wifiManager.autoConnect("AP-NAME", "AP-PASSWORD");
```
if you just want an unsecured access point
```cpp
wifiManager.autoConnect("AP-NAME");
```
or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use
```cpp
wifiManager.autoConnect();
```
// Leave the temporary setup portal available for three minutes.
wifi.setConfigPortalTimeout(180);
After you write your sketch and start the ESP, it will try to connect to WiFi. If it fails it starts in Access Point mode.
While in AP mode, connect to it then open a browser to the gateway IP, default 192.168.4.1, configure wifi, save and it should reboot and connect.
Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples).
## Documentation
#### Password protect the configuration Access Point
You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`.
A short password seems to have unpredictable results so use one that's around 8 characters or more in length.
The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal)
```cpp
wifiManager.autoConnect("AutoConnectAP", "password")
```
#### Callbacks
##### Enter Config mode
Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt.
Before `autoConnect()`
```cpp
wifiManager.setAPCallback(configModeCallback);
```
`configModeCallback` declaration and example
```cpp
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
Serial.println(myWiFiManager->getConfigPortalSSID());
// Reconnect to saved Wi-Fi, or open the setup portal when none works.
wifi.autoConnect("Device Setup", "change-me");
}
```
##### Save settings
This gets called when custom parameters have been set **AND** a connection has been established. Use it to set a flag, so when all the configuration finishes, you can save the extra parameters somewhere.
See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters).
```cpp
wifiManager.setSaveConfigCallback(saveConfigCallback);
```
`saveConfigCallback` declaration and example
```cpp
//flag for saving data
bool shouldSaveConfig = false;
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
```
#### Configuration Portal Timeout
If you need to set a timeout so the ESP doesn't hang waiting to be configured, for instance after a power failure, you can add
```cpp
wifiManager.setConfigPortalTimeout(180);
```
which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome.
Check for connection and if it's still not established do whatever is needed (on some modules I restart them to retry, on others I enter deep sleep)
#### On Demand Configuration Portal
If you would rather start the configuration portal on demand rather than automatically on a failed connection attempt, then this is for you.
Instead of calling `autoConnect()` which does all the connecting and failover configuration portal setup for you, you need to use `startConfigPortal()`. __Do not use BOTH.__
Example usage
```cpp
void loop() {
// is configuration portal requested?
if ( digitalRead(TRIGGER_PIN) == LOW ) {
WiFiManager wifiManager;
wifiManager.startConfigPortal("OnDemandAP");
Serial.println("connected...yeey :)");
}
// Service portal requests and connection state without blocking firmware work.
wifi.process();
}
```
See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal)
#### Custom Parameters
You can use WiFiManager to collect more parameters than just SSID and password.
This could be helpful for configuring stuff like MQTT host and port, [blynk](http://www.blynk.cc) or [emoncms](http://emoncms.org) tokens, just to name a few.
**You are responsible for saving and loading these custom values.** The library just collects and displays the data for you as a convenience.
Usage scenario would be:
- load values from somewhere (EEPROM/FS) or generate some defaults
- add the custom parameters to WiFiManager using
```cpp
// id/name, placeholder/prompt, default, length
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
wifiManager.addParameter(&custom_mqtt_server);
When saved Wi-Fi is unavailable, `autoConnect()` starts the portal asynchronously. Call `process()` from every `loop()` iteration while it may be open. Flash [Basic Portal](examples/BasicPortal/) to try this exact flow; its README gives the network name, password, portal address, and expected result after saving Wi-Fi.
```
- if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal)
- once configuration is done and connection is established [save config callback]() is called
- once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object.
```cpp
mqtt_server = custom_mqtt_server.getValue();
```
This feature is a lot more involved than all the others, so here are some examples to fully show how it is done.
You should also take a look at adding custom HTML to your form.
## Building a Home Assistant device?
- Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters)
- *Save and load custom parameters to EEPROM* (not done yet)
WiFiManager remains a standalone provisioning library. If a device also needs
persistent configuration, MQTT, Home Assistant discovery, OTA, mDNS, and an
optional local web UI, see
[DeviceFramework](https://github.com/alexhopeoconnor/DeviceFramework), which
integrates this portal as part of that larger device lifecycle.
#### Custom IP Configuration
You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state)
## Make it yours
##### Custom Access Point IP Configuration
This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()`
```cpp
//set custom ip for portal
wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
const char kTitle[] PROGMEM = "Set up Temperature Monitor";
const char kBrand[] PROGMEM = "Example Devices";
const char kAccent[] PROGMEM = "#347a45";
void setup() {
WiFiManagerPortalConfig portalUI;
// Leave fields unset to keep WiFiManager's built-in portal values.
portalUI.title = WiFiManagerPortalText::progmem(kTitle);
portalUI.identityText = WiFiManagerPortalText::progmem(kBrand);
// Theme values customise the built-in styles; they do not replace the portal.
portalUI.theme.accent = WiFiManagerPortalText::progmem(kAccent);
portalUI.theme.cornerRadiusPx = 10;
wifi.setPortalConfig(portalUI); // Apply before the portal starts.
wifi.autoConnect("Device Setup");
}
void loop() {
wifi.process();
}
```
##### Custom Station (client) Static IP Configuration
This will make use the specified IP configuration instead of using DHCP in station mode.
```cpp
wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0));
```
There are a couple of examples in the examples folder that show you how to set a static IP and even how to configure it through the web configuration portal.
The [Branded Portal](examples/BrandedPortal/) example includes a static SVG, accessible identity text, and a small semantic theme. [Custom Portal Content](examples/CustomPortalContent/) shows the supported parameters, information sections, and home cards without replacing the portal shell.
#### Custom HTML, CSS, Javascript
There are various ways in which you can inject custom HTML, CSS or Javascript into the configuration portal.
The options are:
- inject custom head element
You can use this to any html bit to the head of the configuration portal. If you add a `<style>` element, bare in mind it overwrites the included css, not replaces.
```cpp
wifiManager.setCustomHeadElement("<style>html{filter: invert(100%); -webkit-filter: invert(100%);}</style>");
```
- inject a custom bit of html in the configuration form
```cpp
WiFiManagerParameter custom_text("<p>This is just a text paragraph</p>");
wifiManager.addParameter(&custom_text);
```
- inject a custom bit of html in a configuration form element
Just add the bit you want added as the last parameter to the custom parameter constructor.
```cpp
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly");
## What it provides
- **Captive Wi-Fi setup:** starts an access point only when saved network credentials cannot connect.
- **Responsive portal:** one small portal for Wi-Fi, application fields, information, actions, and firmware update flow.
- **Structured APIs:** C++ configuration and a local JSON protocol for the built-in portal.
- **Product presentation:** title, logo, tagline, and semantic colour tokens without copying the portal HTML.
- **Primary and fallback networks:** an opt-in two-network controller backed by an application-provided store.
- **ESP8266 and ESP32 support:** the package resolves its asynchronous web dependencies for the selected target.
## Choose a guide
| Goal | Guide |
| --- | --- |
| Understand library/application ownership and supported boundaries | [Architecture](docs/ARCHITECTURE.md) |
| Get a device online or recover from missing Wi-Fi | [Provisioning lifecycle](docs/PROVISIONING_LIFECYCLE.md) |
| Brand or constrain the built-in portal | [Portal UI and configuration](docs/PORTAL_UI.md) |
| Add and persist application settings, status, or home cards | [Portal content](docs/PORTAL_CONTENT.md) |
| Configure primary/fallback station profiles | [Station profiles](docs/STATION_PROFILES.md) |
| Surface setup, offline, and connection state in firmware | [Observability](docs/OBSERVABILITY.md) |
| Configure AP, station, scan, or reconnect behaviour | [Network configuration](docs/NETWORK_CONFIGURATION.md) |
| Look up a supported C++ method and its timing | [API reference](docs/API_REFERENCE.md) |
| Understand the built-in portal's local JSON protocol | [Portal API](docs/PORTAL_API.md) |
| Follow deployment-oriented integration patterns | [Recipes](docs/recipes/README.md) |
| Build or flash a complete example | [Examples](examples/README.md) |
| Run documentation and board-free compile checks | [Testing](docs/TESTING.md) |
| Contribute to this fork or prepare a release | [Development](docs/DEVELOPMENT.md) |
## Install
```ini
[common]
lib_deps =
WiFiManager=https://github.com/alexhopeoconnor/WiFiManager.git#v3.2.5
```
#### Filter Networks
You can filter networks based on signal quality and show/hide duplicate networks.
The suffix after `#` is a Git ref. PlatformIO clones the repository and checks out that release tag; GitHub Release assets are unrelated. Arduino IDE users can install this repository as a library checkout.
- If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %;
```cpp
wifiManager.setMinimumSignalQuality(10);
```
will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%;
- You can also remove or show duplicate networks (default is remove).
Use this function to show (or hide) all networks.
```cpp
wifiManager.setRemoveDuplicateAPs(false);
```
#### Debug
Debug is enabled by default on Serial. To disable add before autoConnect
```cpp
wifiManager.setDebugOutput(false);
```
## Troubleshooting
If you get compilation errors, more often than not, you may need to install a newer version of the ESP8266 core for Arduino.
Changes added on 0.8 should make the latest trunk work without compilation errors. Tested down to ESP8266 core 2.0.0. **Please update to version 0.8**
I am trying to keep releases working with release versions of the core, so they can be installed through boards manager, but if you checkout the latest version directly from github, sometimes, the library will only work if you update the ESP8266 core to the latest version because I am using some newly added function.
If you connect to the created configuration Access Point but the configuration portal does not show up, just open a browser and type in the IP of the web portal, by default `192.168.4.1`.
If trying to connect ends up in an endless loop, try to add `setConnectTimeout(60)` before `autoConnect();`. The parameter is timeout to try connecting in seconds.
## Releases
#### 0.11
- a lot more reliable reconnecting to networks
- custom html in custom parameters (for read only params)
- custom html in custom parameter form (like labels)
- custom head element (like custom css)
- sort networks based on signal quality
- remove duplicate networks
##### 0.10
- some css changes
- bug fixes and speed improvements
- added an alternative to waitForConnectResult() for debugging
- changed `setTimeout(seconds)` to `setConfigPortalTimeout(seconds)`
##### 0.9
- fixed support for encoded characters in ssid/pass
##### 0.8
- made it compile on older versions of ESP8266 core as well, tested down to 2.0.0
- added simple example for Custom IP
##### 0.7
- added static IP in station mode
- added example of persisting custom IP to FS config.json
- more option on portal homepage
- added on PlatformIO
##### 0.6
- custom parameters
- prettier
- on demand config portal
- commit #100 :D
##### 0.5
- Added to Arduino Boards Manager - Thanks Max
- moved most stuff to PROGMEM
- added signal quality and a nice little padlock to show which networks are encrypted
##### v0.4 - all of it user contributed changes - Thank you
- added ability to password protect the configuration Access Point
- callback for enter configuration mode
- memory allocation improvements
##### v0.3
- removed the need for EEPROM and works with the 2.0.0 and above stable release of the ESP8266 for Arduino IDE package
- removed restart on save of credentials
- updated examples
##### v0.2
needs the latest staging version (or at least a recent release of the staging version) to work
##### v0.1
works with the staging release ver. 1.6.5-1044-g170995a, built on Aug 10, 2015 of the ESP8266 Arduino library.
### Contributions and thanks
The support and help I got from the community has been nothing short of phenomenal. I can't thank you guys enough. This is my first real attept in developing open source stuff and I must say, now I understand why people are so dedicated to it, it is because of all the wonderful people involved.
__THANK YOU__
[Shawn A](https://github.com/tablatronix)
[Maximiliano Duarte](https://github.com/domonetic)
[alltheblinkythings](https://github.com/alltheblinkythings)
[Niklas Wall](https://github.com/niklaswall)
[Jakub Piasecki](https://github.com/zaporylie)
[Peter Allan](https://github.com/alwynallan)
[John Little](https://github.com/j0hnlittle)
[markaswift](https://github.com/markaswift)
[franklinvv](https://github.com/franklinvv)
[Alberto Ricci Bitti](https://github.com/riccibitti)
[SebiPanther](https://github.com/SebiPanther)
[jonathanendersby](https://github.com/jonathanendersby)
[walthercarsten](https://github.com/walthercarsten)
Sorry if i have missed anyone.
#### Inspiration
- http://www.esp8266.com/viewtopic.php?f=29&t=2520
See the [documentation index](docs/README.md), [examples](examples/README.md), [release history](CHANGELOG.md), and [licence](LICENSE).
-760
View File
@@ -1,760 +0,0 @@
/**************************************************************
WiFiManager is a library for the ESP8266/Arduino platform
(https://github.com/esp8266/Arduino) to enable easy
configuration and reconfiguration of WiFi credentials using a Captive Portal
inspired by:
http://www.esp8266.com/viewtopic.php?f=29&t=2520
https://github.com/chriscook8/esp-arduino-apboot
https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced
Built by AlexT https://github.com/tzapu
Licensed under MIT license
**************************************************************/
#include "WiFiManager.h"
WiFiManagerParameter::WiFiManagerParameter(const char *custom) {
_id = NULL;
_placeholder = NULL;
_length = 0;
_value = NULL;
_customHTML = custom;
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length) {
init(id, placeholder, defaultValue, length, "");
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) {
init(id, placeholder, defaultValue, length, custom);
}
void WiFiManagerParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) {
_id = id;
_placeholder = placeholder;
_length = length;
_value = new char[length + 1];
for (int i = 0; i < length; i++) {
_value[i] = 0;
}
if (defaultValue != NULL) {
strncpy(_value, defaultValue, length);
}
_customHTML = custom;
}
const char* WiFiManagerParameter::getValue() {
return _value;
}
const char* WiFiManagerParameter::getID() {
return _id;
}
const char* WiFiManagerParameter::getPlaceholder() {
return _placeholder;
}
int WiFiManagerParameter::getValueLength() {
return _length;
}
const char* WiFiManagerParameter::getCustomHTML() {
return _customHTML;
}
WiFiManager::WiFiManager() {
}
void WiFiManager::addParameter(WiFiManagerParameter *p) {
_params[_paramsCount] = p;
_paramsCount++;
DEBUG_WM("Adding parameter");
DEBUG_WM(p->getID());
}
void WiFiManager::setupConfigPortal() {
dnsServer.reset(new DNSServer());
server.reset(new ESP8266WebServer(80));
DEBUG_WM(F(""));
_configPortalStart = millis();
DEBUG_WM(F("Configuring access point... "));
DEBUG_WM(_apName);
if (_apPassword != NULL) {
if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) {
// fail passphrase to short or long!
DEBUG_WM(F("Invalid AccessPoint password. Ignoring"));
_apPassword = NULL;
}
DEBUG_WM(_apPassword);
}
//optional soft ip config
if (_ap_static_ip) {
DEBUG_WM(F("Custom AP IP/GW/Subnet"));
WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn);
}
if (_apPassword != NULL) {
WiFi.softAP(_apName, _apPassword);//password option
} else {
WiFi.softAP(_apName);
}
delay(500); // Without delay I've seen the IP address blank
DEBUG_WM(F("AP IP address: "));
DEBUG_WM(WiFi.softAPIP());
/* Setup the DNS server redirecting all the domains to the apIP */
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
dnsServer->start(DNS_PORT, "*", WiFi.softAPIP());
/* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */
server->on("/", std::bind(&WiFiManager::handleRoot, this));
server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true));
server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false));
server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this));
server->on("/i", std::bind(&WiFiManager::handleInfo, this));
server->on("/r", std::bind(&WiFiManager::handleReset, this));
server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check.
server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
server->onNotFound (std::bind(&WiFiManager::handleNotFound, this));
server->begin(); // Web server start
DEBUG_WM(F("HTTP server started"));
}
boolean WiFiManager::autoConnect() {
String ssid = "ESP" + String(ESP.getChipId());
return autoConnect(ssid.c_str(), NULL);
}
boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) {
DEBUG_WM(F(""));
DEBUG_WM(F("AutoConnect"));
// read eeprom for ssid and pass
//String ssid = getSSID();
//String pass = getPassword();
// attempt to connect; should it fail, fall back to AP
WiFi.mode(WIFI_STA);
if (connectWifi("", "") == WL_CONNECTED) {
DEBUG_WM(F("IP Address:"));
DEBUG_WM(WiFi.localIP());
//connected
return true;
}
return startConfigPortal(apName, apPassword);
}
boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) {
//setup AP
WiFi.mode(WIFI_AP_STA);
DEBUG_WM("SET AP STA");
_apName = apName;
_apPassword = apPassword;
//notify we entered AP mode
if ( _apcallback != NULL) {
_apcallback(this);
}
connect = false;
setupConfigPortal();
while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) {
//DNS
dnsServer->processNextRequest();
//HTTP
server->handleClient();
if (connect) {
connect = false;
delay(2000);
DEBUG_WM(F("Connecting to new AP"));
// using user-provided _ssid, _pass in place of system-stored ssid and pass
if (connectWifi(_ssid, _pass) != WL_CONNECTED) {
DEBUG_WM(F("Failed to connect."));
} else {
//connected
WiFi.mode(WIFI_STA);
//notify that configuration has changed and any optional parameters should be saved
if ( _savecallback != NULL) {
//todo: check if any custom parameters actually exist, and check if they really changed maybe
_savecallback();
}
break;
}
if (_shouldBreakAfterConfig) {
//flag set to exit after config after trying to connect
//notify that configuration has changed and any optional parameters should be saved
if ( _savecallback != NULL) {
//todo: check if any custom parameters actually exist, and check if they really changed maybe
_savecallback();
}
break;
}
}
yield();
}
server.reset();
dnsServer.reset();
return WiFi.status() == WL_CONNECTED;
}
int WiFiManager::connectWifi(String ssid, String pass) {
DEBUG_WM(F("Connecting as wifi client..."));
// check if we've got static_ip settings, if we do, use those.
if (_sta_static_ip) {
DEBUG_WM(F("Custom STA IP/GW/Subnet"));
WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn);
DEBUG_WM(WiFi.localIP());
}
//fix for auto connect racing issue
if (WiFi.status() == WL_CONNECTED) {
DEBUG_WM("Already connected. Bailing out.");
return WL_CONNECTED;
}
//check if we have ssid and pass and force those, if not, try with last saved values
if (ssid != "") {
WiFi.begin(ssid.c_str(), pass.c_str());
} else {
if(WiFi.SSID()) {
DEBUG_WM("Using last saved values, should be faster");
//trying to fix connection in progress hanging
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
WiFi.begin();
} else {
DEBUG_WM("No saved credentials");
}
}
int connRes = waitForConnectResult();
DEBUG_WM ("Connection result: ");
DEBUG_WM ( connRes );
//not connected, WPS enabled, no pass - first attempt
if (_tryWPS && connRes != WL_CONNECTED && pass == "") {
startWPS();
//should be connected at the end of WPS
connRes = waitForConnectResult();
}
return connRes;
}
uint8_t WiFiManager::waitForConnectResult() {
if (_connectTimeout == 0) {
return WiFi.waitForConnectResult();
} else {
DEBUG_WM (F("Waiting for connection result with time out"));
unsigned long start = millis();
boolean keepConnecting = true;
uint8_t status;
while (keepConnecting) {
status = WiFi.status();
if (millis() > start + _connectTimeout) {
keepConnecting = false;
DEBUG_WM (F("Connection timed out"));
}
if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) {
keepConnecting = false;
}
delay(100);
}
return status;
}
}
void WiFiManager::startWPS() {
DEBUG_WM("START WPS");
WiFi.beginWPSConfig();
DEBUG_WM("END WPS");
}
/*
String WiFiManager::getSSID() {
if (_ssid == "") {
DEBUG_WM(F("Reading SSID"));
_ssid = WiFi.SSID();
DEBUG_WM(F("SSID: "));
DEBUG_WM(_ssid);
}
return _ssid;
}
String WiFiManager::getPassword() {
if (_pass == "") {
DEBUG_WM(F("Reading Password"));
_pass = WiFi.psk();
DEBUG_WM("Password: " + _pass);
//DEBUG_WM(_pass);
}
return _pass;
}
*/
String WiFiManager::getConfigPortalSSID() {
return _apName;
}
void WiFiManager::resetSettings() {
DEBUG_WM(F("settings invalidated"));
DEBUG_WM(F("THIS MAY CAUSE AP NOT TO START UP PROPERLY. YOU NEED TO COMMENT IT OUT AFTER ERASING THE DATA."));
WiFi.disconnect(true);
//delay(200);
}
void WiFiManager::setTimeout(unsigned long seconds) {
setConfigPortalTimeout(seconds);
}
void WiFiManager::setConfigPortalTimeout(unsigned long seconds) {
_configPortalTimeout = seconds * 1000;
}
void WiFiManager::setConnectTimeout(unsigned long seconds) {
_connectTimeout = seconds * 1000;
}
void WiFiManager::setDebugOutput(boolean debug) {
_debug = debug;
}
void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) {
_ap_static_ip = ip;
_ap_static_gw = gw;
_ap_static_sn = sn;
}
void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) {
_sta_static_ip = ip;
_sta_static_gw = gw;
_sta_static_sn = sn;
}
void WiFiManager::setMinimumSignalQuality(int quality) {
_minimumQuality = quality;
}
void WiFiManager::setBreakAfterConfig(boolean shouldBreak) {
_shouldBreakAfterConfig = shouldBreak;
}
/** Handle root or redirect to captive portal */
void WiFiManager::handleRoot() {
DEBUG_WM(F("Handle root"));
if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
return;
}
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Options");
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_STYLE);
page += _customHeadElement;
page += FPSTR(HTTP_HEAD_END);
page += "<h1>";
page += _apName;
page += "</h1>";
page += F("<h3>WiFiManager</h3>");
page += FPSTR(HTTP_PORTAL_OPTIONS);
page += FPSTR(HTTP_END);
server->send(200, "text/html", page);
}
/** Wifi config page handler */
void WiFiManager::handleWifi(boolean scan) {
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Config ESP");
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_STYLE);
page += _customHeadElement;
page += FPSTR(HTTP_HEAD_END);
if (scan) {
int n = WiFi.scanNetworks();
DEBUG_WM(F("Scan done"));
if (n == 0) {
DEBUG_WM(F("No networks found"));
page += F("No networks found. Refresh to scan again.");
} else {
//sort networks
int indices[n];
for (int i = 0; i < n; i++) {
indices[i] = i;
}
// RSSI SORT
// old sort
// for (int i = 0; i < n; i++) {
// for (int j = i + 1; j < n; j++) {
// if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) {
// //int temp = indices[j];
// //indices[j] = indices[i];
// //indices[i] = temp;
// std::swap(indices[i], indices[j]);
// }
// }
// }
std::sort(indices, indices + n, [](const int & a, const int & b) -> bool
{
return WiFi.RSSI(a) > WiFi.RSSI(b);
});
// remove duplicates ( must be RSSI sorted )
if(_removeDuplicateAPs){
String cssid;
for (int i = 0; i < n; i++) {
if(indices[i] == -1) continue;
cssid = WiFi.SSID(indices[i]);
for (int j = i + 1; j < n; j++) {
if(cssid == WiFi.SSID(indices[j])){
DEBUG_WM("DUP AP: " + WiFi.SSID(indices[j]));
indices[j] = -1; // set dup aps to index -1
}
}
}
}
//display networks in page
for (int i = 0; i < n; i++) {
if(indices[i] == -1) continue; // skip dups
DEBUG_WM(WiFi.SSID(indices[i]));
DEBUG_WM(WiFi.RSSI(indices[i]));
int quality = getRSSIasQuality(WiFi.RSSI(indices[i]));
if (_minimumQuality == -1 || _minimumQuality < quality) {
String item = FPSTR(HTTP_ITEM);
String rssiQ;
rssiQ += quality;
item.replace("{v}", WiFi.SSID(indices[i]));
item.replace("{r}", rssiQ);
if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) {
item.replace("{i}", "l");
} else {
item.replace("{i}", "");
}
//DEBUG_WM(item);
page += item;
delay(0);
} else {
DEBUG_WM(F("Skipping due to quality"));
}
}
page += "<br/>";
}
}
page += FPSTR(HTTP_FORM_START);
char parLength[2];
// add the extra parameters to the form
for (int i = 0; i < _paramsCount; i++) {
if (_params[i] == NULL) {
break;
}
String pitem = FPSTR(HTTP_FORM_PARAM);
if (_params[i]->getID() != NULL) {
pitem.replace("{i}", _params[i]->getID());
pitem.replace("{n}", _params[i]->getID());
pitem.replace("{p}", _params[i]->getPlaceholder());
snprintf(parLength, 2, "%d", _params[i]->getValueLength());
pitem.replace("{l}", parLength);
pitem.replace("{v}", _params[i]->getValue());
pitem.replace("{c}", _params[i]->getCustomHTML());
} else {
pitem = _params[i]->getCustomHTML();
}
page += pitem;
}
if (_params[0] != NULL) {
page += "<br/>";
}
if (_sta_static_ip) {
String item = FPSTR(HTTP_FORM_PARAM);
item.replace("{i}", "ip");
item.replace("{n}", "ip");
item.replace("{p}", "Static IP");
item.replace("{l}", "15");
item.replace("{v}", _sta_static_ip.toString());
page += item;
item = FPSTR(HTTP_FORM_PARAM);
item.replace("{i}", "gw");
item.replace("{n}", "gw");
item.replace("{p}", "Static Gateway");
item.replace("{l}", "15");
item.replace("{v}", _sta_static_gw.toString());
page += item;
item = FPSTR(HTTP_FORM_PARAM);
item.replace("{i}", "sn");
item.replace("{n}", "sn");
item.replace("{p}", "Subnet");
item.replace("{l}", "15");
item.replace("{v}", _sta_static_sn.toString());
page += item;
page += "<br/>";
}
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_SCAN_LINK);
page += FPSTR(HTTP_END);
server->send(200, "text/html", page);
DEBUG_WM(F("Sent config page"));
}
/** Handle the WLAN save form and redirect to WLAN config page again */
void WiFiManager::handleWifiSave() {
DEBUG_WM(F("WiFi save"));
//SAVE/connect here
_ssid = server->arg("s").c_str();
_pass = server->arg("p").c_str();
//parameters
for (int i = 0; i < _paramsCount; i++) {
if (_params[i] == NULL) {
break;
}
//read parameter
String value = server->arg(_params[i]->getID()).c_str();
//store it in array
value.toCharArray(_params[i]->_value, _params[i]->_length);
DEBUG_WM(F("Parameter"));
DEBUG_WM(_params[i]->getID());
DEBUG_WM(value);
}
if (server->arg("ip") != "") {
DEBUG_WM(F("static ip"));
DEBUG_WM(server->arg("ip"));
//_sta_static_ip.fromString(server->arg("ip"));
String ip = server->arg("ip");
optionalIPFromString(&_sta_static_ip, ip.c_str());
}
if (server->arg("gw") != "") {
DEBUG_WM(F("static gateway"));
DEBUG_WM(server->arg("gw"));
String gw = server->arg("gw");
optionalIPFromString(&_sta_static_gw, gw.c_str());
}
if (server->arg("sn") != "") {
DEBUG_WM(F("static netmask"));
DEBUG_WM(server->arg("sn"));
String sn = server->arg("sn");
optionalIPFromString(&_sta_static_sn, sn.c_str());
}
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Credentials Saved");
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_STYLE);
page += _customHeadElement;
page += FPSTR(HTTP_HEAD_END);
page += FPSTR(HTTP_SAVED);
page += FPSTR(HTTP_END);
server->send(200, "text/html", page);
DEBUG_WM(F("Sent wifi save page"));
connect = true; //signal ready to connect/reset
}
/** Handle the info page */
void WiFiManager::handleInfo() {
DEBUG_WM(F("Info"));
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Info");
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_STYLE);
page += _customHeadElement;
page += FPSTR(HTTP_HEAD_END);
page += F("<dl>");
page += F("<dt>Chip ID</dt><dd>");
page += ESP.getChipId();
page += F("</dd>");
page += F("<dt>Flash Chip ID</dt><dd>");
page += ESP.getFlashChipId();
page += F("</dd>");
page += F("<dt>IDE Flash Size</dt><dd>");
page += ESP.getFlashChipSize();
page += F(" bytes</dd>");
page += F("<dt>Real Flash Size</dt><dd>");
page += ESP.getFlashChipRealSize();
page += F(" bytes</dd>");
page += F("<dt>Soft AP IP</dt><dd>");
page += WiFi.softAPIP().toString();
page += F("</dd>");
page += F("<dt>Soft AP MAC</dt><dd>");
page += WiFi.softAPmacAddress();
page += F("</dd>");
page += F("<dt>Station MAC</dt><dd>");
page += WiFi.macAddress();
page += F("</dd>");
page += F("</dl>");
page += FPSTR(HTTP_END);
server->send(200, "text/html", page);
DEBUG_WM(F("Sent info page"));
}
/** Handle the reset page */
void WiFiManager::handleReset() {
DEBUG_WM(F("Reset"));
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Info");
page += FPSTR(HTTP_SCRIPT);
page += FPSTR(HTTP_STYLE);
page += _customHeadElement;
page += FPSTR(HTTP_HEAD_END);
page += F("Module will reset in a few seconds.");
page += FPSTR(HTTP_END);
server->send(200, "text/html", page);
DEBUG_WM(F("Sent reset page"));
delay(5000);
ESP.reset();
delay(2000);
}
void WiFiManager::handle204() {
DEBUG_WM(F("204 No Response"));
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send ( 204, "text/plain", "");
}
void WiFiManager::handleNotFound() {
if (captivePortal()) { // If captive portal redirect instead of displaying the error page.
return;
}
String message = "File Not Found\n\n";
message += "URI: ";
message += server->uri();
message += "\nMethod: ";
message += ( server->method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server->args();
message += "\n";
for ( uint8_t i = 0; i < server->args(); i++ ) {
message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n";
}
server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server->sendHeader("Pragma", "no-cache");
server->sendHeader("Expires", "-1");
server->send ( 404, "text/plain", message );
}
/** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
boolean WiFiManager::captivePortal() {
if (!isIp(server->hostHeader()) ) {
DEBUG_WM(F("Request redirected to captive portal"));
server->sendHeader("Location", String("http://") + toStringIp(server->client().localIP()), true);
server->send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server->client().stop(); // Stop is needed because we sent no content length
return true;
}
return false;
}
//start up config portal callback
void WiFiManager::setAPCallback( void (*func)(WiFiManager* myWiFiManager) ) {
_apcallback = func;
}
//start up save config callback
void WiFiManager::setSaveConfigCallback( void (*func)(void) ) {
_savecallback = func;
}
//sets a custom element to add to head, like a new style tag
void WiFiManager::setCustomHeadElement(const char* element) {
_customHeadElement = element;
}
//if this is true, remove duplicated Access Points - defaut true
void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) {
_removeDuplicateAPs = removeDuplicates;
}
template <typename Generic>
void WiFiManager::DEBUG_WM(Generic text) {
if (_debug) {
Serial.print("*WM: ");
Serial.println(text);
}
}
int WiFiManager::getRSSIasQuality(int RSSI) {
int quality = 0;
if (RSSI <= -100) {
quality = 0;
} else if (RSSI >= -50) {
quality = 100;
} else {
quality = 2 * (RSSI + 100);
}
return quality;
}
/** Is this an IP? */
boolean WiFiManager::isIp(String str) {
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
/** IP to String? */
String WiFiManager::toStringIp(IPAddress ip) {
String res = "";
for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF);
return res;
}
-196
View File
@@ -1,196 +0,0 @@
/**************************************************************
WiFiManager is a library for the ESP8266/Arduino platform
(https://github.com/esp8266/Arduino) to enable easy
configuration and reconfiguration of WiFi credentials using a Captive Portal
inspired by:
http://www.esp8266.com/viewtopic.php?f=29&t=2520
https://github.com/chriscook8/esp-arduino-apboot
https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced
Built by AlexT https://github.com/tzapu
Licensed under MIT license
**************************************************************/
#ifndef WiFiManager_h
#define WiFiManager_h
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <memory>
#undef min
#undef max
#include <algorithm>
extern "C" {
#include "user_interface.h"
}
const char HTTP_200[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
const char HTTP_HEAD[] PROGMEM = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>";
const char HTTP_STYLE[] PROGMEM = "<style>.c{text-align: center;} div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;font-family:verdana;} button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} .q{float: right;width: 64px;text-align: right;} .l{background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==\") no-repeat left center;background-size: 1em;}</style>";
const char HTTP_SCRIPT[] PROGMEM = "<script>function c(l){document.getElementById('s').value=l.innerText||l.textContent;document.getElementById('p').focus();}</script>";
const char HTTP_HEAD_END[] PROGMEM = "</head><body><div style='text-align:left;display:inline-block;min-width:260px;'>";
const char HTTP_PORTAL_OPTIONS[] PROGMEM = "<form action=\"/wifi\" method=\"get\"><button>Configure WiFi</button></form><br/><form action=\"/0wifi\" method=\"get\"><button>Configure WiFi (No Scan)</button></form><br/><form action=\"/i\" method=\"get\"><button>Info</button></form><br/><form action=\"/r\" method=\"post\"><button>Reset</button></form>";
const char HTTP_ITEM[] PROGMEM = "<div><a href='#p' onclick='c(this)'>{v}</a>&nbsp;<span class='q {i}'>{r}%</span></div>";
//const char HTTP_ITEM_PADLOCK[] PROGMEM = "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==' width='13px'/>";
const char HTTP_FORM_START[] PROGMEM = "<form method='get' action='wifisave'><input id='s' name='s' length=32 placeholder='SSID'><br/><input id='p' name='p' length=64 type='password' placeholder='password'><br/>";
const char HTTP_FORM_PARAM[] PROGMEM = "<br/><input id='{i}' name='{n}' length={l} placeholder='{p}' value='{v}' {c}>";
const char HTTP_FORM_END[] PROGMEM = "<br/><button type='submit'>save</button></form>";
const char HTTP_SCAN_LINK[] PROGMEM = "<br/><div class=\"c\"><a href=\"/wifi\">Scan</a></div>";
const char HTTP_SAVED[] PROGMEM = "<div>Credentials Saved<br />Trying to connect ESP to network.<br />If it fails reconnect to AP to try again</div>";
const char HTTP_END[] PROGMEM = "</div></body></html>";
#define WIFI_MANAGER_MAX_PARAMS 10
class WiFiManagerParameter {
public:
WiFiManagerParameter(const char *custom);
WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length);
WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom);
const char *getID();
const char *getValue();
const char *getPlaceholder();
int getValueLength();
const char *getCustomHTML();
private:
const char *_id;
const char *_placeholder;
char *_value;
int _length;
const char *_customHTML;
void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom);
friend class WiFiManager;
};
class WiFiManager
{
public:
WiFiManager();
boolean autoConnect();
boolean autoConnect(char const *apName, char const *apPassword = NULL);
//if you want to always start the config portal, without trying to connect first
boolean startConfigPortal(char const *apName, char const *apPassword = NULL);
// get the AP name of the config portal, so it can be used in the callback
String getConfigPortalSSID();
void resetSettings();
//sets timeout before webserver loop ends and exits even if there has been no setup.
//usefully for devices that failed to connect at some point and got stuck in a webserver loop
//in seconds setConfigPortalTimeout is a new name for setTimeout
void setConfigPortalTimeout(unsigned long seconds);
void setTimeout(unsigned long seconds);
//sets timeout for which to attempt connecting, usefull if you get a lot of failed connects
void setConnectTimeout(unsigned long seconds);
void setDebugOutput(boolean debug);
//defaults to not showing anything under 8% signal quality if called
void setMinimumSignalQuality(int quality = 8);
//sets a custom ip /gateway /subnet configuration
void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn);
//sets config for a static IP
void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn);
//called when AP mode and config portal is started
void setAPCallback( void (*func)(WiFiManager*) );
//called when settings have been changed and connection was successful
void setSaveConfigCallback( void (*func)(void) );
//adds a custom parameter
void addParameter(WiFiManagerParameter *p);
//if this is set, it will exit after config, even if connection is unsucessful.
void setBreakAfterConfig(boolean shouldBreak);
//if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins)
//TODO
//if this is set, customise style
void setCustomHeadElement(const char* element);
//if this is true, remove duplicated Access Points - defaut true
void setRemoveDuplicateAPs(boolean removeDuplicates);
private:
std::unique_ptr<DNSServer> dnsServer;
std::unique_ptr<ESP8266WebServer> server;
//const int WM_DONE = 0;
//const int WM_WAIT = 10;
//const String HTTP_HEAD = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><title>{v}</title>";
void setupConfigPortal();
void startWPS();
const char* _apName = "no-net";
const char* _apPassword = NULL;
String _ssid = "";
String _pass = "";
unsigned long _configPortalTimeout = 0;
unsigned long _connectTimeout = 0;
unsigned long _configPortalStart = 0;
IPAddress _ap_static_ip;
IPAddress _ap_static_gw;
IPAddress _ap_static_sn;
IPAddress _sta_static_ip;
IPAddress _sta_static_gw;
IPAddress _sta_static_sn;
int _paramsCount = 0;
int _minimumQuality = -1;
boolean _removeDuplicateAPs = true;
boolean _shouldBreakAfterConfig = false;
boolean _tryWPS = false;
const char* _customHeadElement = "";
//String getEEPROMString(int start, int len);
//void setEEPROMString(int start, int len, String string);
int status = WL_IDLE_STATUS;
int connectWifi(String ssid, String pass);
uint8_t waitForConnectResult();
void handleRoot();
void handleWifi(boolean scan);
void handleWifiSave();
void handleInfo();
void handleReset();
void handleNotFound();
void handle204();
boolean captivePortal();
// DNS server
const byte DNS_PORT = 53;
//helpers
int getRSSIasQuality(int RSSI);
boolean isIp(String str);
String toStringIp(IPAddress ip);
boolean connect;
boolean _debug = true;
void (*_apcallback)(WiFiManager*) = NULL;
void (*_savecallback)(void) = NULL;
WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS];
template <typename Generic>
void DEBUG_WM(Generic text);
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;
}
};
#endif
+133
View File
@@ -0,0 +1,133 @@
# API reference
This is a task-oriented reference for the supported WiFiManager firmware API. Configure an instance during boot, keep it alive for the application's lifetime, and call process() regularly while WiFiManager may have active work.
For complete end-to-end patterns, use [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md), [Portal content](PORTAL_CONTENT.md), and [Station profiles](STATION_PROFILES.md).
## Lifecycle
| API | Timing and meaning |
| --- | --- |
| autoConnect([apName, apPassword]) | Tries legacy saved station credentials. Returns true if it connected during the call; otherwise starts the enabled portal fallback and returns false. |
| startConfigPortal([apName, apPassword]) | Immediately starts a configuration AP and captive portal. |
| stopConfigPortal() | Immediately stops the configuration portal. |
| startWebPortal() / stopWebPortal() | Starts/stops the portal web server without the configuration-AP flow. |
| process() | Cooperatively services active portal, scan, station-profile, and connection state. Call from loop(); do not treat it as a hard real-time operation or rely on a fixed maximum duration. |
| getConfigPortalSSID() | Returns the current configuration AP name. |
| getConfigPortalActive() / getWebPortalActive() | Reports active configuration or web portal state. |
| setHttpPort(port) | Chooses the portal server port before starting it. |
The application owns any existing HTTP service and must release a shared port before WiFiManager starts its portal.
## Station profiles
| API | Timing and meaning |
| --- | --- |
| setStationProfileStore(store) | Supplies an application-owned durable store; WiFiManager does not own it. |
| startStationConnection([apName, apPassword]) | Loads and begins the stored primary/fallback profile flow. |
| startStationCandidate(candidate[, apName, apPassword]) | Attempts an in-memory profile set; when a store is attached, saves it only after a successful usable connection. |
| saveStationProfiles(profiles) | Deliberately stores a complete profile set without a connection verification attempt. |
| clearStationProfiles() | Clears the store and disconnects the station. |
| setStationRecoveryInterval(milliseconds) | Sets delay before profile recovery attempts after a connection loss. |
| isStationProfileMode(), getStationProfiles(), getStationStatus() | Inspects profile-controller state. |
Profile mode has exactly primary slot 0 and optional fallback slot 1. See [Station profiles](STATION_PROFILES.md) for storage rules and portal fields.
## Application settings and callbacks
| API | Timing and meaning |
| --- | --- |
| portalAddParameter(parameter) | Registers an application-owned WiFiManagerParameter; it must outlive the portal. Returns false if registration fails. |
| portalClearParameters() | Removes registered parameter pointers; it does not delete them. |
| getParameters() / getParametersCount() | Inspects registered parameters. |
| setPreSaveParamsCallback(callback) | Invoked before a parameter-only save. |
| setSaveParamsCallback(callback) | Invoked when parameters save; receives WiFiManagerRequestArgs. |
| setPreSaveConfigCallback(callback) | Invoked before a combined Wi-Fi/config save. |
| setSaveConfigCallback(callback) | Invoked after changed Wi-Fi settings connect successfully, or when break-after-config is enabled. |
| setConfigResetCallback(callback) | Invoked when Wi-Fi settings reset. |
| setAPCallback(callback) / setWebServerCallback(callback) | Invoked after the AP/config portal or web server begins. |
| setConfigPortalTimeoutCallback(callback) | Invoked when a configuration portal times out. |
| setPreOtaUpdateCallback(callback) | Invoked immediately before OTA update handling. |
WiFiManagerRequestArgs provides hasArg(), getArg(), getArgAsInt(), getArgAsFloat(), getArgAsBool(), and count(). It is a callback argument, not durable application configuration.
WiFiManagerParameter constructors accept an ID, label, default value, maximum length, optional custom HTML, and optional label placement. IDs are request field names; keep them stable and simple.
## Portal presentation and policy
| API | Timing and meaning |
| --- | --- |
| setPortalConfig(config) | Applies title, identity text, tagline, SVG logo, and semantic theme. Returns false when a portal is active or the theme is invalid. |
| portalSetPageInfoVisible(), portalSetPageUpdateVisible(), portalSetPageSetupVisible() | Controls built-in page visibility. |
| portalSetActionEraseVisible(), portalSetActionRestartVisible(), portalSetActionExitVisible(), portalSetActionCloseCaptiveVisible(), portalSetActionBackVisible() | Controls built-in action visibility. |
| portalSetLayoutParamsLocation(location) | Selects WiFiPage or SetupPage for custom parameters. |
| portalSetBehaviorCaptivePortalEnabled(), portalSetBehaviorConnectOnSave(), portalSetBehaviorExitAllowed() | Sets portal availability, post-save connection, and exit policy. |
| portalSetBehaviorConnectTimeoutSeconds(), portalSetBehaviorPortalTimeoutSeconds() | Sets connection and portal timeout behavior. |
| portalSetBehaviorAutoReconnect(), portalSetBehaviorApClientCheck(), portalSetBehaviorWebClientCheck() | Sets reconnection and activity/timeout behavior. |
| portalSetFieldPasswordPlaceholderMode(mode) | Selects Hidden, Masked, or Actual password placeholder behavior. |
| portalSetFieldStaticIpVisibility(visibility), portalSetFieldStaticDnsVisibility(visibility) | Selects Hidden, Auto, or Always static-network fields. |
| portalAddInfoSection(), portalClearInfoSections() | Adds/clears copied read-only information sections. |
| portalAddHomeCard(), portalClearHomeCards() | Adds/clears copied overview cards. |
Use [Portal UI and configuration](PORTAL_UI.md) for configuration examples and [Portal content](PORTAL_CONTENT.md) for ownership/persistence rules.
## Connection and network policy
| API | Timing and meaning |
| --- | --- |
| setConfigPortalTimeout(seconds) | Limits configuration portal lifetime; setTimeout() is deprecated alias. |
| setConnectTimeout(seconds), setConnectRetries(count) | Bounds legacy automatic connection attempts. |
| setSaveConnectTimeout(seconds), setSaveConnect(enabled) | Controls and bounds portal save-and-connect behavior. |
| setBreakAfterConfig(enabled) | Exits after a configuration submission even when it did not connect. |
| setEnableConfigPortal(enabled), setDisableConfigPortal(enabled) | Controls autoConnect() fallback/start-stop behavior. |
| setAPClientCheck(enabled), setWebPortalClientCheck(enabled) | Controls portal timeout interaction with AP/web clients. |
| setWiFiAutoReconnect(enabled), setCleanConnect(enabled) | Controls station reconnect and pre-connect disconnect behavior. |
| setHostname(), getWiFiHostname() | Sets/reads the supported target hostname. |
| setWiFiSSIDPrefix(), setWiFiAPChannel(), setWiFiAPHidden() | Configures the temporary setup AP. |
| setAPStaticIPConfig(), setSTAStaticIPConfig() | Configures AP or station static addressing. |
| setCountry(), setMinimumSignalQuality(), setRemoveDuplicateAPs(), setScanDispPerc() | Configures country and scan presentation/filter behavior. |
| setRestorePersistent(enabled) | Controls restoration of the platform Wi-Fi persistence setting. |
See [Network configuration](NETWORK_CONFIGURATION.md) for deployment constraints.
## Scan, state, and diagnostics
| API | Timing and meaning |
| --- | --- |
| requestAsyncScan(forceRefresh) | Requests a non-blocking scan. |
| getScanSnapshot(), getScanRuntimeState(), getScanState() | Returns scan lifecycle state. |
| isScanRunning(), hasValidScanResults() | Reads scan progress and cached-result validity. |
| getScanResults() | Returns WiFiManager-owned cached visible results; do not retain references after a new scan or portal shutdown. |
| getRSSIasQuality(rssi) | Converts RSSI to WiFiManager quality. |
| getLastConxResult(), getWLStatusString(), getModeString() | Formats connection and mode diagnostics. |
| hasEnteredConfigPortal(), getConfigPortalConnectState() | Reads portal-session history and last submission state. |
| isConfigPortalConnectPending(), didConfigPortalConnectSucceed(), didConfigPortalConnectFail() | Reads concise portal connection status. |
| getConfigPortalConnectStatus(), getConfigPortalConnectMessage() | Returns platform status and message for the last portal attempt. |
| setEventCallback(callback) | Receives lifecycle notifications; use getters for detailed state. |
| setLogEnabled(), setLogPrefix(), setLogOutput(), setLogSink(), getLogSink() | Configures log output and optional application-owned sink. |
See [Observability](OBSERVABILITY.md) for event meanings and product feedback.
## Reset and low-level helpers
| API | Meaning |
| --- | --- |
| disconnect() | Disconnects without erasing saved configuration. |
| resetSettings() | Clears legacy Wi-Fi settings. |
| erase([optional]) | Erases Wi-Fi configuration. |
| reboot() | Reboots the target. |
| getWiFiIsSaved(), getWiFiSSID(), getWiFiPass() | Reads legacy saved/current station values; handle credentials carefully. |
| getDefaultAPName() | Returns the default generated AP name. |
| debugSoftAPConfig(), debugPlatformInfo() | Writes diagnostic information. |
| htmlEntities(text[, whitespace]) | Escapes text for WiFiManager HTML rendering. |
| preloadWiFi(ssid, password) | Intended for fixtures or controlled integrations that deliberately skip normal station configuration. |
getServer() and getDNSServer() are exposed for testing/host integration. They are not a supported way for product firmware to add private portal routes or mutate the built-in server.
## Continue
- [Architecture and boundaries](ARCHITECTURE.md)
- [Portal API](PORTAL_API.md)
- [Examples](../examples/README.md)
Back to [documentation](README.md) · [project overview](../README.md).
+93
View File
@@ -0,0 +1,93 @@
# Integrating WiFiManager
WiFiManager runs device-local Wi-Fi setup. It tries station Wi-Fi, temporarily
hosts an access point and portal when the device cannot connect, and then lets
the firmware continue its normal work. It is not a cloud service,
remote-management system, or companion-app framework.
## What WiFiManager handles
| WiFiManager handles | Your firmware handles |
| --- | --- |
| Temporary AP, captive DNS, portal routes, Wi-Fi connection attempts, portal session state | Durable application settings, schema migration, product services, LEDs/display, reboot policy, telemetry, and access-control decisions |
| Wi-Fi credentials in the legacy flow, or profile-selection policy in station-profile mode | The durable station-profile store when profile mode is enabled |
| Structured portal presentation and built-in Wi-Fi/settings forms | Product-specific validation and the persistence of product settings |
| The local portal JSON protocol | Any separate product HTTP API or local web server |
This lets a firmware decide what configuration it needs without copying the
portal, captive-network behavior, or Wi-Fi connection flow.
## Typical boot sequence
~~~text
Firmware boot
│
├─ Load and migrate application settings
├─ Register portal branding, policy, and application parameters
├─ Start a WiFiManager connection flow
│ ├─ Connected: start normal application services
│ └─ Not connected: temporary AP + local portal
├─ Service wifi.process() while a portal or profile controller is active
└─ Persist application data and decide when to restart or resume services
~~~
Register portal configuration before calling autoConnect(), startConfigPortal(), startWebPortal(), or a station-profile start method. The active portal uses an immutable response model so that asynchronous requests cannot see a partially changed UI.
## Customise the built-in portal
WiFiManager can set product identity, named theme values, page/action
visibility, parameters, information sections, and home cards. Use its public
C++ configuration and content APIs for those tasks:
~~~cpp
WiFiManagerPortalConfig portal;
portal.title = WiFiManagerPortalText::progmem(PSTR("Set up sensor"));
wifi.setPortalConfig(portal);
~~~
The built-in portal still owns its HTML shell, routes, forms, navigation, and
captive behavior. It does not provide:
- arbitrary portal HTML-shell replacement;
- raw CSS or JavaScript injection;
- route replacement or navigation injection;
- a cloud API or supported mobile-companion integration surface.
The `/api/*` routes are the built-in portal's browser protocol. They are useful
for portal maintenance and tests, but are not a product firmware or
companion-app integration API. If a product needs a reusable portal capability,
add one focused public WiFiManager C++ API and test it on ESP8266 and ESP32.
## Application-service handoff
WiFiManager's portal server uses its configured HTTP port, 80 by default. A product already using that port must explicitly release it before WiFiManager starts a portal. Conversely, the application decides when its normal web service is safe to start after a successful connection.
Release an application-owned server before starting the portal:
~~~cpp
void beginRecovery() {
stopApplicationWebServer(); // Releases port 80 owned by the product.
wifi.startConfigPortal("Device Setup", "setup-password");
}
~~~
The application may instead use a different WiFiManager HTTP port through setHttpPort(); document that address for installers because the captive-portal redirect and station handoff will include the selected port.
## Data lifetime and persistence
WiFiManagerPortalConfig text and SVG values are non-owning. Keep RAM or PROGMEM source data alive for the entire firmware lifetime. WiFiManagerParameter instances are application-owned and must outlive the portal. Portal information sections and home cards are copied when registered.
A station-profile store is also application-owned. Its load(), save(), and clear() methods are responsible for durable storage and error handling. The profile controller chooses and verifies networks; it does not own the store or an application's migration format.
## Security and operator expectations
The configuration portal is intended for local setup. Use a Wi-Fi-valid AP password in deployed products, do not put secrets in information cards or logs, and do not expose password placeholders unless there is an explicit local-installation requirement. The portal's JSON endpoints are the built-in UI's device-local protocol; they are not an authenticated remote-management API.
## Continue
- [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md)
- [Portal UI and configuration](PORTAL_UI.md)
- [Portal content](PORTAL_CONTENT.md)
- [Integration recipes](recipes/README.md)
Back to [documentation](README.md) · [project overview](../README.md).
+120
View File
@@ -0,0 +1,120 @@
# Development and releases
Released consumers use the public Git tag. While changing WiFiManager and a sibling dependency together, point an ignored local PlatformIO override at a `symlink://` or `file://` checkout rather than changing tracked application dependencies.
```ini
lib_deps =
WiFiManager=symlink:///path/to/WiFiManager
```
## Target pins
WiFiManager uses one maintained ESP32 test lane:
| Lane | pioarduino platform | Purpose |
| --- | --- | --- |
| `esp32` | `55.03.311` / Arduino-ESP32 3.3.11 | maintained baseline |
This is a test-target policy, not a library-manifest dependency: a consuming
application chooses its own `platform` and must validate the complete
framework/toolchain stack. Do not let a shared global PlatformIO cache choose
framework metadata or a compiler implicitly, and do not override just the
toolchain to repair a cache mismatch. Each pioarduino platform owns its
matching framework, uploader, and compiler package set.
Core 3 Wi-Fi builds need the C++14, `SOC_WIFI_SUPPORTED`, and `Network/src`
settings in this repository's `platformio.ini`; keep those settings together
when adding an ESP32 environment. The portal OTA fixture and every guided
example use this 3.3.11 ESP32 baseline.
ESP8266 test environments pin framework commit `521ae60` for the upstream
Postmortem large-jump linker fix. The exact rationale and update rule are in
the shared [ESP8266 linker-workaround note](https://github.com/alexhopeoconnor/arduino-home-assistant/blob/main/docs/ESP8266-LINKER-WORKAROUND.md).
For the pioarduino release-to-Core mapping and cache-collision diagnosis, see
[DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md).
`./scripts/test.sh` and `./tools/portal-hardware ota --platform esp32` use the
PlatformIO Core/cache shared by the maintained framework repositories,
defaulting to `${XDG_CACHE_HOME:-$HOME/.cache}/arduino-framework-platformio/core-3.3.11`.
WiFiManager, DeviceFramework, DFTE, and ArduinoHA pin this same graph, so this
avoids downloading the same Core 3.3.11 inputs for each repository while
keeping pioarduino's package-form `esptool` and generated environment separate
from stale global `tool-esptoolpy` metadata. Override the location with
`WIFIMANAGER_PLATFORMIO_CORE_DIR`,
`WIFIMANAGER_PLATFORMIO_PACKAGES_DIR`, and
`WIFIMANAGER_PLATFORMIO_CACHE_DIR` when space belongs elsewhere or an isolated
diagnosis is needed. The first shared install is several GiB; reserve at least
4 GiB plus cache headroom. It is persistent and is never cleared by normal test
commands.
For a disposable cache investigation, point that variable at an exact temporary
directory, run the affected command, inspect the resolved graph, then remove
only that directory:
```bash
wm_pio_core="$(mktemp -d /tmp/wifimanager-pio-XXXXXX)"
WIFIMANAGER_PLATFORMIO_CORE_DIR="$wm_pio_core" \
./scripts/test.sh compile --platform esp32
rm -rf -- "$wm_pio_core"
```
Start a release with `bump-version.sh`. It updates package metadata and canonical installation snippets, then creates the changelog section. Replace its generated TODO with the release summary and update any behavioural documentation before running:
```bash
./scripts/bump-version.sh vMAJOR.MINOR.PATCH
# Replace the generated CHANGELOG TODO with the release summary.
./scripts/check-docs.sh
./scripts/test.sh compile --platform esp8266
./scripts/test.sh compile --platform esp32
./scripts/test.sh unity --platform esp8266
./scripts/test.sh unity --platform esp32
./scripts/test.sh examples --platform esp8266
./scripts/test.sh examples --platform esp32
./scripts/test.sh ota-fixtures --platform esp8266
./scripts/test.sh ota-fixtures --platform esp32
./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag
```
When a physical ESP8266 and ESP32 are available, include their local lifecycle tests in the release gate. These tests remain opt-in because they flash the selected board and use its actual radio:
~~~bash
./scripts/test.sh hardware --platform esp8266 --port /dev/serial/by-id/usb-...
./scripts/test.sh hardware --platform esp32 --port /dev/serial/by-id/usb-...
~~~
When a physical ESP8266 or ESP32 and a spare USB Wi-Fi adapter are available,
run the Docker portal test harness as an additional release-gate check. It is
opt-in because it flashes the selected board and temporarily joins its AP, but
it refuses the host default-route adapter and leaves Docker responsible only
for browser/API testing:
```bash
./tools/portal-hardware run --platform esp8266 --port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165
```
From an SSH/headless shell, the portal command may ask once for scoped
NetworkManager sudo authorization before the selected board is erased. This is
host setup, not a test secret; never add a sudo value to an env file or run the
whole runner as root. See [Testing](TESTING.md#networkmanager-authorization)
for the direct/Polkit and scoped-sudo behavior.
See [Testing](TESTING.md#docker-portal-test-harness) for cleanup, artifacts, and
optional station handoff credentials.
Run the portal HTTP OTA A/B test harness separately when a spare adapter and 4 MB
test board are available. It erases the selected board's flash, serial-flashes
A, and uses the real browser update form to upload B; do not replace its
automatic-reboot assertion with a manual reset:
```bash
./tools/portal-hardware ota --platform esp8266 --port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165
```
See [Portal HTTP OTA A/B test harness](TESTING.md#portal-http-ota-ab-test-harness) for
the partition, artifact, final-board-state, and adapter rules.
Push the branch and annotated tag. GitHub Actions repeats the board-free compile checks, validates the package, and creates a GitHub Release using that version’s changelog section. The workflow does not publish to the PlatformIO Registry.
Back to [documentation](README.md) · [project overview](../README.md).
+38
View File
@@ -0,0 +1,38 @@
# Getting started
WiFiManager owns station credential recovery and a temporary configuration portal. Keep one instance for the life of the application.
```cpp
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager wifi;
void setup() {
Serial.begin(115200);
wifi.setConfigPortalTimeout(180); // Stop the portal after three minutes.
wifi.autoConnect("Example Setup", "change-me");
}
void loop() {
wifi.process(); // Keeps the portal responsive when setup is needed.
// Normal work begins after autoConnect succeeds.
}
```
`autoConnect()` first tries stored station credentials. If that cannot connect, it starts the AP and portal with the supplied name and password, then returns `false`; call `process()` from `loop()` so that portal can run. `setConfigPortalTimeout(180)` limits that portal to three minutes; pass `0` (the default) to leave it open. Use a Wi-Fi-valid AP password.
## PlatformIO dependency
```ini
lib_deps =
WiFiManager=https://github.com/alexhopeoconnor/WiFiManager.git#v3.2.5
```
The package includes the asynchronous web and TCP dependencies required by the selected ESP8266 or ESP32 target. Add WiFiManager as the application’s direct dependency; do not copy its internal dependency list into your project.
Next: build [Basic Portal](../examples/BasicPortal/), then read [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md) for return-state, timeout, and recovery rules.
For product presentation and settings, continue with [Portal UI and configuration](PORTAL_UI.md) and [Portal content](PORTAL_CONTENT.md).
Back to [documentation](README.md) · [project overview](../README.md).
+107
View File
@@ -0,0 +1,107 @@
# Network configuration
These APIs configure WiFiManager's AP, station, scan, and reconnection behavior. Set them during boot, before starting a connection or portal flow, so an installer sees one consistent configuration.
The current ESP8266 and ESP32 implementations apply AP static addressing through WiFi.softAPConfig() and station static addressing through WiFi.config(). Station static configuration is used by legacy connections, portal save-and-connect attempts, and the station-profile controller.
This page is an advanced deployment reference. Use these settings only when the local network and the product's operating policy require them; WiFiManager's defaults are appropriate for many devices.
## Access-point setup network
| API | Purpose |
| --- | --- |
| setWiFiSSIDPrefix(prefix) | Changes the prefix used by an automatically generated AP name. |
| setWiFiAPChannel(channel) | Selects the setup AP Wi-Fi channel. |
| setWiFiAPHidden(hidden) | Hides or advertises the setup AP SSID. |
| setAPStaticIPConfig(ip, gateway, subnet) | Sets the AP-side portal address configuration. |
| setHttpPort(port) | Uses a non-default portal HTTP port. |
| setHostname(name) | Sets the station/AP hostname as supported by the target. |
| getConfigPortalSSID() / getDefaultAPName() | Reports the actual/current setup AP name. |
A hidden AP can make field setup harder because an installer must enter the SSID manually. Treat it as a deployment decision, not a general security control. If setHttpPort() changes the default, publish the full portal address in the product's installation procedure.
## A fixed setup-portal address
Give the setup AP a fixed address when an installer procedure needs a stable local portal address:
~~~cpp
wifi.setAPStaticIPConfig(
IPAddress(192, 168, 8, 1),
IPAddress(192, 168, 8, 1),
IPAddress(255, 255, 255, 0));
wifi.setWiFiAPChannel(6);
wifi.setWiFiAPHidden(false);
~~~
This is applied before WiFiManager starts its SoftAP. The usual portal address becomes http://192.168.8.1/. If setHttpPort() selects a non-default port, include that port in the installer instructions and expect the station handoff URL to include it too.
## Station address and credential behavior
Use a station static address only when the network owner has reserved and documented it:
~~~cpp
wifi.setSTAStaticIPConfig(
IPAddress(192, 168, 20, 50),
IPAddress(192, 168, 20, 1),
IPAddress(255, 255, 255, 0),
IPAddress(192, 168, 20, 1));
~~~
| API | Purpose |
| --- | --- |
| setSTAStaticIPConfig(ip, gateway, subnet[, dns]) | Supplies a station static address and optional DNS server. |
| setCleanConnect(enabled) | Disconnects before connecting; use when the product requires a fresh association. |
| setRestorePersistent(enabled) | Controls restoration of the platform Wi-Fi persistence preference. |
| setWiFiAutoReconnect(enabled) | Enables Wi-Fi auto-reconnect behavior. |
| setCountry(countryCode) | Applies the supported Wi-Fi country setting. |
| disconnect() | Disconnects without erasing persistent settings. |
| resetSettings() | Clears legacy saved Wi-Fi settings. |
| erase([optional]) | Erases Wi-Fi configuration and schedules the configured reset behavior. |
Static-IP entry fields can be configured independently of the network setting:
~~~cpp
wifi.portalSetFieldStaticIpVisibility(PortalFieldVisibility::Auto);
wifi.portalSetFieldStaticDnsVisibility(PortalFieldVisibility::Hidden);
~~~
Auto shows these fields when a static station configuration is already in use; Always makes them visible; Hidden suppresses them. Do not expose static network controls in a general user portal unless the installer is expected to manage those values.
## Scan behavior
WiFiManager's portal schedules asynchronous scans. Firmware that needs its own nearby-network status can request and inspect the same cached scan state:
~~~cpp
wifi.requestAsyncScan();
if (wifi.hasValidScanResults()) {
for (const auto& network : wifi.getScanResults()) {
Serial.printf("%s: %ld dBm\n", network.ssid.c_str(), network.rssi);
}
}
~~~
| API | Purpose |
| --- | --- |
| requestAsyncScan(forceRefresh) | Queues a scan without blocking the application loop. |
| getScanSnapshot() / getScanRuntimeState() | Returns the complete scan lifecycle snapshot. |
| getScanState() / isScanRunning() / hasValidScanResults() | Provides concise status checks. |
| getScanResults() | Returns the cached visible network list. |
| setMinimumSignalQuality(quality) | Filters low-quality scan results. |
| setRemoveDuplicateAPs(enabled) | Controls duplicate SSID removal. |
| setScanDispPerc(enabled) | Uses percentage rather than quality icons in the portal. |
| getRSSIasQuality(rssi) | Converts RSSI for display. |
WiFiManager owns the scan cache. It keeps the cache and its allocation while a portal is active so nearby networks can be rendered without repeated allocation churn; it clears and releases that storage when the portal fully closes. Treat getScanResults() as a snapshot and do not retain references, iterators, or pointers across a new scan or portal shutdown.
## Connection and timeout policy
See [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md) for setConfigPortalTimeout(), setConnectTimeout(), setConnectRetries(), setSaveConnectTimeout(), setSaveConnect(), and the portal-prefixed behavior equivalents. These settings define recovery behavior; they should reflect how long an on-site installer can reasonably work and how long the product can remain offline.
## Continue
- [Portal UI and configuration](PORTAL_UI.md)
- [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md)
- [API reference](API_REFERENCE.md)
Back to [documentation](README.md) · [project overview](../README.md).
+89
View File
@@ -0,0 +1,89 @@
# Observability
WiFiManager exposes connection and portal state so product firmware can provide useful local feedback. Use getters as the source of truth and treat callbacks as notifications.
A device framework consuming WiFiManager uses this pattern to distinguish normal operation, offline recovery, active setup, and a successful portal connection before it changes LED state or starts product services.
## Portal state
| API | Meaning |
| --- | --- |
| getConfigPortalActive() | A configuration AP/portal is currently active. |
| getWebPortalActive() | A manually started portal web service is active. |
| hasEnteredConfigPortal() | Setup has been entered at least once since boot. |
| getConfigPortalConnectState() | Idle, queued, waiting, success, or failed for the most recent portal connection attempt. |
| isConfigPortalConnectPending() | A concise check for queued or waiting connection work. |
| didConfigPortalConnectSucceed() / didConfigPortalConnectFail() | Result checks for the most recent portal submission. |
| getConfigPortalConnectStatus() | Platform Wi-Fi status for that attempt. |
| getConfigPortalConnectMessage() | Human-readable status; suitable for logs or local display. |
| getLastConxResult() / getWLStatusString() | Legacy and general Wi-Fi connection result helpers. |
Use these values to drive product feedback. Do not derive state by scraping portal HTML or assuming that an autoConnect() false return means the portal session failed.
## Events
setEventCallback() installs an optional notification hook:
~~~cpp
wifi.setEventCallback([](WiFiManager::wm_event_t event) {
switch (event) {
case WiFiManager::WM_EVENT_PORTAL_STARTED:
setIndicator(IndicatorState::Setup);
break;
case WiFiManager::WM_EVENT_PORTAL_CONNECT_SUCCESS:
setIndicator(IndicatorState::ConnectingComplete);
break;
case WiFiManager::WM_EVENT_STATION_LINK_LOST:
setIndicator(IndicatorState::Offline);
break;
default:
break;
}
});
~~~
| Event | Product use |
| --- | --- |
| WM_EVENT_PORTAL_STARTED / WM_EVENT_PORTAL_STOPPED | Begin or end setup feedback. |
| WM_EVENT_PORTAL_CONNECT_QUEUED / START / SUCCESS / FAILED | Show progress and result for a portal-submitted network. |
| WM_EVENT_STATION_PROFILE_ATTEMPT / CONNECTED / FAILED | Track profile-controller progress. |
| WM_EVENT_STATION_LINK_LOST / BACKOFF | Show recovery behavior after an established connection drops. |
| WM_EVENT_STATION_PROFILES_CLEARED | Reconcile product state after profiles are cleared. |
Events are intentionally small and do not carry credentials or mutable request state. Read the relevant getter inside the callback when more detail is needed.
## Station-profile status
When using profile mode, getStationStatus() reports:
- state: idle, loading, attempting, switching, connected, backoff, or portal;
- activeSlot and attemptedSlot;
- configuredProfiles;
- wifiStatus and a human-readable message;
- whether the last connection was a candidate;
- whether the profile store could not save a successful candidate.
A store-save failure is operationally important: the device may be connected now but will not necessarily reconnect after a restart. Preserve that distinction in an LED, display, or operator log.
## Logging
WiFiManager logs to its configured Print output unless a WiFiManagerLogSink is supplied.
~~~cpp
wifi.setLogPrefix("[network] ");
wifi.setLogOutput(true, WiFiManagerLogLevel::Info);
~~~
WiFiManagerLogLevel ranges from Silent through Error, Warn, Info, Debug, and Trace. A custom WiFiManagerLogSink receives a WiFiManagerLogMessage instead of the Print output. Redact SSIDs and never log passwords, portal form values, or product secrets into a remotely collected log.
## Scan status
For nearby-network progress, use getScanState(), isScanRunning(), hasValidScanResults(), and getScanResults(); see [Network configuration](NETWORK_CONFIGURATION.md#scan-behavior). The portal API exposes a matching local scan-status representation for the built-in UI.
## Continue
- [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md)
- [Station profiles](STATION_PROFILES.md)
- [API reference](API_REFERENCE.md)
Back to [documentation](README.md) · [project overview](../README.md).
+118
View File
@@ -0,0 +1,118 @@
# Built-in portal browser protocol
This device-local protocol is used by WiFiManager's built-in portal shell. It
is useful when maintaining that UI or writing portal-focused tests. It is not a
cloud API, remote-management interface, or supported companion-app integration
surface.
The portal is unauthenticated local setup infrastructure. Do not expose it as a product's general application API, and do not infer a security boundary from hiding an action in the UI.
## Contract version and format
GET /api/bootstrap returns contractVersion 3. The built-in portal uses that versioned response; tests that assert its shape should feature-detect fields rather than assume undocumented portal HTML or JSON properties.
All documented API responses are JSON with no-cache headers. The server also sends permissive CORS headers for the built-in portal implementation; that does not change the local-only security boundary or make these routes a remote integration contract.
## Route inventory
| Method | Route | Built-in portal purpose |
| --- | --- | --- |
| GET | / | Serves the one portal HTML shell. |
| GET | /api/bootstrap | Reads product brand, portal context, page/action visibility, layout, scan summary, and overview cards. |
| GET | /api/wifi/scan-status | Reads async scan state and visible nearby networks. |
| POST | /api/wifi/scan | Queues a forced asynchronous scan; returns 202. |
| GET | /api/wifi/meta | Reads Wi-Fi form fields, static-IP fields, parameters on the Wi-Fi page, and profile metadata when enabled. |
| POST | /api/wifi/save | Submits Wi-Fi fields, applicable parameters, and optionally a station-profile set. |
| GET | /api/wifi/connect-status | Reads the result of the most recent portal save-and-connect attempt. |
| POST | /api/wifi/connect-complete | Acknowledges that the built-in portal has received the successful station handoff address. |
| POST | /api/portal/timeout-reset | Restarts an active configured portal timeout. |
| GET | /api/params | Reads parameters for the separate Setup page. |
| POST | /api/params/save | Saves Setup-page parameters. |
| GET | /api/info | Reads device/Wi-Fi info, copied information sections, and visible actions. |
| GET | /api/status | Reads a short plain-text status summary in JSON. |
| POST | /api/device/restart | Schedules a target restart. |
| POST | /api/device/erase | Erases Wi-Fi configuration and schedules restart when successful. |
| POST | /api/portal/close | Disables captive-portal detection for the active session. |
| POST | /api/portal/exit | Requests portal exit when portal exit is allowed. |
| POST | /u | Receives multipart firmware upload and returns JSON completion status. |
Unknown routes are redirected only while captive-portal handling is active; otherwise they return the normal not-found result.
## Bootstrap and read models
Bootstrap includes a brand object (title, tagline, logo SVG, and logo alt text), a context object (portal activity, timeout remaining, identity text, status summary, scan state), visible pages/actions, parameter layout, and copied home cards.
Wi-Fi form metadata is intentionally separate:
- Legacy mode returns SSID/password fields, configured static fields, and parameters when the layout places them on the Wi-Fi page.
- Profile mode returns primary/fallback profile metadata, the active slot, controller state, static fields, and applicable parameters.
- Password values are never returned. Legacy password placeholder behavior is controlled by portalSetFieldPasswordPlaceholderMode().
GET /api/params exposes all registered parameters for the separate Setup page, plus whether the back action is visible. GET /api/info exposes device/Wi-Fi facts, copied information sections, and action visibility. GET /api/status returns a short human-readable text field.
## Wi-Fi submit and connection handoff
POST /api/wifi/save accepts form fields. In legacy mode:
| Field | Meaning |
| --- | --- |
| s | Station SSID. |
| p | Station password. A password without an SSID is treated as a password change for the stored SSID. |
| ip, gw, sn, dns | Optional station static IP, gateway, subnet, and DNS values when those fields are visible. |
| Registered parameter ID or param_N | Application parameter values when parameters are placed on the Wi-Fi page. |
A normal accepted save returns 202 and directs the portal to poll /api/wifi/connect-status. The status response is:
~~~json
{
"state": "success",
"message": "human readable status",
"wifiStatus": "WL_CONNECTED",
"stationIp": "192.168.1.42",
"redirectUrl": "http://192.168.1.42/"
}
~~~
`state` is one of `idle`, `waiting`, `success`, or `failed`. The example shows
a successful join; `stationIp` and `redirectUrl` are present only in that state.
If the portal server is not on port 80, `redirectUrl` includes that port. When
connect-on-save is disabled, a saved configuration has no station address and
the built-in portal remains open.
After observing success, the built-in portal POSTs /api/wifi/connect-complete. A 409 response means successful handoff is not ready; otherwise WiFiManager keeps the portal alive briefly, receives the acknowledgement, and then closes after a grace delay. Browser captive redirects can still fail, so the portal keeps the station address visible.
When portalSetBehaviorConnectOnSave(false) or setSaveConnect(false) is selected, a Wi-Fi save does not start this station connection/handoff flow.
## Profile-mode submit
In profile mode, POST /api/wifi/save accepts s0/p0 for primary and s1/p1 for fallback. Primary must be non-empty. A blank p0 or p1 preserves an existing password; clear0 or clear1 explicitly clears a password for an open network.
By default, WiFiManager attempts the submitted candidate and returns 202 for status polling. With stationAction=save, it writes the submitted profile set for a later connection attempt and returns 200. See [Station profiles](STATION_PROFILES.md) for candidate verification and storage behavior.
## Parameter submit
POST /api/params/save sends registered application parameter fields and returns a successful acknowledgement after the registered save callbacks run. A parameter can be addressed by its stable ID or by param_N index. WiFiManager does not define application validation or durable-storage semantics; the consuming application owns both.
## Actions and error states
| Route | Success | Important non-success response |
| --- | --- | --- |
| POST /api/wifi/scan | 202 with accepted/queued state | Scan result arrives through scan-status. |
| POST /api/wifi/save | 202 for queued connection, or 200 for profile save-for-later | 400 for invalid Wi-Fi/profile input; 500 when an explicit profile store save fails. |
| POST /api/wifi/connect-complete | 200 after successful station handoff | 409 when success/address is not ready. |
| POST /api/portal/timeout-reset | 200 with timeout seconds remaining | 409 when no active finite portal timeout exists. |
| POST /api/device/restart | 200, restart scheduled | The target restarts shortly after the response. |
| POST /api/device/erase | 200, erase/restart scheduled | 500 when erase fails. |
| POST /api/portal/close | 200, captive detection disabled | The portal server itself remains subject to its normal lifecycle. |
| POST /api/portal/exit | 200, exit scheduled | 403 when exit is not allowed. |
| POST /u | 200, firmware update/restart scheduled | 500 with update failure detail. |
## Using this protocol safely
Use this document to understand and test WiFiManager's own portal behavior.
Applications that need a product web API should host and secure that API after
WiFiManager has completed its provisioning role. Do not scrape the portal shell,
depend on undocumented JSON fields, or add routes through WiFiManager's testing
server accessor.
Back to [documentation](README.md) · [project overview](../README.md).
+107
View File
@@ -0,0 +1,107 @@
# Portal content and application settings
Use the built-in portal to collect small product settings alongside Wi-Fi credentials. WiFiManager owns the form and its temporary values; the application validates and persists its own settings.
This matches the product-firmware pattern used by real consumers: load configuration first, expose its current values through WiFiManagerParameter objects, then persist valid submitted values through the application's configuration layer.
## End-to-end pattern
~~~cpp
#include <WiFiManager.h>
constexpr int kBrokerHostLength = 64;
WiFiManager wifi;
WiFiManagerParameter brokerHost(
"broker_host", "MQTT broker", "", kBrokerHostLength);
void setupPortal() {
// The application has already loaded settings before this point.
brokerHost.setValue(settings.mqttHost.c_str(), kBrokerHostLength);
wifi.portalAddParameter(&brokerHost);
wifi.setSaveParamsCallback([](WiFiManager::WiFiManagerRequestArgs) {
const String candidate = brokerHost.getValue();
if (!isValidHostname(candidate)) {
logInvalidBroker(candidate);
return; // Keep the application's known-good stored value.
}
settings.mqttHost = candidate;
saveApplicationSettings(settings);
});
}
~~~
Call setupPortal() after loading application settings and before a WiFiManager connection or portal start method. The callback receives a copy of the submitted request arguments; use getArg(), getArgAsInt(), getArgAsFloat(), or getArgAsBool() when the application needs request-level values.
The save-parameters callback is a notification hook, not a validation-response API. Its return type cannot turn the built-in UI's success response into a form error. Validate before using the candidate, preserve known-good data when persistence fails, and provide product-specific feedback through the application's own UI/logging policy.
## Parameter rules
| Rule | Why it matters |
| --- | --- |
| Keep each WiFiManagerParameter alive while the portal can use it. | WiFiManager stores the parameter pointer; it does not take ownership. |
| Use a stable ID without spaces or special characters. | The ID is used in portal requests. |
| Choose a bounded value length. | It defines the editable buffer length. |
| Register parameters before opening the portal. | Active portal responses use their established form model. |
| Treat submitted text as untrusted application input. | Portal input is not application validation or durable storage. |
Use portalClearParameters() only before opening a portal when rebuilding a complete form. It removes registered parameter pointers; it does not destroy application-owned parameter objects.
## Where settings appear
By default, custom parameters appear on the Wi-Fi page. To put them on the separate Setup page:
~~~cpp
wifi.portalSetLayoutParamsLocation(PortalParamsLocation::SetupPage);
~~~
Use the Wi-Fi page for a small setting that is naturally provisioned with network credentials. Use the Setup page when product configuration needs its own step. Page visibility and layout are part of the structured portal policy; see [Portal UI and configuration](PORTAL_UI.md).
## Read-only product context
Use information sections for labelled facts and home cards for a short overview or callout:
~~~cpp
PortalInfoSection deviceInfo;
deviceInfo.id = "device";
deviceInfo.title = "Device";
deviceInfo.items = {
{"firmware", "Firmware", firmwareVersion},
{"sensor", "Sensor", sensorReady ? "Ready" : "Checking"},
};
wifi.portalAddInfoSection(deviceInfo);
PortalHomeCard installerHint;
installerHint.id = "installer-hint";
installerHint.title = "Before you begin";
installerHint.kind = PortalHomeCardKind::Callout;
installerHint.text = "Connect the device to its final local network.";
wifi.portalAddHomeCard(installerHint);
~~~
Information sections and cards are copied at registration. Do not place secrets, passwords, API tokens, or personally identifying values in them.
## Save callbacks
| Callback | Use |
| --- | --- |
| setPreSaveParamsCallback() | Observe a parameter-only save before the normal parameter callback. |
| setSaveParamsCallback(args) | Read, validate, and persist application settings after a parameter save. |
| setPreSaveConfigCallback() | Observe a combined Wi-Fi/config save before Wi-Fi connection processing. |
| setSaveConfigCallback() | React after Wi-Fi settings changed and the connection succeeded, or when break-after-config is enabled. |
| setConfigResetCallback() | Clear or reconcile application configuration when the portal resets Wi-Fi settings. |
Do not use a Wi-Fi-success callback to persist unrelated product settings: parameters can be saved separately, and an application needs its own durable-data policy.
The buildable [Custom Portal Content](../examples/CustomPortalContent/) example demonstrates parameters, information sections, and home cards. This guide supplies the missing persistence and validation boundary.
## Continue
- [Portal UI and configuration](PORTAL_UI.md)
- [Product settings and Wi-Fi recipe](recipes/PRODUCT_SETTINGS_AND_WIFI.md)
- [API reference](API_REFERENCE.md)
Back to [documentation](README.md) · [project overview](../README.md).
+134
View File
@@ -0,0 +1,134 @@
# Portal UI and configuration
WiFiManagerPortalConfig is the supported presentation API for the built-in provisioning portal. It changes product identity and semantic visual tokens; the portal-policy methods below control the visibility and behavior of existing built-in features. WiFiManager continues to own portal routes, forms, navigation, captive behavior, reset, and OTA views.
Apply presentation before autoConnect(), startConfigPortal(), or startWebPortal(). Configure portal policy during boot as well so each portal session begins consistently. Portal text and SVG assets are non-owning, so their RAM or PROGMEM data must have static firmware lifetime. WiFiManager locks presentation while a portal is active so asynchronous responses cannot observe partial configuration; setPortalConfig() returns false if it cannot accept the configuration.
## Portal views
These ESP32 captures use the same real-board portal test harness described in
[Testing](TESTING.md). The nearby networks shown are the networks visible to
the capture device when the portal scans.
| Overview | Wi-Fi and application settings |
| --- | --- |
| ![WiFiManager portal overview with branded identity, status, and portal actions.](assets/readme/portal-overview.png) | ![WiFiManager Wi-Fi page with nearby networks and an application setting.](assets/readme/portal-wifi-settings.png) |
## Standalone branded portal
~~~cpp
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager wifi;
namespace {
const char kTitle[] PROGMEM = "Set up Temperature Monitor";
const char kIdentity[] PROGMEM = "Example Devices";
const char kTagline[] PROGMEM = "Reliable setup for connected devices.";
const char kLogoAlt[] PROGMEM = "Example Devices";
const char kLogo[] PROGMEM =
R"svg(<svg viewBox="0 0 64 64"><circle cx="32" cy="32" r="28"/></svg>)svg";
const char kPage[] PROGMEM = "#f4f7f3";
const char kSurface[] PROGMEM = "#ffffff";
const char kAccent[] PROGMEM = "#347a45";
const char kAccentText[] PROGMEM = "#ffffff";
WiFiManagerPortalConfig kPortalUI;
}
void setup() {
// Set only the identity values this product needs.
kPortalUI.title = WiFiManagerPortalText::progmem(kTitle);
kPortalUI.identityText = WiFiManagerPortalText::progmem(kIdentity);
kPortalUI.tagline = WiFiManagerPortalText::progmem(kTagline);
kPortalUI.logo = WiFiManagerPortalAsset::svgFromProgmem(kLogo);
kPortalUI.logoAltText = WiFiManagerPortalText::progmem(kLogoAlt);
// Unset theme values retain the built-in style.
kPortalUI.theme.pageBackground = WiFiManagerPortalText::progmem(kPage);
kPortalUI.theme.surface = WiFiManagerPortalText::progmem(kSurface);
kPortalUI.theme.accent = WiFiManagerPortalText::progmem(kAccent);
kPortalUI.theme.accentText = WiFiManagerPortalText::progmem(kAccentText);
kPortalUI.theme.cornerRadiusPx = 10;
if (!wifi.setPortalConfig(kPortalUI)) {
Serial.println("Portal UI configuration was rejected");
}
wifi.autoConnect("Temperature Monitor");
}
void loop() { wifi.process(); }
~~~
The complete buildable example is [Branded Portal](../examples/BrandedPortal/BrandedPortal.ino). The compile fixture exercises this API on ESP8266 and the maintained ESP32 3.3.11 baseline.
## Presentation reference
Leave a text or colour value empty, or a radius at 0, to retain the built-in stylesheet value.
| Field | Used by |
| --- | --- |
| title | Document title and concise setup-page heading |
| identityText | Company or product name in the header above navigation |
| tagline | Short product context in the header above navigation |
| logo.svg, logoAltText | Optional trusted inline SVG and its accessible label |
| pageBackground, surface, text, mutedText, border | Portal surfaces and text |
| accent, accentHover, accentText | Primary links and actions |
| success, danger, dangerHover | Status and destructive actions |
| cornerRadiusPx, smallCornerRadiusPx | Card and compact-control corners, limited to 64 px |
Theme values accept simple named CSS values and are emitted once into a small
portal theme block. Raw CSS and JavaScript are not supported. An SVG is a
trusted compiled firmware asset, never form, MQTT, or network input.
## Portal policy
Use the portal-prefixed methods to choose which built-in pages and actions a
product presents. Configure them during boot, before the portal starts, so a
session begins with the intended behavior.
~~~cpp
// An installer portal that does not expose destructive reset or OTA actions.
wifi.portalSetPageUpdateVisible(false);
wifi.portalSetActionEraseVisible(false);
wifi.portalSetActionRestartVisible(false);
// Keep application settings on their own Setup page.
wifi.portalSetLayoutParamsLocation(PortalParamsLocation::SetupPage);
// Do not show saved passwords or static-IP fields unless the product needs them.
wifi.portalSetFieldPasswordPlaceholderMode(PortalPasswordPlaceholderMode::Hidden);
wifi.portalSetFieldStaticIpVisibility(PortalFieldVisibility::Hidden);
wifi.portalSetFieldStaticDnsVisibility(PortalFieldVisibility::Hidden);
~~~
| Group | Methods | Use |
| --- | --- | --- |
| Pages | portalSetPageInfoVisible(), portalSetPageUpdateVisible(), portalSetPageSetupVisible() | Show only product-appropriate built-in pages. |
| Actions | portalSetActionEraseVisible(), portalSetActionRestartVisible(), portalSetActionExitVisible(), portalSetActionCloseCaptiveVisible(), portalSetActionBackVisible() | Control existing action affordances; hiding an action is not a security boundary. |
| Layout | portalSetLayoutParamsLocation() | Put registered parameters on the Wi-Fi page or separate Setup page. |
| Connection/portal behavior | portalSetBehaviorCaptivePortalEnabled(), portalSetBehaviorConnectOnSave(), portalSetBehaviorExitAllowed(), portalSetBehaviorConnectTimeoutSeconds(), portalSetBehaviorPortalTimeoutSeconds(), portalSetBehaviorAutoReconnect(), portalSetBehaviorApClientCheck(), portalSetBehaviorWebClientCheck() | Set built-in portal behavior. |
| Fields | portalSetFieldPasswordPlaceholderMode(), portalSetFieldStaticIpVisibility(), portalSetFieldStaticDnsVisibility() | Limit password disclosure and network-field visibility. |
The older setConfigPortalTimeout(), setSaveConnect(), setShowStaticFields(), and related methods remain available. Prefer a single vocabulary within a product; the portal-prefixed methods make the policy visible in the portal's structured model.
## Structured content
Use portalAddParameter() for editable product settings, portalAddInfoSection() for labelled read-only values, and portalAddHomeCard() for overview text or key/value cards. Parameters remain application-owned; information sections and cards are copied when registered.
See [Portal content](PORTAL_CONTENT.md) for the full persistence, validation, callback, and lifetime rules. The buildable [Custom Portal Content](../examples/CustomPortalContent/) example shows all three content types.
## What stays built in
Branding, policy, and structured content configure the supplied portal. The
portal's HTML shell, routes, navigation, stylesheet, and scripts stay owned by
WiFiManager. There is no custom shell, route replacement, navigation injection,
raw stylesheet, or script hook.
For a product-specific web application, start that application's own server
after WiFiManager has completed provisioning. If the supplied portal needs a
reusable capability, add one focused public WiFiManager C++ API and test it on
ESP8266 and ESP32.
Back to the [documentation index](README.md) or [project overview](../README.md).
+92
View File
@@ -0,0 +1,92 @@
# Provisioning lifecycle
Choose a connection flow that matches the device's operating policy, then call process() regularly for as long as WiFiManager is active. It is a cooperative service call, not a hard real-time guarantee: target Wi-Fi or DNS work can occasionally take longer than a typical loop iteration. The consuming firmware owns its product-service lifecycle and restart decision.
## Choose a flow
| Need | Preferred API | What it does |
| --- | --- | --- |
| One saved station network, with portal fallback | autoConnect() | Tries saved credentials and starts the configuration portal when the attempt cannot connect. |
| Primary plus fallback network with application-owned storage | setStationProfileStore() + startStationConnection() | Loads, selects, retries, and recovers a fixed two-profile station set. |
| Verify a received profile before retaining it | startStationCandidate() | Attempts a primary/fallback candidate in memory and saves it only after success. |
| Start setup under application control | startConfigPortal() | Starts an AP and captive configuration portal immediately. |
| Show the portal while station Wi-Fi is already available | startWebPortal() | Starts the portal web service without starting a configuration AP. |
The first two are the normal deployed-device flows. StartConfigPortal() and startWebPortal() are supported control APIs, but should be used only when the application has a clear policy for entering and leaving them.
## Basic recovery flow
~~~cpp
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager wifi;
void setup() {
Serial.begin(115200);
wifi.setConfigPortalTimeout(180);
if (wifi.autoConnect("Device Setup", "change-me")) {
startNormalApplication();
} else {
Serial.println("Wi-Fi setup portal is active");
}
}
void loop() {
wifi.process();
if (wifi.didConfigPortalConnectSucceed()) {
// The application decides whether to start services or reboot.
startNormalApplication();
}
}
~~~
autoConnect() returns true when WiFiManager connected during that call. It returns false when it could not connect and has entered the portal path; false is not, by itself, an instruction to restart. Call process() every loop iteration while setup may be needed.
A portal timeout is in seconds. setConfigPortalTimeout(0), the default, leaves the portal open. A field-installed product may deliberately use a longer bounded window, such as 15 minutes, so an installer has time to complete setup without leaving an unattended portal indefinitely.
## Portal connection outcome
For a portal save-and-connect attempt, use these getters instead of inferring state from the rendered page:
| Getter | Meaning |
| --- | --- |
| getConfigPortalActive() | The configuration portal is currently running. |
| hasEnteredConfigPortal() | The portal has been entered at least once this runtime session. |
| isConfigPortalConnectPending() | A portal-submitted station connection is queued or waiting. |
| didConfigPortalConnectSucceed() / didConfigPortalConnectFail() | Result of the last portal-submitted connection attempt. |
| getConfigPortalConnectStatus() / getConfigPortalConnectMessage() | Platform Wi-Fi status and a human-readable result. |
The local portal UI obtains the same state through its documented local API. Do not parse portal HTML to determine connection state.
## Timing and policy
Set these before the flow starts:
| API | Use |
| --- | --- |
| setConfigPortalTimeout(seconds) | Limits a captive configuration session; setTimeout() is its deprecated alias. |
| setConnectTimeout(seconds) and setConnectRetries(count) | Bounds legacy automatic connection attempts. |
| setSaveConnectTimeout(seconds) | Bounds a portal save-and-connect attempt. |
| setSaveConnect(enabled) | Controls whether a normal portal save attempts a station connection. |
| setBreakAfterConfig(enabled) | Exits after a configuration submission even if the connection was unsuccessful. |
| setEnableConfigPortal(enabled) / setDisableConfigPortal(enabled) | Controls autoConnect() portal fallback and its post-save shutdown behavior. |
| setAPClientCheck(enabled) / setWebPortalClientCheck(enabled) | Controls whether AP/web-client activity affects the portal timeout. |
The portal-prefixed behavior methods provide the same configuration through the structured portal contract; prefer one vocabulary consistently in a product.
## Port ownership and clean handoff
Before beginning a portal on port 80, stop any application server that already owns that port. After a portal connection succeeds, wait for the application's own readiness requirements before starting its server again. A successful station connection does not automatically make an application-level service ready.
See [Local web-service handoff](recipes/LOCAL_WEB_SERVICE_HANDOFF.md) for the integration sequence.
## Continue
- [Station profiles](STATION_PROFILES.md)
- [Observability](OBSERVABILITY.md)
- [API reference](API_REFERENCE.md)
Back to [documentation](README.md) · [project overview](../README.md).
+20
View File
@@ -0,0 +1,20 @@
# WiFiManager documentation
| I want to… | Read |
| --- | --- |
| See what WiFiManager handles and what the firmware handles | [Integrating WiFiManager](ARCHITECTURE.md) |
| Start a basic portal or install a released dependency | [Getting started](GETTING_STARTED.md) |
| Choose and operate a provisioning flow | [Provisioning lifecycle](PROVISIONING_LIFECYCLE.md) |
| Brand or constrain the built-in portal | [Portal UI and configuration](PORTAL_UI.md) |
| Add and persist application settings, status, or home cards | [Portal content](PORTAL_CONTENT.md) |
| Configure primary/fallback station profiles or their portal workflow | [Station profiles](STATION_PROFILES.md) |
| Configure AP, station, scan, and reconnect settings | [Network configuration](NETWORK_CONFIGURATION.md) |
| Surface portal and station state in product firmware | [Observability](OBSERVABILITY.md) |
| Look up a supported C++ method and lifecycle rule | [API reference](API_REFERENCE.md) |
| Maintain or test the built-in portal's browser protocol | [Portal browser protocol](PORTAL_API.md) |
| Apply an existing device-integration pattern | [Recipes](recipes/README.md) |
| Run documentation and board-free compile checks | [Testing](TESTING.md) |
| Build or flash a complete example | [Examples](../examples/README.md) |
| Work on this fork or make a release | [Development and releases](DEVELOPMENT.md) |
Back to the [project overview](../README.md).
+108
View File
@@ -0,0 +1,108 @@
# Station profiles
WiFiManager adds an opt-in station-profile controller for applications that need a primary Wi-Fi network and one fallback. It is independent of the legacy autoConnect() flow: existing WiFiManager consumers do not need to change.
Profile mode is enabled only when the application supplies a WiFiManagerStationProfileStore. The store may be an in-memory implementation for a temporary session, but durable deployments should provide persistent storage.
## Lifecycle
A profile set has exactly two fixed slots:
- **Primary** (slot 0) is required whenever the controller is enabled.
- **Fallback** (slot 1) is optional.
- The last successful slot is tried first on the next connection cycle, then the remaining enabled slot.
The controller never treats the ESP SDK's saved single network as an additional source of truth. It begins one bounded connection attempt at a time, moves to the fallback after failure, and retries both profiles after a temporary loss of a previously working connection. If a new device has no valid profiles, it opens the normal configuration portal.
A candidate submitted by the portal or another application subsystem is only committed after it connects and receives a usable IP address. A failed candidate leaves the last saved profile set intact.
## Direct WiFiManager use
Implement a small store appropriate to the application. The manager neither allocates nor owns it. This complete in-memory version makes the ownership and return contract visible; use the buildable EEPROM example when the profiles must survive a restart:
```cpp
class MemoryProfileStore final : public WiFiManagerStationProfileStore {
public:
bool load(WiFiManagerStationProfiles& profiles) override {
if (!hasProfiles_) return false; // No saved primary profile: open the portal.
profiles = profiles_;
return true;
}
bool save(const WiFiManagerStationProfiles& profiles) override {
profiles_ = profiles;
hasProfiles_ = true;
return true; // A durable store must return false when its write fails.
}
bool clear() override {
profiles_ = {};
hasProfiles_ = false;
return true;
}
private:
WiFiManagerStationProfiles profiles_{};
bool hasProfiles_ = false;
};
WiFiManager wifi;
MemoryProfileStore profiles; // Must outlive WiFiManager's asynchronous connection work.
void setup() {
wifi.setStationProfileStore(&profiles);
wifi.setStationRecoveryInterval(30000);
wifi.startStationConnection("Example Setup", "setup-password");
}
void loop() {
wifi.process(); // Advances profile retries and serves the fallback portal.
}
```
This memory-only store intentionally loses profiles on restart. The store must return a complete `WiFiManagerStationProfiles` value. Each enabled profile has a NUL-terminated SSID of at most 32 characters and an optional NUL-terminated password of at most 64 characters. Keep slot 0 enabled; set `hasPassword = false` for an open network.
When load() returns false, WiFiManager treats the profile set as unavailable and opens the normal configuration portal. When save() or clear() returns false, getStationStatus().storageSaveFailed is set and the status message explains the failure.
## Verified candidate flow
Use startStationCandidate(candidate) when another application subsystem supplies a complete primary/fallback proposal:
~~~cpp
wifi.setStationProfileStore(&profiles);
if (!wifi.startStationCandidate(candidate, "Example Setup", "setup-password")) {
reportInvalidProfileCandidate();
}
~~~
WiFiManager tries the candidate in memory, then calls the attached store only after the station connects and has a usable IP address. Inspect getStationStatus() after WM_EVENT_STATION_PROFILE_CONNECTED: lastConnectionWasCandidate tells the application that this was a candidate, and storageSaveFailed distinguishes a usable but non-durable connection.
Use saveStationProfiles(profiles) only when deliberately saving without a connection check. clearStationProfiles() asks the supplied store to clear profiles and disconnects the station only after that clear succeeds.
The [Primary and fallback Wi-Fi recipe](recipes/PRIMARY_AND_FALLBACK_WIFI.md) shows why candidate verification protects known-good data.
## Portal contract
In profile mode, the existing Wi-Fi page becomes a two-profile form. It remains driven by the same local portal endpoints:
- GET /api/wifi/meta returns profiles, activeSlot, and controller state without passwords.
- POST /api/wifi/save accepts s0/p0 for primary and s1/p1 for fallback. A blank submitted password preserves an existing password; send clear0 or clear1 for an intentional open network.
- A normal save verifies the candidate by connecting. The built-in portal polls GET /api/wifi/connect-status for its result.
- stationAction=save stores the submitted profiles for a later connection attempt.
The portal requires a non-empty primary SSID. Its local protocol never returns a password. See [Portal API](PORTAL_API.md) for the shared connection-status response.
## Recovery and troubleshooting
| Symptom | Inspect | Meaning |
| --- | --- | --- |
| Portal starts immediately | getStationStatus().configuredProfiles and message | Store had no valid primary profile, so WiFiManager did not fall back to SDK-owned credentials. |
| Repeated network recovery | state, attemptedSlot, activeSlot, and WM_EVENT_STATION_BACKOFF | The controller is trying configured profiles with the recovery interval. |
| Candidate is connected but lost after reboot | lastConnectionWasCandidate and storageSaveFailed | The candidate connected, but the application store did not retain it. |
| Portal form rejects a save | Local API response/message | Primary profile was missing or SSID/password bounds were invalid. |
| Profiles do not clear | storageSaveFailed and message | The application store rejected clear(); fix its storage error before assuming Wi-Fi was removed. |
The buildable [Station Profiles](../examples/StationProfiles/) example contains a compact EEPROM-backed store for both supported ESP targets.
Back to [documentation](README.md) · [project overview](../README.md).
+305
View File
@@ -0,0 +1,305 @@
# Testing
WiFiManager separates repeatable board-free builds from opt-in tests that flash
a real board or join a captive portal. The normal commands never need a board,
local Wi-Fi credentials, browser binary, or sibling checkout.
| Physical test harness | Transport | Host adapter | Secret source | Required proof |
| --- | --- | --- | --- | --- |
| Portal lifecycle suite | Serial flash + captive-portal HTTP/browser | Named secondary adapter | safe fixture AP password | Unity/lifecycle checks and portal UI/API coverage |
| Portal HTTP OTA | WiFiManager multipart `POST /u` | Named secondary adapter | safe fixture AP password | rendered upload succeeds, portal restarts automatically, and fixture marker changes A → B twice |
The selected secondary adapter is intentionally never used for normal LAN
testing. It is `never-default`, so the host's ordinary route remains intact.
## Board-free fixture, consumer, and example builds
The Unity compile check builds WiFiManager's own fixture without a board. The
consumer check builds a project that declares only WiFiManager, proving that a
normal PlatformIO dependency resolution can compile DFTE, ESPAsyncWebServer,
and the correct ESP8266 or ESP32 TCP dependency. Normal commands reuse the
persistent PlatformIO cache; they do not delete, reinstall, or separately
assert the package graph.
```bash
./scripts/test.sh compile --platform esp8266
./scripts/test.sh compile --platform esp32
./scripts/test.sh unity --platform esp8266
./scripts/test.sh unity --platform esp32
./scripts/test.sh examples --platform esp8266
./scripts/test.sh examples --platform esp32
./scripts/test.sh ota-fixtures --platform esp8266
./scripts/test.sh ota-fixtures --platform esp32
```
CI runs these board-free checks for pull requests and pushes to the maintained
branch. `esp32` uses Arduino-ESP32 3.3.11 and compiles the guided examples.
The OTA fixture builds compile both immutable A
and B images against their tracked OTA partition layout. CI rejects equal A/B
artifacts, an ESP32 image larger than either 0x1F0000-byte app slot, or a
partition-table edit that breaks the required two-slot/no-filesystem layout. These checks
intentionally do not require attached hardware, a local network, or Docker.
Direct PlatformIO test-harness commands default to two compiler jobs. Set
`PLATFORMIO_RUN_JOBS=3` only for an explicit local run on an otherwise idle
host.
Physical portal commands lock the shared `192.168.4.0/24` portal network, the
selected secondary adapter, and the named serial device. These non-secret
resource locks are shared with DeviceFramework's portal harness, so a collision
fails before either runner changes a board or adapter while unrelated station
tests can use their own resources.
## Local hardware lifecycle tests
The Unity suite runs portal-only firmware with no Wi-Fi credentials, MQTT,
product application framework, or local profile. It verifies portal start/stop
recovery, scan-cache release, and a real asynchronous Wi-Fi scan.
Use a stable serial-by-id path rather than a changing `/dev/ttyUSB` number:
```bash
pio device list
./scripts/test.sh hardware --platform esp8266 --port /dev/serial/by-id/usb-...
./scripts/test.sh hardware --platform esp32 --port /dev/serial/by-id/usb-...
```
The runner flashes the selected board, captures normal-boot serial output with
the repository Bash helper, requires Unity's `Tests 0 Failures` and `OK`
summary, and prints lifecycle metrics. Hardware work shares a lock with the
portal test harness and DeviceFramework's hardware runners on the same host, so
two first-party invocations cannot flash or use the same board at once.
## Docker portal test harness
`test/portal-harness` is deliberately tiny portal-only firmware, not an example
or consuming application. `tools/portal-hardware` flashes it to one explicitly
selected board, joins its AP through one explicitly selected **secondary**
Wi-Fi adapter, then runs its HTTP and browser test harness in a pinned Playwright
Docker image. Docker uses host networking only to reach the already-routed
portal; it never runs NetworkManager or changes host adapters.
The runner resolves PlatformIO from `WIFIMANAGER_PIO_EXECUTABLE`, then `PATH`,
then PlatformIO's standard `~/.platformio/penv/bin/pio` installation. That
makes the same command work from a non-interactive SSH shell without modifying
the user's `PATH`.
### NetworkManager authorization
The portal adapter is a host-side resource, separate from fixture credentials.
The runner never reads a sudo password from `test/.env`, an environment file,
or source control. `doctor` reports whether the current session can use
NetworkManager directly or will need scoped sudo. In a graphical desktop,
Polkit normally authorizes the selected adapter directly. In an SSH or other
headless session with no Polkit agent, the runner visibly validates `sudo -v`
before it erases or flashes the board, then uses `sudo -n nmcli` only to scan,
disconnect, join, and remove its generated connection on the named secondary
adapter.
The normal setting is `WM_NMCLI_AUTH=auto`. Use `WM_NMCLI_AUTH=sudo` to choose
the same scoped path deliberately, or `WM_NMCLI_AUTH=direct` only when a
working Polkit policy already grants the required actions. Do not run the whole
runner under `sudo`: its state files and browser artifacts intentionally remain
owned by the invoking developer. If the sudo ticket expires during a long run,
the runner stops with an actionable message rather than silently treating an
unauthorized rescan as a missing portal SSID. `down` uses the same scoped path
to remove a retained connection.
```bash
./tools/portal-hardware doctor --client-interface wlx74da385d4165
./tools/portal-hardware run \
--platform esp8266 \
--port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165
```
The command refuses the host default-route adapter. If the chosen secondary
adapter is already connected, require an explicit acknowledgement before it is
replaced:
```bash
./tools/portal-hardware run ... --take-over-client-adapter
```
The fixture opens a 15-minute portal session and includes thirteen harmless
custom parameters. It verifies root/bootstrap/info/status API responses,
concurrent low-priority requests, every custom field and value across repeated
API fetches, timeout reset, an actual async scan, a missing-route response, and
desktop/mobile portal rendering with no browser page errors. It also round-trips
a value containing apostrophes, quotes, backslashes, angle brackets, and an
ampersand through the rendered form and parameter-save API. Screenshots, traces
on failure, JSON results, and the HTML report are saved under the printed XDG
state-directory artifact path.
On ESP8266, an AP+STA scan can briefly move the radio off the AP channel. The
client may reconnect during that interval; the test harness deliberately retries
that transport interruption and still requires a reachable portal with a
complete, valid scan result.
The normal browser test harness catches the common regression case. When changing
parameter rendering, run the opt-in ESP8266 soak as well. It performs twelve
full browser renders and API fetches while the AP is active, asserting all
thirteen fields and their exact values on every pass. This targets the
memory-sensitive rendering failure reported upstream in issue #1787 without
making every ordinary hardware run unnecessarily long:
```bash
./tools/portal-hardware run \
--platform esp8266 \
--port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165 \
--custom-parameter-stress
```
For interactive diagnosis, leave the temporary client connection up and remove
only that managed connection when finished:
```bash
./tools/portal-hardware up --platform esp32 --port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165
./tools/portal-hardware down
```
An optional station handoff test is deliberately separate because it connects
the fixture to a real LAN. Copy the ignored template below, add local
credentials, and pass it explicitly. The runner parses only `WIFI_SSID` and
`WIFI_PASSWORD` into a generated mode-600 two-key file, mounts that file
read-only into the test container, and removes it after the browser run; it
never mounts the complete local environment file or logs either value. Because
browser traces can retain request bodies, this opt-in mode disables Playwright
screenshots, video, and tracing, including explicit diagnostic screenshots. It
cannot be combined with README-media capture. Docker builds from the tracked
`tests/portal-harness` directory only, so neither the source environment file
nor the generated two-key file enters its build context. Keep its private output
directory private and review any remaining report before sharing it.
After either a passing or failing station-handoff attempt, the runner
serial-flashes the portal-only fixture once more. Its `setup()` clears saved
station settings, so the selected test board returns to the clean no-station
portal state and does not retain the developer's Wi-Fi credentials. A failed
restore or a failure to see the cleaned fixture AP return makes the command
fail. `--keep` affects only the runner's temporary
secondary-adapter connection; it does not retain station credentials on the
board.
A retained session is deliberately never overwritten. Before touching
NetworkManager, the runner atomically records its uniquely generated connection
name; after creation it atomically replaces that pending record with the exact
UUID. Ordinary failures and interrupts remove that connection immediately, and
`down` accepts either record after an uncatchable host termination or an
intentional `up`/`--keep` session. It never removes another NetworkManager
connection.
```bash
cp test/portal-station.env.example test/portal-station.env
./tools/portal-hardware run ... --station-env test/portal-station.env
```
## Refresh README media
README media is an explicit ESP32-only capture, not part of normal testing or
CI. It uses the same real-board portal test harness above, but records a short
browser tour and stores all candidate files under the ignored
`artifacts/readme-media/` directory by default:
```bash
./tools/portal-hardware run \
--platform esp32 \
--port /dev/serial/by-id/usb-... \
--client-interface USB_WIFI_ADAPTER \
--capture-readme-media
```
Review the printed artifact directory. To keep a run somewhere more convenient,
pass `--output DIRECTORY`. After review, promote only the approved PNG/GIF
files into tracked documentation assets:
```bash
./tools/promote-readme-media \
--from artifacts/readme-media/TIMESTAMP-esp32 \
--replace
./scripts/check-docs.sh
```
The Docker renderer validates the GIF duration. The promotion tool requires the
successful ESP32 media manifest, checks file types and size limits, and never
copies raw video, browser reports, traces, or arbitrary artifact files. The
renderer preserves the real recording but deliberately presents it at 1.25×
duration and 6 fps so the
README tour is readable; it does not change normal browser-test-harness timing.
ESP8266 remains covered by the normal hardware and browser test harness but does
not produce duplicate README media.
## Portal HTTP OTA A/B test harness
`portal-hardware ota` is a separate opt-in physical test for WiFiManager's
built-in HTTP update path. It exercises the rendered firmware-update page and
its real multipart `POST /u` request; it is not an ArduinoOTA/UDP test.
```bash
./tools/portal-hardware ota \
--platform esp8266 \
--port /dev/serial/by-id/usb-... \
--client-interface wlx74da385d4165
```
The selected `--client-interface` has exactly the same safety rules as the
normal portal test harness: it must be the explicitly named secondary adapter and
cannot be the host default-route interface. The test never attaches that
adapter to a normal station network. The fixture AP uses the safe local
`default1` WPA password; this is an AP-access test, not a claim that `/u` has
HTTP route authentication.
The test harness performs the following complete run:
1. Builds immutable A and B fixture images from one platform environment. A
generated harness-only header in an ignored, per-run private directory is
the only changed input, so their marker is compiled into the binary rather
than saved in WiFiManager settings or EEPROM.
2. Checks both ESP32 images against the explicit matching `app0`/`app1` slots;
ESP8266 validates B after A has booted against the exact aligned capacity
passed to `Update.begin()`.
3. Erases the explicitly selected test board's flash, then flashes A over
serial and starts its captive portal.
4. Joins that portal only through the named secondary adapter and requires the
A marker at `/api/test/firmware-marker`.
5. Mounts B read-only into the Playwright container, chooses it in the real
`#wm-ota-file` browser input, and submits the rendered form.
6. Requires the real `POST /u` success response, an automatic portal outage,
automatic restart, and two independent B-marker responses.
The OTA command additionally requires Python with PySerial (the
`python3-serial` package on Debian/Ubuntu) and retains a passive,
no-reset `serial-ota.log` beside the browser artifacts. It attaches immediately
after serial-flashing A releases the port—before portal association and the A
marker check—and remains attached through the two B checks. A passing run
requires a healthy recorder, but its contents are diagnostic evidence rather
than a pass/fail comparison against product log strings. This preserves
firmware-side portal-start and DHCP evidence without manufacturing a reset.
OTA-only fixture images wait five seconds after their upload reset so
the passive recorder can attach before A/B boot evidence is emitted; ordinary
portal test-harness startup remains fast.
The fixture marker endpoint exists only in `test/portal-harness`; it is not a
WiFiManager library route or a product-firmware pattern. The test does not
issue a manual reset. A board which boots B only after intervention is a
failure, even if B later appears.
Both fixture images are built with explicit OTA-capable layouts:
| Platform | Fixture layout | Capacity check |
| --- | --- | --- |
| ESP8266 | `eagle.flash.4m1m.ld` | A's live `ESP.getFreeSketchSpace()` response |
| ESP32 | two `0x1F0000` A/B app slots, no filesystem | tracked CSV `app1` size |
These are 4 MB fixture layouts (`d1_mini` for ESP8266 and `esp32dev` for
ESP32). Do not run this command against a board with another flash size unless
its matching explicit A/B layout and capacity checks have been added first.
The final board state is firmware B in the portal-only fixture: it clears
saved station settings on every boot and leaves no developer Wi-Fi credential
on the device. By default the temporary NetworkManager connection is removed
when the test exits. Pass `--keep` only for interactive diagnosis, then run
`./tools/portal-hardware down` to remove that named temporary connection.
Back to [documentation](README.md) · [project overview](../README.md).
Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

@@ -0,0 +1,63 @@
# Field installer provisioning
A field-installed controller or sensor often needs more time for setup than a desk-bound demo, but should not host an unattended configuration portal forever. Existing consuming device sketches solve this by choosing a deliberate 15-minute configuration window and exposing clear local feedback while setup is active.
## Flow
1. Boot with the product's normal configuration.
2. Try the stored primary/fallback profile set.
3. If Wi-Fi is unavailable, start the local setup AP and portal.
4. Keep the portal available for the installation window.
5. On a successful connection, let the application start services or reboot according to its own policy.
6. On timeout, return to the product's recovery policy rather than assuming the installer finished.
~~~cpp
constexpr unsigned long kInstallerWindowSeconds = 15 * 60;
MyProfileStore profileStore;
void setup() {
configureProductPortal();
wifi.setStationProfileStore(&profileStore);
wifi.setStationRecoveryInterval(30000);
wifi.setConfigPortalTimeout(kInstallerWindowSeconds);
wifi.setAPCallback([](WiFiManager*) {
setIndicator(IndicatorState::Setup);
showInstallerInstructions();
});
wifi.setConfigPortalTimeoutCallback([] {
setIndicator(IndicatorState::Offline);
recordSetupTimeout();
});
wifi.startStationConnection(deviceSetupName(), deviceSetupPassword());
}
void loop() {
wifi.process();
// Do not start or recreate an application server while the portal owns its port.
}
~~~
The timeout is a product decision. A short interval is appropriate for a user-facing appliance; a longer maintenance window may be justified for a device installed in a cabinet or plant room. Set 0 only when an always-open setup portal is an explicit operational choice.
## What to show an installer
Keep feedback independent of a browser redirect:
- the setup SSID and any required password;
- the device's portal address and non-default port, if configured;
- a distinct setup indicator while the portal is active;
- a distinct failure/offline indication after timeout;
- confirmation only after Wi-Fi has actually connected.
Use getConfigPortalActive(), didConfigPortalConnectSucceed(), and getConfigPortalConnectMessage() for this state. See [Observability](../OBSERVABILITY.md).
## Product boundary
WiFiManager supplies the local portal and timer. The product decides what happens after timeout: keep retrying profiles, sleep, wait for a physical action, or operate in an offline mode. If startStationConnection() returns false because no usable stored profile exists, the portal may be the intended next state rather than a reason to reboot immediately.
For a product that deliberately uses one platform-saved network rather than primary/fallback profiles, the smaller legacy equivalent is wifi.autoConnect(deviceSetupName(), deviceSetupPassword()). It has the same local portal fallback, but no application-owned profile store, candidate verification, or fallback network.
Continue with [Provisioning lifecycle](../PROVISIONING_LIFECYCLE.md) or [Provisioning state feedback](PROVISIONING_STATE_FEEDBACK.md).
+40
View File
@@ -0,0 +1,40 @@
# Local web-service handoff
A product may already host its own local HTTP service when a later connection failure opens WiFiManager's provisioning portal. Because WiFiManager owns its portal server port while active, the product must release that port before WiFiManager registers its portal routes.
A real consuming framework does this from the AP callback: it shuts down its normal web service after the setup AP has started but before WiFiManager registers portal routes.
## Automatic recovery handoff
~~~cpp
MyProfileStore profileStore;
void setup() {
wifi.setStationProfileStore(&profileStore);
wifi.setStationRecoveryInterval(30000);
wifi.setAPCallback([](WiFiManager*) {
stopApplicationWebServer(); // Releases port 80 for WiFiManager.
setIndicator(IndicatorState::Setup);
});
wifi.startStationConnection("Device Setup", "setup-password");
}
~~~
The AP callback runs after AP mode begins and before the portal routes are registered. It is the appropriate hook for automatic portal fallback. This profile-controller form matches the consuming firmware's recovery flow. If a product deliberately uses one platform-saved network instead, replace startStationConnection(...) with wifi.autoConnect(...); the same AP callback ordering applies. If the application explicitly starts setup itself, release its server before calling startConfigPortal().
## After a successful connection
The portal's successful Wi-Fi connection means the station has an address. It does not guarantee that the product's own web application, MQTT connection, or sensors are ready. The product should:
1. observe didConfigPortalConnectSucceed() or the matching event;
2. persist any application settings required for normal operation;
3. choose whether to restart or recreate its own server;
4. only advertise the product service when it is ready.
If the product uses a non-default WiFiManager HTTP port, it can avoid a port conflict but must treat the portal URL and its station-connect handoff URL as that non-default port.
Do not add routes to WiFiManager's internal server through getServer(). That accessor is for testing/host integration, not a supported product-extension API.
Continue with [Provisioning lifecycle](../PROVISIONING_LIFECYCLE.md) and [Observability](../OBSERVABILITY.md).
+49
View File
@@ -0,0 +1,49 @@
# Primary and fallback Wi-Fi
Some deployed devices receive a primary Wi-Fi network and an optional fallback from a local provisioning source. The consuming framework uses WiFiManager's fixed two-profile controller so it can verify a candidate connection before replacing durable known-good profiles.
## Flow
1. The application obtains a complete candidate profile set.
2. It gives the candidate to startStationCandidate().
3. WiFiManager attempts the primary profile and then fallback when needed.
4. On a usable station connection, WiFiManager saves the candidate through the application-owned store.
5. If connection or storage fails, the application can report the result without silently replacing known-good data.
~~~cpp
WiFiManagerStationProfiles candidate = makeDeploymentProfiles();
wifi.setStationProfileStore(&profileStore);
wifi.setStationRecoveryInterval(30000);
if (!wifi.startStationCandidate(candidate, "Device Setup", "setup-password")) {
reportRejectedProfileSet();
}
~~~
A candidate needs a non-empty enabled primary slot. The fallback slot is optional. WiFiManager never exposes profile passwords through the portal metadata API.
## Treat persistence result as part of success
A candidate can connect successfully while the profile store fails to write. Read getStationStatus() when WM_EVENT_STATION_PROFILE_CONNECTED arrives:
~~~cpp
wifi.setEventCallback([](WiFiManager::wm_event_t event) {
if (event != WiFiManager::WM_EVENT_STATION_PROFILE_CONNECTED) {
return;
}
const auto& status = wifi.getStationStatus();
if (status.lastConnectionWasCandidate && status.storageSaveFailed) {
reportConnectedButNotRetained();
}
});
~~~
This distinction matters in unattended devices: the device works now, but may fail to reconnect after a restart.
## Bootstrap and reconcile are application decisions
WiFiManager verifies and selects station profiles. It does not define whether a product should accept a supplied profile only on first boot, replace values after an explicit revision, or merge settings from another system. Keep that policy in the application, alongside its durable configuration and schema migration.
See [Station profiles](../STATION_PROFILES.md) for store requirements, portal fields, and the complete controller lifecycle.
+56
View File
@@ -0,0 +1,56 @@
# Product settings and Wi-Fi
A connected device often needs more than an SSID and password: a device name, broker host, endpoint, operating mode, or installer-selected option. The actual consuming framework pattern is to load those settings before WiFiManager begins, expose them as portal parameters, and persist them through the application's own storage layer.
## Flow
1. Load the application's durable settings and run its schema migration.
2. Build WiFiManagerParameter objects from the loaded values.
3. Register those parameters before a portal can start.
4. Register the save-parameters callback.
5. Validate and persist submitted application values through the application's storage layer.
6. Separately observe a successful Wi-Fi configuration/save if product services need a connected station first.
~~~cpp
constexpr int kBrokerHostLength = 64;
WiFiManagerParameter brokerHost(
"broker_host", "MQTT broker", "", kBrokerHostLength);
void configurePortalFromSettings() {
brokerHost.setValue(settings.mqttHost.c_str(), kBrokerHostLength);
wifi.portalAddParameter(&brokerHost);
wifi.setSaveParamsCallback([](WiFiManager::WiFiManagerRequestArgs) {
const String requestedHost = brokerHost.getValue();
if (!isValidHostname(requestedHost)) {
logRejectedSetting("broker_host");
return;
}
settings.mqttHost = requestedHost;
if (!saveApplicationSettings(settings)) {
reportConfigurationStorageFailure();
}
});
}
~~~
WiFiManager does not own settings, schema migration, or the storage transaction. In particular, an application should keep known-good settings if validation or storage fails.
## Keep the two persistence paths separate
| Data | Owner | Save trigger |
| --- | --- | --- |
| Wi-Fi credentials in legacy mode | WiFiManager/platform Wi-Fi | Portal Wi-Fi save and connection flow |
| Primary/fallback station profiles | Application-provided profile store | Profile controller after verified candidate connection, or explicit save |
| Product settings | Application | setSaveParamsCallback() and application validation |
| Product schema/revision | Application | Application boot/migration policy |
A profile provisioning revision is not the same thing as an application schema version. The application owns both migration and the decision to apply a configuration update.
## Form placement
Use portalSetLayoutParamsLocation(PortalParamsLocation::WiFiPage) for one or two values that naturally belong in initial connectivity setup. Use SetupPage for product configuration that deserves a separate step. Put read-only status in PortalInfoSection or PortalHomeCard rather than turning it into a parameter.
For lifetime and callback details, see [Portal content](../PORTAL_CONTENT.md).
@@ -0,0 +1,43 @@
# Provisioning state feedback
A physical device should give useful feedback without relying on a captive-browser redirect. Existing consuming firmware uses WiFiManager state to make setup, recovery, and connected states visible through an LED, display, or local log.
## State model
| Product state | WiFiManager signal | Typical feedback |
| --- | --- | --- |
| Normal connected operation | Station/profile controller connected, no configuration portal | Normal indicator and application services. |
| Trying known networks | Profile status is attempting or switching | Short recovery indication; no claim that setup is active yet. |
| Setup portal active | getConfigPortalActive() is true or WM_EVENT_PORTAL_STARTED | Installer-oriented setup indication and instructions. |
| Portal submitted credentials | isConfigPortalConnectPending() is true | Progress indication. |
| Portal connection succeeded | didConfigPortalConnectSucceed() or WM_EVENT_PORTAL_CONNECT_SUCCESS | Connected confirmation; application decides when services start. |
| Portal connection failed | didConfigPortalConnectFail() or WM_EVENT_PORTAL_CONNECT_FAILED | Failure indication with retry/recovery policy. |
| Candidate connected but not stored | Station event plus storageSaveFailed | Warning: active connection may not survive restart. |
## Polling pattern
~~~cpp
void updateIndicator() {
if (wifi.getConfigPortalActive()) {
setIndicator(IndicatorState::Setup);
} else if (wifi.isConfigPortalConnectPending()) {
setIndicator(IndicatorState::Connecting);
} else if (wifi.didConfigPortalConnectFail()) {
setIndicator(IndicatorState::Offline);
} else {
setIndicator(IndicatorState::Normal);
}
}
~~~
Call this from the application loop after wifi.process(). For profile mode, add getStationStatus() so the product can distinguish an active station recovery attempt from a portal session.
## Event pattern
Events reduce polling for transitions, but getters remain the authoritative state. Use setEventCallback() to record a transition or wake a product state machine, then read the relevant portal/profile status. Avoid performing long work in the callback; keep it suitable for the normal firmware loop.
## Operator-facing messages
Use getConfigPortalConnectMessage() and getWLStatusString() for concise local diagnostics. Never place Wi-Fi passwords, portal parameter values, or secrets in an operator display or remotely collected logs.
See [Observability](../OBSERVABILITY.md) for the complete event list and [Field installer provisioning](FIELD_INSTALLER_PROVISIONING.md) for timeout policy.
+15
View File
@@ -0,0 +1,15 @@
# Integration recipes
These patterns come from real firmware that consumes this WiFiManager fork. They describe the boundary between a product application and WiFiManager; they are not additional framework APIs and do not require a cloud service or companion app.
| Scenario | Start here when… |
| --- | --- |
| [Field installer provisioning](FIELD_INSTALLER_PROVISIONING.md) | A physical device needs a deliberately bounded setup window on site. |
| [Product settings and Wi-Fi](PRODUCT_SETTINGS_AND_WIFI.md) | The portal collects Wi-Fi and application-owned settings together. |
| [Primary and fallback Wi-Fi](PRIMARY_AND_FALLBACK_WIFI.md) | A deployment supplies a candidate primary/fallback network that must be verified before storage. |
| [Local web-service handoff](LOCAL_WEB_SERVICE_HANDOFF.md) | The application already owns port 80 when recovery provisioning may begin. |
| [Provisioning state feedback](PROVISIONING_STATE_FEEDBACK.md) | LEDs, a display, or logs need to distinguish setup, recovery, and connected states. |
The normal [Basic Portal](../../examples/BasicPortal/) example remains the shortest way to try the legacy saved-network-or-portal flow. These recipes explain the product concerns that a standalone example should not pretend to solve.
Back to [documentation](../README.md) · [project overview](../../README.md).
-38
View File
@@ -1,38 +0,0 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset saved settings
//wifiManager.resetSettings();
//set custom ip for portal
//wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
//fetches ssid and pass from eeprom and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
wifiManager.autoConnect("AutoConnectAP");
//or use this for auto generated name ESP + ChipID
//wifiManager.autoConnect();
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,156 +0,0 @@
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
//define your default values here, if there are different values in config.json, they are overwritten.
char mqtt_server[40];
char mqtt_port[6] = "8080";
char blynk_token[34] = "YOUR_BLYNK_TOKEN";
//flag for saving data
bool shouldSaveConfig = false;
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
//clean FS, for testing
//SPIFFS.format();
//read configuration from FS json
Serial.println("mounting FS...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
Serial.println("\nparsed json");
strcpy(mqtt_server, json["mqtt_server"]);
strcpy(mqtt_port, json["mqtt_port"]);
strcpy(blynk_token, json["blynk_token"]);
} else {
Serial.println("failed to load json config");
}
}
}
} else {
Serial.println("failed to mount FS");
}
//end read
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5);
WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 32);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//set config save notify callback
wifiManager.setSaveConfigCallback(saveConfigCallback);
//set static ip
wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
//add all your parameters here
wifiManager.addParameter(&custom_mqtt_server);
wifiManager.addParameter(&custom_mqtt_port);
wifiManager.addParameter(&custom_blynk_token);
//reset settings - for testing
//wifiManager.resetSettings();
//set minimu quality of signal so it ignores AP's under that quality
//defaults to 8%
//wifiManager.setMinimumSignalQuality();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
//read updated parameters
strcpy(mqtt_server, custom_mqtt_server.getValue());
strcpy(mqtt_port, custom_mqtt_port.getValue());
strcpy(blynk_token, custom_blynk_token.getValue());
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["mqtt_server"] = mqtt_server;
json["mqtt_port"] = mqtt_port;
json["blynk_token"] = blynk_token;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.printTo(Serial);
json.printTo(configFile);
configFile.close();
//end save
}
Serial.println("local ip");
Serial.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,188 +0,0 @@
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
//define your default values here, if there are different values in config.json, they are overwritten.
//length should be max size + 1
char mqtt_server[40];
char mqtt_port[6] = "8080";
char blynk_token[33] = "YOUR_BLYNK_TOKEN";
//default custom static IP
char static_ip[16] = "10.0.1.56";
char static_gw[16] = "10.0.1.1";
char static_sn[16] = "255.255.255.0";
//flag for saving data
bool shouldSaveConfig = false;
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
//clean FS, for testing
//SPIFFS.format();
//read configuration from FS json
Serial.println("mounting FS...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
Serial.println("\nparsed json");
strcpy(mqtt_server, json["mqtt_server"]);
strcpy(mqtt_port, json["mqtt_port"]);
strcpy(blynk_token, json["blynk_token"]);
if(json["ip"]) {
Serial.println("setting custom ip from config");
//static_ip = json["ip"];
strcpy(static_ip, json["ip"]);
strcpy(static_gw, json["gateway"]);
strcpy(static_sn, json["subnet"]);
//strcat(static_ip, json["ip"]);
//static_gw = json["gateway"];
//static_sn = json["subnet"];
Serial.println(static_ip);
/* Serial.println("converting ip");
IPAddress ip = ipFromCharArray(static_ip);
Serial.println(ip);*/
} else {
Serial.println("no custom ip in config");
}
} else {
Serial.println("failed to load json config");
}
}
}
} else {
Serial.println("failed to mount FS");
}
//end read
Serial.println(static_ip);
Serial.println(blynk_token);
Serial.println(mqtt_server);
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5);
WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//set config save notify callback
wifiManager.setSaveConfigCallback(saveConfigCallback);
//set static ip
IPAddress _ip,_gw,_sn;
_ip.fromString(static_ip);
_gw.fromString(static_gw);
_sn.fromString(static_sn);
wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
//add all your parameters here
wifiManager.addParameter(&custom_mqtt_server);
wifiManager.addParameter(&custom_mqtt_port);
wifiManager.addParameter(&custom_blynk_token);
//reset settings - for testing
//wifiManager.resetSettings();
//set minimu quality of signal so it ignores AP's under that quality
//defaults to 8%
wifiManager.setMinimumSignalQuality();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
//read updated parameters
strcpy(mqtt_server, custom_mqtt_server.getValue());
strcpy(mqtt_port, custom_mqtt_port.getValue());
strcpy(blynk_token, custom_blynk_token.getValue());
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["mqtt_server"] = mqtt_server;
json["mqtt_port"] = mqtt_port;
json["blynk_token"] = blynk_token;
json["ip"] = WiFi.localIP().toString();
json["gateway"] = WiFi.gatewayIP().toString();
json["subnet"] = WiFi.subnetMask().toString();
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.prettyPrintTo(Serial);
json.printTo(configFile);
configFile.close();
//end save
}
Serial.println("local ip");
Serial.println(WiFi.localIP());
Serial.println(WiFi.gatewayIP());
Serial.println(WiFi.subnetMask());
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,47 +0,0 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include "WiFiManager.h" //https://github.com/tzapu/WiFiManager
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
//if you used auto generated SSID, print it
Serial.println(myWiFiManager->getConfigPortalSSID());
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
wifiManager.setAPCallback(configModeCallback);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if(!wifiManager.autoConnect()) {
Serial.println("failed to connect and hit timeout");
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(1000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,68 +0,0 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
//for LED status
#include <Ticker.h>
Ticker ticker;
void tick()
{
//toggle state
int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin
digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state
}
//gets called when WiFiManager enters configuration mode
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
//if you used auto generated SSID, print it
Serial.println(myWiFiManager->getConfigPortalSSID());
//entered config mode, make led toggle faster
ticker.attach(0.2, tick);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//set led pin as output
pinMode(BUILTIN_LED, OUTPUT);
// start ticker with 0.5 because we start in AP mode and try to connect
ticker.attach(0.6, tick);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
wifiManager.setAPCallback(configModeCallback);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect()) {
Serial.println("failed to connect and hit timeout");
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(1000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
ticker.detach();
//keep LED on
digitalWrite(BUILTIN_LED, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,49 +0,0 @@
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//exit after config instead of connecting
wifiManager.setBreakAfterConfig(true);
//reset settings - for testing
//wifiManager.resetSettings();
//tries to connect to last known settings
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP" with password "password"
//and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
Serial.println("failed to connect, we should reset as see if it connects");
delay(3000);
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
Serial.println("local ip");
Serial.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,75 +0,0 @@
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
/**************************************************************************************
* this example shows how to set a static IP configuration for the ESP
* although the IP shows in the config portal, the changes will revert
* to the IP set in the source file.
* if you want the ability to configure and persist the new IP configuration
* look at the FS examples, which save the config to file
*************************************************************************************/
//default custom static IP
//char static_ip[16] = "10.0.1.59";
//char static_gw[16] = "10.0.1.1";
//char static_sn[16] = "255.255.255.0";
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//set static ip
//the commented bit only works for ESP8266 core 2.1.0 or newer
/*IPAddress _ip,_gw,_sn;
_ip.fromString(static_ip);
_gw.fromString(static_gw);
_sn.fromString(static_sn);
*/
IPAddress _ip = IPAddress(10, 0, 1, 78);
IPAddress _gw = IPAddress(10, 0, 1, 1);
IPAddress _sn = IPAddress(255, 255, 255, 0);
wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
//tries to connect to last known settings
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP" with password "password"
//and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect("AutoConnectAP", "password")) {
Serial.println("failed to connect, we should reset as see if it connects");
delay(3000);
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
Serial.println("local ip");
Serial.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
}
@@ -1,45 +0,0 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
wifiManager.setTimeout(180);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if(!wifiManager.autoConnect("AutoConnectAP")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
void loop() {
// put your main code here, to run repeatedly:
}
+20
View File
@@ -0,0 +1,20 @@
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager portal;
void setup() {
Serial.begin(115200);
portal.setConfigPortalTimeout(180); // Do not leave a first-boot setup AP open forever.
// Returns true when saved station credentials connect; otherwise opens the portal.
if (portal.autoConnect("WiFiManager Basic", "example-pass")) {
Serial.println("Connected. Run your normal application here.");
} else {
Serial.println("Setup portal started at http://192.168.4.1/");
}
}
void loop() {
portal.process(); // Keeps DNS, HTTP, and station-recovery work responsive.
}
+12
View File
@@ -0,0 +1,12 @@
# Basic Portal
This is the smallest useful WiFiManager application. It first tries the credentials the ESP platform already knows. If it cannot connect, it opens an access point named **WiFiManager Basic** with password **example-pass**.
1. Build and flash the selected `esp8266` or `esp32` environment.
2. Connect a phone or computer to **WiFiManager Basic**.
3. Open `http://192.168.4.1/` if your captive-portal helper does not open it automatically.
4. Select a network and save it. The board joins that network and the next reboot reconnects without opening the portal.
The access-point password is only an example. Choose a unique, Wi-Fi-valid password for a real product.
See the shared [example guide](../README.md), [getting started](../../docs/GETTING_STARTED.md), and [provisioning lifecycle](../../docs/PROVISIONING_LIFECYCLE.md).
+26
View File
@@ -0,0 +1,26 @@
[platformio]
default_envs = esp8266
src_dir = .
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
+47
View File
@@ -0,0 +1,47 @@
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager wifi;
namespace {
const char kPortalTitle[] PROGMEM = "Set up Temperature Monitor";
const char kPortalIdentity[] PROGMEM = "Example Devices";
const char kPortalTagline[] PROGMEM = "Reliable setup for connected devices.";
const char kPortalLogoAlt[] PROGMEM = "Example Devices";
const char kExampleLogo[] PROGMEM = "<svg viewBox='0 0 64 64' aria-hidden='true'><circle cx='32' cy='32' r='28' fill='#347a45'/></svg>";
const char kPage[] PROGMEM = "#f4f7f3";
const char kSurface[] PROGMEM = "#ffffff";
const char kText[] PROGMEM = "#1c251e";
const char kAccent[] PROGMEM = "#347a45";
const char kAccentText[] PROGMEM = "#ffffff";
WiFiManagerPortalConfig kPortalUI;
}
void setup() {
Serial.begin(115200);
// Brand the built-in portal; unassigned fields retain their default values.
kPortalUI.title = WiFiManagerPortalText::progmem(kPortalTitle);
kPortalUI.identityText = WiFiManagerPortalText::progmem(kPortalIdentity);
kPortalUI.tagline = WiFiManagerPortalText::progmem(kPortalTagline);
kPortalUI.logo = WiFiManagerPortalAsset::svgFromProgmem(kExampleLogo);
kPortalUI.logoAltText = WiFiManagerPortalText::progmem(kPortalLogoAlt);
// Override only the theme tokens that define this product's appearance.
kPortalUI.theme.pageBackground = WiFiManagerPortalText::progmem(kPage);
kPortalUI.theme.surface = WiFiManagerPortalText::progmem(kSurface);
kPortalUI.theme.text = WiFiManagerPortalText::progmem(kText);
kPortalUI.theme.accent = WiFiManagerPortalText::progmem(kAccent);
kPortalUI.theme.accentText = WiFiManagerPortalText::progmem(kAccentText);
kPortalUI.theme.cornerRadiusPx = 10;
kPortalUI.theme.smallCornerRadiusPx = 6;
if (!wifi.setPortalConfig(kPortalUI)) {
Serial.println("Portal UI configuration was rejected");
}
wifi.setConfigPortalTimeout(180);
wifi.autoConnect("Temperature Monitor");
}
void loop() { wifi.process(); }
+9
View File
@@ -0,0 +1,9 @@
# Branded Portal
This example uses the supported `WiFiManagerPortalConfig` presentation API to give the built-in portal a product name, company identity, tagline, inline SVG mark, and semantic colour tokens.
Flash the `esp8266` or `esp32` environment, join **Temperature Monitor**, and open `http://192.168.4.1/`. The visual changes come from static firmware data; WiFiManager still owns the portal routes, forms, validation, and captive-network behaviour.
Use only trusted compiled SVG data. Keep the backing strings static for the lifetime of the firmware, then call `setPortalConfig()` before opening a portal.
See [Portal UI and configuration](../../docs/PORTAL_UI.md), [architecture boundaries](../../docs/ARCHITECTURE.md), and the shared [example guide](../README.md).
+26
View File
@@ -0,0 +1,26 @@
[platformio]
default_envs = esp8266
src_dir = .
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
@@ -0,0 +1,43 @@
#include <Arduino.h>
#include <WiFiManager.h>
WiFiManager portal;
// WiFiManager reads this object while the portal is open, so it must outlive setup().
WiFiManagerParameter brokerHost("broker_host", "MQTT broker", "mqtt.local", 40);
void setup() {
Serial.begin(115200);
portal.portalAddParameter(&brokerHost); // Adds an application-owned setting to the built-in form.
// WiFiManager copies this read-only status section when it is registered.
PortalInfoSection deviceInfo;
deviceInfo.id = "device";
deviceInfo.title = "Example device";
deviceInfo.items = {
{"firmware", "Firmware", "1.0.0"},
{"sensor", "Sensor", "Ready"},
};
portal.portalAddInfoSection(deviceInfo);
// This callout appears on the built-in portal overview.
PortalHomeCard hint;
hint.id = "hint";
hint.title = "What this example adds";
hint.kind = PortalHomeCardKind::Callout;
hint.text = "A normal text setting, a status section, and a home-page callout.";
portal.portalAddHomeCard(hint);
portal.setSaveParamsCallback([](WiFiManager::WiFiManagerRequestArgs) {
// Validate and persist a copy in the application; this example only reports it.
Serial.print("MQTT broker selected: ");
Serial.println(brokerHost.getValue());
});
portal.setConfigPortalTimeout(180);
portal.autoConnect("WiFiManager Content", "example-pass");
}
void loop() {
portal.process(); // Serves portal requests until provisioning completes or times out.
}
+13
View File
@@ -0,0 +1,13 @@
# Custom Portal Content
This example keeps WiFiManager’s portal navigation, validation, and captive behaviour, while adding three application-owned pieces of content:
- an editable MQTT broker host field;
- a compact device-information section;
- a callout on the portal overview.
It opens **WiFiManager Content** with password **example-pass** until it has working station credentials. Save the form, then inspect serial output to see the selected broker value.
The parameter object is global because WiFiManager reads it for the lifetime of the portal. In a real application, copy the value into that application’s own validated persistent configuration inside the save callback.
See [Portal content](../../docs/PORTAL_CONTENT.md), [product settings and Wi-Fi](../../docs/recipes/PRODUCT_SETTINGS_AND_WIFI.md), and the shared [example guide](../README.md).
@@ -0,0 +1,26 @@
[platformio]
default_envs = esp8266
src_dir = .
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
@@ -1,60 +0,0 @@
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
// select wich pin will trigger the configuraton portal when set to LOW
// ESP-01 users please note: the only pins available (0 and 2), are shared
// with the bootloader, so always set them HIGH at power-up
#define TRIGGER_PIN 0
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("\n Starting");
pinMode(TRIGGER_PIN, INPUT);
}
void loop() {
// is configuration portal requested?
if ( digitalRead(TRIGGER_PIN) == LOW ) {
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
//it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
//WITHOUT THIS THE AP DOES NOT SEEM TO WORK PROPERLY WITH SDK 1.5 , update to at least 1.5.1
//WiFi.mode(WIFI_STA);
if (!wifiManager.startConfigPortal("OnDemandAP")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
// put your main code here, to run repeatedly:
}
+29
View File
@@ -0,0 +1,29 @@
# WiFiManager examples
Every directory below is a standalone PlatformIO project. Build it from the repository root or the example directory:
```bash
pio run -d examples/BasicPortal -e esp8266
pio run -d examples/BasicPortal -e esp8266 -t upload
pio device monitor -d examples/BasicPortal -e esp8266
```
Choose `esp32` for an ESP32 development board. The examples use the checked-out WiFiManager source, so they are also useful while developing this fork.
| Example | Start here when you want to… |
| --- | --- |
| [Basic Portal](BasicPortal/) | provision one board through the normal saved-network-or-portal flow |
| [Custom Portal Content](CustomPortalContent/) | add application settings and useful status cards to the built-in portal |
| [Branded Portal](BrandedPortal/) | change the portal’s identity, logo, and semantic visual theme |
| [Station Profiles](StationProfiles/) | remember a primary Wi-Fi network and one fallback in application-owned EEPROM storage |
The portal examples intentionally begin with no station credentials. On first boot, connect to the matching setup network and open `http://192.168.4.1/`.
| Example | Setup network | Password |
| --- | --- | --- |
| Basic Portal | WiFiManager Basic | example-pass |
| Custom Portal Content | WiFiManager Content | example-pass |
| Branded Portal | Temperature Monitor | none |
| Station Profiles | WiFiManager Profiles | example-pass |
Back to the [project overview](../README.md).
+9
View File
@@ -0,0 +1,9 @@
# Station Profiles
This example gives WiFiManager a small application-owned EEPROM store. The portal accepts a required primary Wi-Fi network and an optional fallback, verifies a submitted network before saving it, then remembers the last successful choice across restarts.
On a blank board, connect to **WiFiManager Profiles** with password **example-pass** and open `http://192.168.4.1/`. Enter a primary network and, if useful, one fallback. After a successful connection, restart the board to confirm that it tries the saved profiles before reopening the portal.
`StoredProfiles` is intentionally simple so the ownership boundary is visible. A production application should add its own record versioning and integrity protection around the application’s complete configuration; WiFiManager only owns network-selection policy.
See [Station profiles](../../docs/STATION_PROFILES.md), [primary and fallback Wi-Fi](../../docs/recipes/PRIMARY_AND_FALLBACK_WIFI.md), and the shared [example guide](../README.md).
@@ -0,0 +1,68 @@
#include <Arduino.h>
#include <EEPROM.h>
#include <WiFiManager.h>
namespace {
constexpr uint32_t kStoreMagic = 0x574D5031; // "WMP1"
struct StoredProfiles {
uint32_t magic;
WiFiManagerStationProfiles profiles;
};
// The application owns persistence; WiFiManager only chooses and verifies profiles.
class EepromProfileStore final : public WiFiManagerStationProfileStore {
public:
bool begin() {
#if defined(ESP32)
// ESP32 EEPROM emulation can fail to reserve its backing region.
return EEPROM.begin(sizeof(StoredProfiles));
#else
EEPROM.begin(sizeof(StoredProfiles));
return true;
#endif
}
bool load(WiFiManagerStationProfiles& profiles) override {
StoredProfiles stored{};
EEPROM.get(0, stored);
if (stored.magic != kStoreMagic) {
// Treat erased or unrelated EEPROM as having no profiles.
return false;
}
profiles = stored.profiles;
return true;
}
bool save(const WiFiManagerStationProfiles& profiles) override {
// WiFiManager calls this only after it has verified the submitted candidate.
EEPROM.put(0, StoredProfiles{kStoreMagic, profiles});
return EEPROM.commit();
}
bool clear() override {
EEPROM.put(0, StoredProfiles{});
return EEPROM.commit();
}
};
EepromProfileStore profileStore;
WiFiManager portal;
} // namespace
void setup() {
Serial.begin(115200);
if (!profileStore.begin()) {
Serial.println("Could not initialise EEPROM profile storage");
return;
}
// Both objects are global because station retries continue after setup() returns.
portal.setStationProfileStore(&profileStore);
portal.setStationRecoveryInterval(30000);
portal.startStationConnection("WiFiManager Profiles", "example-pass");
}
void loop() {
portal.process(); // Advances connection attempts and serves provisioning when needed.
}
+26
View File
@@ -0,0 +1,26 @@
[platformio]
default_envs = esp8266
src_dir = .
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
-38
View File
@@ -1,38 +0,0 @@
<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>
<style>.c{text-align: center;} div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;font-family:verdana;} button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} .q{float: right;width: 64px;text-align: right;} .l{background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==") no-repeat left center;background-size: 1em;}</style>
<script>function c(l){document.getElementById('s').value=l.innerText||l.textContent;document.getElementById('p').focus();}</script>
</head><body><div style="text-align:left;display:inline-block;min-width:260px;">
<!--
<div><a href='#' onclick='c(this)'>{v}</a> {r}% {i}</div>
<div><a href='#' onclick='c(this)'>{v}</a> 100% <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAKCAMAAAC+Ge+yAAAACVBMVEUAAAC7u7v///9etNz6AAAAI0lEQVQI133GsQ3AMAAEoXv2H9qNJacKFbEaWTQJ+uQB/nMdEaYAXeJkZ9AAAAAASUVORK5CYII='/></div>
<div><a href='#' onclick='c(this)'>Vila17</a> 95% <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAADFBMVEUAAAAAtgD///8AAADV1YIHAAAAA3RSTlMAAAD6dsTeAAAAHUlEQVR4AWMAAmYgYGBkArHAAMoEYnQmMxSQywQAKvMA3+mlSFAAAAAASUVORK5CYII='/></div>
<div><a href='#'>LilRid</a> 100% <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAABlBMVEUAAAD///+l2Z/dAAAAIklEQVR4AWNgZGRkAAIQBURQDEZAgM5kgAJGEAQDwkxkbQAOhgBBk64+mQAAAABJRU5ErkJggg=='/></div>
<div><a href='#'>Marcelica</a> 100% <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAACVBMVEUAAAC7u7v///9etNz6AAAAJ0lEQVR4AY3GsREAIBSDUD77D63x4tlKw0MdmD0ijTO9f6SFnv7YXB4qAIVn0xoMAAAAAElFTkSuQmCC'/></div>
<div><a href='#'>PMica</a> 110% <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==' width="13px"/></div>
-->
<style>
.q{float: right;width: 64px;text-align: right;}
.l{background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==") no-repeat left center;background-size: 1em;}
</style>
<div><a href='#' onclick='c(this)'>{v}</a> <span class="q {i}">{r}%</span></div>
<div><a href='#'>PMisa</a> <span class="q l">100%</span> </div>
<div><a href='#'>Dragos_Networks</a>&nbsp;<span class="q l">10%</span> </div>
<div><a href='#'>PMisa</a> <span class="q l">8%</span> </div>
<br/>
<form method='get' action='wifisave'><input id='s' name='s' length=32 placeholder='SSID'><br/><input id='p' name='p' length=64 placeholder='password'><br/><button type='submit'>save</button></form>
<br/><div></div>
<br/>
<form action=\"/wifi\" method=\"get\"><button>Configure WiFi</button></form><br/>
<form action=\"/0wifi\" method=\"get\"><button>Configure WiFi (No Scan)</button></form>
<br>
<div class="c"><a href=\"/wifi\">Scan</a></div>
</div>
</body></html>
-39
View File
@@ -1,39 +0,0 @@
#######################################
# Syntax Coloring Map For WifiManager
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
WiFiManager KEYWORD1
WiFiManagerParameter KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
autoConnect KEYWORD2
getSSID KEYWORD2
getPassword KEYWORD2
getConfigPortalSSID KEYWORD2
resetSettings KEYWORD2
setConfigPortalTimeout KEYWORD2
setConnectTimeout KEYWORD2
setDebugOutput KEYWORD2
setMinimumSignalQuality KEYWORD2
setAPStaticIPConfig KEYWORD2
setSTAStaticIPConfig KEYWORD2
setAPCallback KEYWORD2
setSaveConfigCallback KEYWORD2
addParameter KEYWORD2
getID KEYWORD2
getValue KEYWORD2
getPlaceholder KEYWORD2
getValueLength KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
# LITERAL1
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
/**
* WiFiManagerDfteLogger.h
*
* @author alexhopeoconnor
* @license MIT
*
* Optional bridge from DFTE's logging hooks to WiFiManager::log.
* Enabled only when the sketch / library build defines WM_DFTE_LOGGING.
*/
#ifndef WiFiManagerDfteLogger_h
#define WiFiManagerDfteLogger_h
#if defined(ESP8266) || defined(ESP32)
#include <DeviceFrameworkTemplateEngineDebug.h>
#include "WiFiManager.h"
/**
* 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(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(WiFiManagerLogLevel level, const String& msg) {
if (!_wm) {
return;
}
_wm->log(level, "WM/DFTE", msg);
}
};
#endif // ESP8266 || ESP32
#endif // WiFiManagerDfteLogger_h
@@ -0,0 +1,125 @@
/**
* WiFiManagerHandlers.h
*
* HTTP request handlers for WiFiManager: single HTML shell + JSON APIs.
*
* @author alexhopeoconnor
* @license MIT
*/
#ifndef WiFiManagerHandlers_h
#define WiFiManagerHandlers_h
#if defined(ESP8266) || defined(ESP32)
#include <ESPAsyncWebServer.h>
#include <memory>
#include "WiFiManager.h"
#ifndef WM_TEMPLATE_REGISTRY_CAPACITY
#define WM_TEMPLATE_REGISTRY_CAPACITY 16
#endif
// Portal UI customization is driven by WiFiManager `portal*` APIs and JSON (/api/...) — not by mutating template
// placeholder registries.
// -----------------------------------------------------------------------------------------------
// FORM FIELD NAMES (for IP configuration forms)
const char S_ip[] PROGMEM = "ip";
const char S_gw[] PROGMEM = "gw";
const char S_sn[] PROGMEM = "sn";
const char S_dns[] PROGMEM = "dns";
// -----------------------------------------------------------------------------------------------
// HTTP HEADERS
const char HTTP_HEAD_CT[] PROGMEM = "text/html";
const char HTTP_HEAD_CT2[] PROGMEM = "text/plain";
const char HTTP_HEAD_CORS[] PROGMEM = "Access-Control-Allow-Origin";
const char HTTP_HEAD_CORS_ALLOW_ALL[] PROGMEM = "*";
class WiFiManagerHandlers {
public:
WiFiManagerHandlers(WiFiManager* wm);
void handleRoot(AsyncWebServerRequest *request);
void handleNotFound(AsyncWebServerRequest *request);
void handleRequest(AsyncWebServerRequest *request);
void handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
void handleUpdateDone(AsyncWebServerRequest *request);
void handleApiBootstrap(AsyncWebServerRequest *request);
void handleApiWifiScanStatus(AsyncWebServerRequest *request);
void handleApiWifiScan(AsyncWebServerRequest *request);
void handleApiWifiMeta(AsyncWebServerRequest *request);
void handleApiWifiSave(AsyncWebServerRequest *request);
void handleApiWifiConnectStatus(AsyncWebServerRequest *request);
void handleApiWifiConnectComplete(AsyncWebServerRequest *request);
void handleApiPortalTimeoutReset(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, boolean optionalErase = false);
void handleApiPortalClose(AsyncWebServerRequest *request);
void handleApiPortalExit(AsyncWebServerRequest *request);
boolean captivePortal(AsyncWebServerRequest *request);
void stopCaptivePortal();
/** True when the HTTP Host header does not match the portal’s canonical host:port (captive redirect needed). */
static bool shouldRedirectCaptiveForHost(const String& requestHost, const String& serverLocWithPort);
void doParamSave(WiFiManager::WiFiManagerRequestArgs requestArgs);
/** Portal bootstrap JSON (same payload as GET /api/bootstrap). Public for tests and host integration. */
String buildPortalBootstrapJson();
/** Same JSON body as GET /api/wifi/meta (tests + embedding). */
String buildApiWifiMetaJson();
/** Same JSON body as GET /api/info (tests + embedding). */
String buildApiInfoJson();
/** Same JSON body as GET /api/params (tests + embedding). */
String buildApiParamsGetJson();
/** Same JSON body as GET /api/status (tests + embedding). */
String buildApiStatusJson();
/** GET /api/wifi/connect-status (portal connect progress). */
String buildApiWifiConnectStatusJson();
/** Fixed JSON bodies for POST action endpoints (single source for handlers + tests). */
static String jsonApiWifiScanAccepted();
static String jsonApiDeviceRestartScheduled();
static String jsonApiParamsSaveOk();
static String jsonApiPortalCloseOk();
static String jsonApiPortalExitOk();
static String jsonApiPortalExitForbidden();
static String jsonApiOtaUpdateSuccess();
static String jsonApiEraseResponse(boolean success);
private:
WiFiManager* _wm;
void collectVisibleScanResults(std::vector<const WiFiManager::WiFiScanNetwork*>& networks);
void appendVisibleScanResultsJson(String& json, const std::vector<const WiFiManager::WiFiScanNetwork*>& networks);
void applyWifiAndParamsFromRequest(AsyncWebServerRequest *request);
bool buildStationProfilesFromRequest(AsyncWebServerRequest *request, WiFiManagerStationProfiles& profiles);
void buildPlainStatusSummary(String& out);
void appendPortalJsonStaticFields(String& json, bool& first);
void appendPortalJsonCustomParams(String& json, bool& first);
void appendPortalExtraInfoSectionsJson(String& json, bool& first);
void appendPortalExtraHomeCardsJson(String& json, bool& first);
void appendJsonKvItem(String& json, bool& first, const char* key, const String& label, const String& value);
void appendOneInfoItemForId(String& json, bool& first, const char* id);
void appendInfoSectionFromIds(String& json, const char* const* ids, size_t count, bool& first);
void appendApiInfoActionsJson(String& json);
static void sendApiJson(AsyncWebServerRequest *request, int code, const String& json);
};
#endif // defined(ESP8266) || defined(ESP32)
#endif // WiFiManagerHandlers_h
@@ -0,0 +1,35 @@
/**
* WiFiManagerLogLevel.h
*
* @author alexhopeoconnor
* @license MIT
*
* 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,22 @@
/**
* WiFiManagerLogSink.h
*
* @author alexhopeoconnor
* @license MIT
*
* 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,48 @@
/**
* WiFiManagerLogTemplates.h
*
* @author alexhopeoconnor
* @license MIT
*
* 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
@@ -0,0 +1,64 @@
/**
* WiFiManagerParameter.h
*
* @author alexhopeoconnor
* @license MIT
*/
#ifndef WiFiManagerParameter_h
#define WiFiManagerParameter_h
#include <Arduino.h>
class WiFiManager;
#ifndef WIFI_MANAGER_MAX_PARAMS
#define WIFI_MANAGER_MAX_PARAMS 5 // params will autoincrement and realloc by this amount when max is reached
#endif
#define WFM_LABEL_BEFORE 1
#define WFM_LABEL_AFTER 2
#define WFM_NO_LABEL 0
#define WFM_LABEL_DEFAULT 1
class WiFiManagerParameter {
public:
/**
Create custom parameters that can be added to the WiFiManager setup web page
@id is used for HTTP queries and must not contain spaces nor other special characters
*/
WiFiManagerParameter();
explicit WiFiManagerParameter(const char *custom);
WiFiManagerParameter(const char *id, const char *label);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement);
virtual ~WiFiManagerParameter();
WiFiManagerParameter(const WiFiManagerParameter&) = delete;
WiFiManagerParameter& operator=(const WiFiManagerParameter&) = delete;
const char *getID() const;
const char *getValue() const;
const char *getLabel() const;
const char *getPlaceholder() const; // @deprecated, use getLabel
int getValueLength() const;
int getLabelPlacement() const;
virtual const char *getCustomHTML() const;
void setValue(const char *defaultValue, int length);
protected:
void init(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement);
const char *_id;
const char *_label;
char *_value;
int _length;
int _labelPlacement;
const char *_customHTML;
friend class WiFiManager;
};
#endif // WiFiManagerParameter_h
@@ -0,0 +1,93 @@
/**
* WiFiManagerPortalUI.h
*
* Deliberate, portal-specific presentation configuration. This header does
* not depend on DeviceFramework: WiFiManager remains useful on its own.
*/
#ifndef WIFI_MANAGER_PORTAL_UI_H
#define WIFI_MANAGER_PORTAL_UI_H
#include <Arduino.h>
enum class WiFiManagerPortalStorage : uint8_t {
Ram,
Progmem,
};
/** Non-owning static text. The caller retains the data for the firmware lifetime. */
struct WiFiManagerPortalText {
const char* data = nullptr;
WiFiManagerPortalStorage storage = WiFiManagerPortalStorage::Ram;
static constexpr WiFiManagerPortalText ram(const char* value) {
return {value, WiFiManagerPortalStorage::Ram};
}
static constexpr WiFiManagerPortalText progmem(const char* value) {
return {value, WiFiManagerPortalStorage::Progmem};
}
bool empty() const { return data == nullptr || length() == 0; }
size_t length() const {
return data == nullptr ? 0 : (storage == WiFiManagerPortalStorage::Progmem ? strlen_P(data) : strlen(data));
}
char at(size_t index) const {
return storage == WiFiManagerPortalStorage::Progmem
? static_cast<char>(pgm_read_byte(data + index))
: data[index];
}
};
/** Optional inline SVG branding asset. It is not a general HTML extension point. */
struct WiFiManagerPortalAsset {
WiFiManagerPortalText svg;
static constexpr WiFiManagerPortalAsset svgFromRam(const char* value) {
return {WiFiManagerPortalText::ram(value)};
}
static constexpr WiFiManagerPortalAsset svgFromProgmem(const char* value) {
return {WiFiManagerPortalText::progmem(value)};
}
bool empty() const { return svg.empty(); }
};
/**
* Semantic colour and shape values for WiFiManager's built-in portal.
*
* Leave a value empty to retain the built-in stylesheet value. Values are
* validated before they are emitted into the portal stylesheet; they are not
* a general CSS injection mechanism.
*/
struct WiFiManagerPortalTheme {
WiFiManagerPortalText pageBackground;
WiFiManagerPortalText surface;
WiFiManagerPortalText text;
WiFiManagerPortalText mutedText;
WiFiManagerPortalText border;
WiFiManagerPortalText accent;
WiFiManagerPortalText accentHover;
WiFiManagerPortalText accentText;
WiFiManagerPortalText danger;
WiFiManagerPortalText dangerHover;
WiFiManagerPortalText success;
uint8_t cornerRadiusPx = 0;
uint8_t smallCornerRadiusPx = 0;
};
/**
* Complete setup-time presentation configuration for WiFiManager's portal.
*
* Text and SVG assets are non-owning static data in RAM or PROGMEM. Apply this
* before starting a portal; asynchronous portal responses use immutable state.
*/
struct WiFiManagerPortalConfig {
WiFiManagerPortalText title;
WiFiManagerPortalText identityText;
WiFiManagerPortalText tagline;
WiFiManagerPortalAsset logo;
WiFiManagerPortalText logoAltText;
WiFiManagerPortalTheme theme;
};
#endif // WIFI_MANAGER_PORTAL_UI_H
+100
View File
@@ -0,0 +1,100 @@
/**
* WiFiManagerServer.h
*
* @author alexhopeoconnor
* @license MIT
*
* HTTP server for the config portal: single HTML shell (GET /), JSON under /api/..., OTA POST /u,
* captive-portal redirects, and 404 handling. No legacy page routes.
*
* Supported surface (authoritative; registerRoutes mirrors this):
* GET /
* GET /api/bootstrap
* GET /api/wifi/scan-status
* POST /api/wifi/scan
* GET /api/wifi/meta
* POST /api/wifi/save
* GET /api/wifi/connect-status
* POST /api/wifi/connect-complete
* POST /api/portal/timeout-reset
* GET /api/params
* POST /api/params/save
* GET /api/info
* GET /api/status
* POST /api/device/restart
* POST /api/device/erase
* POST /api/portal/close
* POST /api/portal/exit
* POST /u (multipart firmware upload; JSON completion response)
* notFound -> captive redirect or 404
*/
#ifndef WiFiManagerServer_h
#define WiFiManagerServer_h
#if defined(ESP8266) || defined(ESP32)
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
#include <functional>
#include <memory>
class WiFiManager;
class WiFiManagerHandlers;
#ifdef WM_DFTE_LOGGING
class WiFiManagerDfteLogger;
#endif
// -----------------------------------------------------------------------------------------------
// HTTP routes (portal API only; no legacy /wifi, /info, … page URLs)
const char R_root[] PROGMEM = "/";
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_wifi_connect_status[] PROGMEM = "/api/wifi/connect-status";
const char R_api_wifi_connect_complete[] PROGMEM = "/api/wifi/connect-complete";
const char R_api_portal_timeout_reset[] PROGMEM = "/api/portal/timeout-reset";
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";
const char R_updatedone[] PROGMEM = "/u";
class WiFiManagerServer {
public:
WiFiManagerServer(WiFiManager* wm);
~WiFiManagerServer();
void createServer(uint16_t port);
void registerRoutes();
void setupDNSD();
void processDNS();
void shutdownServer();
AsyncWebServer* getServer() { return server.get(); }
DNSServer* getDNSServer() { return dnsServer.get(); }
private:
WiFiManager* _wm;
std::unique_ptr<WiFiManagerHandlers> _handlers;
std::unique_ptr<AsyncWebServer> server;
std::unique_ptr<DNSServer> dnsServer;
#ifdef WM_DFTE_LOGGING
std::unique_ptr<WiFiManagerDfteLogger> _dfteLogger;
bool _wmOwnsDfteLogSink = false;
#endif
};
#endif // defined(ESP8266) || defined(ESP32)
#endif // WiFiManagerServer_h
+106
View File
@@ -0,0 +1,106 @@
/**
* WiFiManagerUtils.h
* Pure utility functions for WiFiManager
* String conversions, HTML encoding, and helper calculations
* These functions have no dependency on WiFiManager instance state
*
* @author alexhopeoconnor
* @license MIT
*/
#ifndef _WIFI_MANAGER_UTILS_H_
#define _WIFI_MANAGER_UTILS_H_
#include <Arduino.h>
// Forward declaration
class IPAddress;
namespace WiFiManagerUtils {
// -----------------------------------------------------------------------------------------------
// WIFI STATUS ARRAYS (for status string conversion)
extern const char * const WIFI_STA_STATUS[] PROGMEM;
extern const char * const WIFI_MODES[] PROGMEM;
#ifdef ESP32
extern const char * const AUTH_MODE_NAMES[] PROGMEM;
#elif defined(ESP8266)
extern const char * const AUTH_MODE_NAMES[] PROGMEM;
#endif
// -----------------------------------------------------------------------------------------------
// STRING CONVERSION UTILITIES
/**
* Convert WiFi status code to readable string
* @param status WiFi status code
* @return Status string or "Unknown" if invalid
*/
String getStatusString(uint8_t status);
/**
* Convert WiFi mode code to readable string
* @param mode WiFi mode code
* @return Mode string or "Unknown" if invalid
*/
String getModeString(uint8_t mode);
/**
* Convert encryption/auth mode to readable string
* @param authmode Encryption type code
* @return Encryption type string
*/
String getEncryptionString(uint8_t authmode);
// -----------------------------------------------------------------------------------------------
// HTML UTILITIES
/**
* Encode HTML entities in a string
* @param str String to encode
* @param whitespace If true, also encode spaces as &#160;
* @return Encoded string
*/
String htmlEntities(const String& str, bool whitespace = false);
// -----------------------------------------------------------------------------------------------
// IP/STRING UTILITIES
/**
* Check if string is a valid IP address
* @param str String to check
* @return true if valid IP address
*/
bool isValidIP(const String& str);
/**
* Convert IPAddress to String
* @param ip IPAddress to convert
* @return IP address string
*/
String ipToString(IPAddress ip);
/**
* Validate AP password format (8-63 characters)
* @param password Password to validate
* @return true if valid
*/
bool isValidAPPassword(const String& password);
// -----------------------------------------------------------------------------------------------
// HELPER CALCULATIONS
/**
* Convert RSSI value to quality percentage (0-100)
* @param rssi RSSI value in dBm
* @return Quality percentage (0-100)
*/
int rssiToQuality(int rssi);
} // namespace WiFiManagerUtils
#endif // _WIFI_MANAGER_UTILS_H_
+233
View File
@@ -0,0 +1,233 @@
/**
* CSS.h
*
* @author alexhopeoconnor
* @license MIT
*
* CSS stylesheet for WiFiManager web interface.
* Embedded styles to avoid external file dependencies.
*/
#ifndef _CSS_TEMPLATES_H_
#define _CSS_TEMPLATES_H_
#include <Arduino.h>
const char CSS_STYLE[] PROGMEM = "<style>"
/* Design tokens */
":root{"
"--wm-bg:#f0f4f8;"
"--wm-surface:#ffffff;"
"--wm-text:#0f172a;"
"--wm-muted:#64748b;"
"--wm-border:#e2e8f0;"
"--wm-brand:#0ea5e9;"
"--wm-brand-hover:#0284c7;"
"--wm-brand-text:#ffffff;"
"--wm-danger:#dc2626;"
"--wm-danger-hover:#b91c1c;"
"--wm-success:#16a34a;"
"--wm-radius:12px;"
"--wm-radius-sm:8px;"
"--wm-shadow:0 1px 3px rgba(15,23,42,.08),0 4px 16px rgba(15,23,42,.06);"
"--wm-font:system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;"
"}"
"body.invert{"
"--wm-bg:#0c1222;"
"--wm-surface:#151d2e;"
"--wm-text:#f1f5f9;"
"--wm-muted:#94a3b8;"
"--wm-border:#334155;"
"--wm-brand:#38bdf8;"
"--wm-brand-hover:#7dd3fc;"
"--wm-danger:#f87171;"
"--wm-danger-hover:#fca5a5;"
"--wm-success:#4ade80;"
"--wm-shadow:0 4px 24px rgba(0,0,0,.45);"
"}"
/* Base */
"*,*::before,*::after{box-sizing:border-box}"
"body.portal{margin:0;min-height:100vh;background:var(--wm-bg);color:var(--wm-text);"
"font-family:var(--wm-font);font-size:16px;line-height:1.5;-webkit-text-size-adjust:100%;text-align:left}"
"a{color:var(--wm-brand);font-weight:600;text-decoration:none}"
"a:hover{color:var(--wm-brand-hover);text-decoration:underline}"
/* Layout shell */
".wm-layout{width:100%;max-width:420px;margin:0 auto;padding:16px 18px 28px;}"
"h1,h2,h3{margin:0 0 .35em;font-weight:700;letter-spacing:-.02em}"
"h1{font-size:1.5rem}"
"h2{font-size:1.15rem}"
"h3{font-size:1rem}"
"p{margin:.5em 0}"
/* Top navigation — single row; overflow scrollable but scrollbar hidden (touch still pans) */
".wm-nav{display:flex;flex-wrap:nowrap;align-items:stretch;gap:4px;margin:0 0 20px;padding:4px 6px;"
"overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none;"
"background:var(--wm-surface);border-radius:var(--wm-radius);box-shadow:var(--wm-shadow);border:1px solid var(--wm-border)}"
".wm-nav::-webkit-scrollbar{display:none;width:0;height:0}"
".wm-nav-link{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;padding:6px 8px;border-radius:var(--wm-radius-sm);"
"font-size:.8rem;font-weight:600;color:var(--wm-muted);text-decoration:none;border:1px solid transparent;white-space:nowrap}"
".wm-nav-link:hover{color:var(--wm-brand);background:rgba(14,165,233,.08);text-decoration:none}"
"body.invert .wm-nav-link:hover{background:rgba(56,189,248,.12)}"
".wm-nav-link--active{color:var(--wm-text);background:rgba(14,165,233,.15);border-color:rgba(14,165,233,.35)}"
"body.invert .wm-nav-link--active{background:rgba(56,189,248,.2);border-color:rgba(56,189,248,.4)}"
".wm-nav .wm-icon-label{gap:4px}"
".wm-nav .wm-icon{width:.95rem;height:.95rem;flex:0 0 .95rem}"
".wm-icon-label{display:inline-flex;align-items:center;gap:8px;min-width:0}"
".wm-icon{display:inline-flex;align-items:center;justify-content:center;width:1.1rem;height:1.1rem;flex:0 0 1.1rem;color:currentColor}"
".wm-icon svg{display:block;width:100%;height:100%}"
/* Header / page chrome */
".wm-site-header{display:flex;align-items:center;gap:10px;min-height:40px;margin:0 0 12px}"
".wm-site-logo{display:flex;align-items:center;justify-content:center;width:40px;height:40px;flex:0 0 40px;line-height:0}"
".wm-site-logo svg{display:block;width:100%;height:100%}"
".wm-site-brand-copy{min-width:0}"
".wm-site-brand-name{margin:0;font-size:.78rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--wm-text)}"
".wm-site-tagline{margin:2px 0 0;font-size:.82rem;line-height:1.25;color:var(--wm-muted)}"
".wm-page-head{margin-bottom:16px}"
".wm-page-head h1{font-size:1.45rem}"
".wm-page-desc{font-size:.95rem;color:var(--wm-muted);margin:.35em 0 0}"
/* Cards */
".wm-card{background:var(--wm-surface);border:1px solid var(--wm-border);border-radius:var(--wm-radius);"
"box-shadow:var(--wm-shadow);padding:18px 16px;margin-bottom:16px;text-align:left}"
".wm-scan-card,.wm-ota-card{position:relative;overflow:hidden}"
".wm-scan-results{min-height:126px}"
".wm-card-title{font-size:1rem;margin:0 0 12px;padding-bottom:10px;border-bottom:1px solid var(--wm-border);"
"color:var(--wm-text)}"
".wm-card-subtitle{margin:-4px 0 12px;font-size:.9rem;line-height:1.45;color:var(--wm-muted)}"
".wm-lead{margin:0 0 8px;font-size:.95rem;color:var(--wm-muted);line-height:1.5}"
".wm-home-summary{margin:0 0 14px;font-size:1rem;font-weight:600;line-height:1.45;color:var(--wm-text)}"
/* Callout / status */
".wm-callout{padding:12px 14px;border-radius:var(--wm-radius-sm);border:1px solid var(--wm-border);"
"background:rgba(14,165,233,.06);margin-bottom:16px}"
"body.invert .wm-callout{background:rgba(56,189,248,.08)}"
".wm-callout--info{border-left:4px solid var(--wm-brand)}"
".wm-info-summary{font-weight:600;color:var(--wm-text)}"
".wm-status{margin:0 0 12px;padding:10px 12px;font-size:.92rem;font-weight:700;color:var(--wm-brand);"
"text-align:center;border-radius:var(--wm-radius-sm);background:rgba(14,165,233,.08);border:1px solid rgba(14,165,233,.18)}"
".wm-status--warning{color:#c2410c;background:rgba(249,115,22,.12);border-color:rgba(249,115,22,.28)}"
".wm-status--caution{color:#a16207;background:rgba(234,179,8,.14);border-color:rgba(234,179,8,.3)}"
".wm-status--danger{color:var(--wm-danger);background:rgba(220,38,38,.12);border-color:rgba(220,38,38,.28)}"
"body.invert .wm-status{background:rgba(56,189,248,.12);border-color:rgba(56,189,248,.22)}"
"body.invert .wm-status--warning{background:rgba(249,115,22,.18);border-color:rgba(249,115,22,.34)}"
"body.invert .wm-status--caution{background:rgba(234,179,8,.18);border-color:rgba(234,179,8,.34)}"
"body.invert .wm-status--danger{background:rgba(220,38,38,.18);border-color:rgba(220,38,38,.34)}"
/* Form fields */
".wm-field{margin-bottom:14px;text-align:left}"
".wm-field:last-child{margin-bottom:0}"
".wm-field label{display:block;font-size:.82rem;font-weight:600;color:var(--wm-muted);margin-bottom:6px}"
"input[type=text],input[type=password],input[type=number],input[type=email],select{"
"display:block;width:100%;padding:12px 14px;font-size:1rem;font-family:inherit;"
"color:var(--wm-text);background:var(--wm-bg);border:1px solid var(--wm-border);border-radius:var(--wm-radius-sm);"
"-webkit-appearance:none;appearance:none}"
"input:focus,select:focus{outline:2px solid var(--wm-brand);outline-offset:0;border-color:var(--wm-brand)}"
"input[type=radio],input[type=checkbox]{width:auto;margin-right:8px;accent-color:var(--wm-brand)}"
".wm-checkbox-row{display:flex;align-items:center;gap:8px;margin:12px 0;font-size:.92rem}"
".wm-checkbox-row label{display:inline;margin:0;font-weight:500;color:var(--wm-text)}"
".wm-form-actions{margin-top:16px}"
".wm-wifi-details-card{position:relative}"
".wm-wifi-save-overlay{position:fixed;inset:0;z-index:10002;display:none;align-items:center;justify-content:center;padding:18px;"
"box-sizing:border-box;background:rgba(15,23,42,.58)}"
".wm-wifi-save-panel{display:flex;align-items:center;gap:14px;width:100%;max-width:340px;padding:18px;border:1px solid var(--wm-border);"
"border-radius:var(--wm-radius-sm);background:var(--wm-surface);box-shadow:var(--wm-shadow);text-align:left}"
".wm-wifi-save-panel strong{display:block;font-size:1rem;color:var(--wm-text)}"
".wm-wifi-save-panel p{margin:4px 0 0;font-size:.9rem;line-height:1.45;color:var(--wm-muted)}"
".wm-operation-overlay{position:absolute;inset:0;z-index:5;display:none;align-items:center;justify-content:center;padding:16px;background:rgba(15,23,42,.56)}"
".wm-operation-panel{display:flex;align-items:center;gap:12px;width:100%;max-width:310px;padding:16px;border:1px solid var(--wm-border);border-radius:var(--wm-radius-sm);background:var(--wm-surface);box-shadow:var(--wm-shadow);text-align:left}"
".wm-operation-panel strong{display:block;font-size:.98rem;color:var(--wm-text)}"
".wm-operation-panel p{margin:3px 0 0;font-size:.88rem;line-height:1.4;color:var(--wm-muted)}"
".wm-operation-progress{margin-top:10px}"
".wm-operation-progress-track{height:7px;overflow:hidden;border-radius:999px;background:var(--wm-border)}"
".wm-operation-progress-track span{display:block;width:0;height:100%;border-radius:inherit;background:var(--wm-brand);transition:width .15s ease}"
".wm-operation-progress-label{display:block;margin-top:4px;font-size:.8rem;font-weight:700;color:var(--wm-muted);text-align:right}"
".wm-portal-timeout-row{display:flex;align-items:stretch;gap:8px;margin:0 0 12px}"
".wm-portal-timeout-row .wm-status{flex:1;margin:0}"
".wm-icon-button{display:inline-flex;align-items:center;justify-content:center;width:42px;min-height:42px;padding:0;border:1px solid var(--wm-border);border-radius:var(--wm-radius-sm);background:var(--wm-bg);color:var(--wm-text);cursor:pointer}"
".wm-icon-button:hover{border-color:var(--wm-brand);color:var(--wm-brand)}"
".wm-icon-button:disabled{opacity:.5;cursor:not-allowed}"
".wm-icon-button .wm-icon{width:1.05rem;height:1.05rem}"
".wm-inline-link{display:inline-block;margin-top:12px;font-size:.92rem}"
".wm-spinner{width:24px;height:24px;flex:0 0 24px;border:3px solid var(--wm-border);border-top-color:var(--wm-brand);border-radius:50%;animation:wm-spin .8s linear infinite}"
"@keyframes wm-spin{to{transform:rotate(360deg)}}"
"@media (prefers-reduced-motion:reduce){.wm-spinner{animation:none;border-right-color:var(--wm-brand)}}"
/* Buttons */
".wm-btn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 18px;"
"font-size:1rem;font-weight:600;font-family:inherit;border-radius:var(--wm-radius-sm);border:0;cursor:pointer;"
"transition:background .15s,transform .1s,opacity .15s}"
".wm-btn:disabled{opacity:.5;cursor:not-allowed}"
".wm-btn:active{transform:scale(.98)}"
"a.wm-btn{box-sizing:border-box;text-decoration:none}"
".wm-btn .wm-icon-label{justify-content:center}"
".wm-btn--block{width:100%}"
".wm-btn--primary{background:var(--wm-brand);color:var(--wm-brand-text)}"
".wm-btn--primary:hover{background:var(--wm-brand-hover)}"
".wm-btn--secondary{background:var(--wm-bg);color:var(--wm-text);border:1px solid var(--wm-border)}"
".wm-btn--secondary:hover{border-color:var(--wm-brand);color:var(--wm-brand)}"
".wm-btn--danger{background:var(--wm-danger);color:var(--wm-brand-text)}"
".wm-btn--danger:hover{background:var(--wm-danger-hover)}"
"input[type=file]{width:100%;padding:10px;border:1px dashed var(--wm-border);border-radius:var(--wm-radius-sm);"
"background:var(--wm-bg);font-size:.9rem}"
/* Legacy: unclassed submit in forms */
"button[type=submit],.wm-form-actions .wm-btn--primary{background:var(--wm-brand);color:var(--wm-brand-text)}"
"button[type=submit]:hover{background:var(--wm-brand-hover)}"
/* Device actions / button stack */
".wm-actions-stack{display:flex;flex-direction:column;gap:10px;margin-top:4px}"
".wm-btn-group{display:flex;flex-direction:column;gap:10px}"
/* WiFi scan list */
".wm-scan-list{margin:0 0 12px;border:1px solid var(--wm-border);border-radius:var(--wm-radius-sm);"
"overflow:hidden;background:var(--wm-bg)}"
".wm-scan-row{display:flex;align-items:center;gap:10px;min-height:48px;padding:10px 12px;"
"border-bottom:1px solid var(--wm-border);text-decoration:none;color:inherit;cursor:pointer}"
".wm-scan-row:last-child{border-bottom:0}"
".wm-scan-row:hover{background:rgba(14,165,233,.1)}"
"body.invert .wm-scan-row:hover{background:rgba(56,189,248,.12)}"
".wm-scan-ssid{flex:1;min-width:0;font-weight:600;font-size:.95rem;text-align:left;word-break:break-word}"
".wm-scan-meta{display:flex;align-items:center;justify-content:flex-end;gap:6px;flex-shrink:0;min-width:78px}"
".wm-scan-signal{display:block;flex-shrink:0;font-size:.8rem;color:var(--wm-muted);font-weight:600;min-width:38px;text-align:right}"
".wm-scan-lock,.wm-scan-bars{display:block;flex:0 0 16px}"
// quality icons
".q{position:relative;height:16px;width:16px;margin:0;padding:0;flex-shrink:0}.q.q-0:after{background-position-x:0}.q.q-1:after{background-position-x:-16px}.q.q-2:after{background-position-x:-32px}.q.q-3:after{background-position-x:-48px}.q.q-4:after{background-position-x:-64px}.q.l:before{background-position-x:-80px}.ql .q{float:left}.q:after,.q:before{content:'';position:absolute;left:0;top:0;width:16px;height:16px;display:block;background-repeat:no-repeat;background-position:16px 0;"
"background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAQCAMAAADeZIrLAAAAJFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHJj5lAAAAC3RSTlMAIjN3iJmqu8zd7vF8pzcAAABsSURBVHja7Y1BCsAwCASNSVo3/v+/BUEiXnIoXkoX5jAQMxTHzK9cVSnvDxwD8bFx8PhZ9q8FmghXBhqA1faxk92PsxvRc2CCCFdhQCbRkLoAQ3q/wWUBqG35ZxtVzW4Ed6LngPyBU2CobdIDQ5oPWI5nCUwAAAAASUVORK5CYII=');}"
".wm-scan-lock:after,.wm-scan-bars:before{content:none}"
"@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){.q:before,.q:after {"
"background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALwAAAAgCAMAAACfM+KhAAAALVBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAOrOgAAAADnRSTlMAESIzRGZ3iJmqu8zd7gKjCLQAAACmSURBVHgB7dDBCoMwEEXRmKlVY3L//3NLhyzqIqSUggy8uxnhCR5Mo8xLt+14aZ7wwgsvvPA/ofv9+44334UXXngvb6XsFhO/VoC2RsSv9J7x8BnYLW+AjT56ud/uePMdb7IP8Bsc/e7h8Cfk912ghsNXWPpDC4hvN+D1560A1QPORyh84VKLjjdvfPFm++i9EWq0348XXnjhhT+4dIbCW+WjZim9AKk4UZMnnCEuAAAAAElFTkSuQmCC');"
"background-size: 95px 16px;}}"
// messages from firmware / server
".msg{padding:16px;margin:12px 0;border-radius:var(--wm-radius-sm);border:1px solid var(--wm-border);"
"border-left-width:4px;border-left-color:var(--wm-muted);background:var(--wm-surface);text-align:left}"
".msg h4{margin:0 0 8px;font-size:1rem}"
".msg.P{border-left-color:var(--wm-brand)}.msg.P h4{color:var(--wm-brand)}"
".msg.D{border-left-color:var(--wm-danger)}.msg.D h4{color:var(--wm-danger)}"
".msg.S{border-left-color:var(--wm-success)}.msg.S h4{color:var(--wm-success)}"
"dt{font-weight:700;font-size:.85rem;color:var(--wm-muted)}dd{margin:2px 0 12px 0;padding:0;font-size:.95rem}"
"td{vertical-align:top}"
".h{display:none}"
/* Info page key-value grid */
".wm-kv{margin:0;padding:0}"
".wm-kv dt{padding-top:10px}"
".wm-kv dt:first-of-type{padding-top:0}"
".wm-kv dd{margin-left:0;padding-bottom:4px;border-bottom:1px solid var(--wm-border)}"
".wm-kv dd:last-of-type{border-bottom:0}"
/* Feedback areas */
"#wm-wifi-msg,#wm-param-msg{font-size:.9rem;margin-top:12px;min-height:1.2em;color:var(--wm-muted)}"
// invert legacy body
"body.invert{background-color:var(--wm-bg)}"
"body.invert .msg{border-color:var(--wm-border)}"
"body.invert .q[role=img]{-webkit-filter:invert(1);filter:invert(1)}"
":disabled{opacity:.55}"
// toast + modal
".wm-toast{position:fixed;left:50%;top:12px;transform:translateX(-50%);z-index:10001;max-width:92%;padding:12px 16px;border-radius:var(--wm-radius-sm);"
"box-shadow:var(--wm-shadow);font-size:.95rem;text-align:center;font-weight:600}"
".wm-toast.ok{background:rgba(22,163,74,.15);border:1px solid var(--wm-success);color:var(--wm-text)}"
".wm-toast.err{background:rgba(220,38,38,.12);border:1px solid var(--wm-danger);color:var(--wm-text)}"
".wm-dialog{position:fixed;inset:0;z-index:10000;display:none;align-items:center;justify-content:center;padding:16px;box-sizing:border-box}"
".wm-dialog-backdrop{position:absolute;inset:0;background:rgba(15,23,42,.5)}"
".wm-dialog-panel{position:relative;z-index:1;background:var(--wm-surface);border-radius:var(--wm-radius);padding:20px 18px;max-width:400px;width:100%;"
"box-shadow:var(--wm-shadow);border:1px solid var(--wm-border);text-align:left}"
".wm-dialog-msg{margin:0 0 16px;line-height:1.45;color:var(--wm-text)}"
".wm-dialog-actions{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}"
".wm-dialog-actions .wm-btn{min-width:108px}"
".wm-dialog-ok,.wm-btn.wm-dialog-ok{background:var(--wm-brand)!important;color:var(--wm-brand-text)!important}"
".wm-dialog-ok:hover{background:var(--wm-brand-hover)!important}"
"body.invert .wm-toast.ok{background:rgba(22,163,74,.2)}"
"body.invert .wm-toast.err{background:rgba(220,38,38,.2)}"
"</style>";
#endif // _CSS_TEMPLATES_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,48 @@
/**
* RootShell.h
*
* @author alexhopeoconnor
* @license MIT
*
* Single-page portal shell: only HTML document served for GET /.
* Dynamic UI is driven by embedded JS + JSON APIs under /api/...
*
* Placeholder keys (%PAGE_TITLE%, %STYLES%, %PORTAL_THEME%, %BOOTSTRAP_JSON%, %PORTAL_APP_JS%) are filled
* per request in WiFiManagerHandlers::handleRoot; do not treat placeholders as a customization 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>"
"%STYLES%"
"%PORTAL_THEME%"
"</head>"
"<body class='portal'>"
"<div id='wm-toast' class='wm-toast' aria-live='polite' role='status' style='display:none'></div>"
"<div id='wm-dialog' class='wm-dialog' style='display:none' aria-hidden='true'>"
"<div class='wm-dialog-backdrop' id='wm-dialog-backdrop'></div>"
"<div class='wm-dialog-panel'>"
"<p class='wm-dialog-msg' id='wm-dialog-msg'></p>"
"<div class='wm-dialog-actions'>"
"<button type='button' id='wm-dialog-cancel' class='wm-btn wm-btn--secondary'>Cancel</button>"
"<button type='button' id='wm-dialog-ok' class='wm-btn wm-btn--primary wm-dialog-ok'>OK</button>"
"</div></div></div>"
"<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_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,111 @@
/**
* WiFiManagerParameter.cpp
*
* @author alexhopeoconnor
* @license MIT
*/
#include "WiFiManagerParameter.h"
#include <cstring>
#include <new>
WiFiManagerParameter::WiFiManagerParameter()
: WiFiManagerParameter("")
{
}
WiFiManagerParameter::WiFiManagerParameter(const char *custom) {
_id = NULL;
_label = NULL;
_length = 0;
_value = nullptr;
_labelPlacement = WFM_LABEL_DEFAULT;
_customHTML = custom;
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label) {
init(id, label, "", 0, "", WFM_LABEL_DEFAULT);
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length) {
init(id, label, defaultValue, length, "", WFM_LABEL_DEFAULT);
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom) {
init(id, label, defaultValue, length, custom, WFM_LABEL_DEFAULT);
}
WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement) {
init(id, label, defaultValue, length, custom, labelPlacement);
}
void WiFiManagerParameter::init(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement) {
_id = id;
_label = label;
_labelPlacement = labelPlacement;
_customHTML = custom;
_length = 0;
_value = nullptr;
setValue(defaultValue,length);
}
WiFiManagerParameter::~WiFiManagerParameter() {
if (_value != NULL) {
delete[] _value;
}
_length=0; // setting length 0, ideally the entire parameter should be removed, or added to wifimanager scope so it follows
}
// WiFiManagerParameter& WiFiManagerParameter::operator=(const WiFiManagerParameter& rhs){
// Serial.println("copy assignment op called");
// (*this->_value) = (*rhs._value);
// return *this;
// }
// @note debug is not available in wmparameter class
void WiFiManagerParameter::setValue(const char *defaultValue, int length) {
if (!_id || length < 0) {
return;
}
if (_length != length || _value == nullptr) {
char* replacement = new (std::nothrow) char[static_cast<size_t>(length) + 1];
if (!replacement) {
return;
}
delete[] _value;
_value = replacement;
_length = length;
}
memset(_value, 0, static_cast<size_t>(_length) + 1);
if (defaultValue != nullptr) {
strncpy(_value, defaultValue, _length);
}
}
const char* WiFiManagerParameter::getValue() const {
// Serial.println(printf("Address of _value is %p\n", (void *)_value));
return _value;
}
const char* WiFiManagerParameter::getID() const {
return _id;
}
const char* WiFiManagerParameter::getPlaceholder() const {
return _label;
}
const char* WiFiManagerParameter::getLabel() const {
return _label;
}
int WiFiManagerParameter::getValueLength() const {
return _length;
}
int WiFiManagerParameter::getLabelPlacement() const {
return _labelPlacement;
}
const char* WiFiManagerParameter::getCustomHTML() const {
return _customHTML;
}
+184
View File
@@ -0,0 +1,184 @@
/**
* WiFiManagerServer.cpp
*
* @author alexhopeoconnor
* @license MIT
*
* HTTP server lifecycle and route registration only. HTML shell rendering is request-scoped in
* WiFiManagerHandlers (WM_ROOT_SHELL_TEMPLATE + per-request placeholder registry).
* Route inventory matches WiFiManagerServer.h (GET /, /api/..., POST /u, onNotFound).
*/
#include "WiFiManagerServer.h"
#include "WiFiManager.h"
#include "WiFiManagerHandlers.h"
#ifdef WM_DFTE_LOGGING
#include "WiFiManagerDfteLogger.h"
#include <DeviceFrameworkTemplateEngineDebug.h>
#endif
#if defined(ESP8266) || defined(ESP32)
WiFiManagerServer::WiFiManagerServer(WiFiManager* wm)
: _wm(wm), _handlers(std::make_unique<WiFiManagerHandlers>(wm)) {}
WiFiManagerServer::~WiFiManagerServer() = default;
void WiFiManagerServer::createServer(uint16_t port) {
if (server) {
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("Server already exists, shutting down first"));
#endif
shutdownServer();
}
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Info, kWiFiMgrLogSubsystem, F("Starting Web Portal"));
#endif
if (port != 80) {
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("http server started with custom port: "), port);
#endif
}
server.reset(new AsyncWebServer(port));
#ifdef WM_DFTE_LOGGING
// DFTE logging is still owned by server lifecycle; it is intentionally independent of
// request-scoped shell rendering / placeholder registration.
if (!deviceFrameworkTemplateEngineIsLoggingEnabled()) {
if (!_dfteLogger) {
_dfteLogger = std::make_unique<WiFiManagerDfteLogger>(_wm);
}
deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get(), static_cast<const void*>(this));
_wmOwnsDfteLogSink = true;
}
#endif
}
void WiFiManagerServer::registerRoutes() {
if (!server) {
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Error, kWiFiMgrLogSubsystem, F("[ERROR] Server not created, call createServer() first"));
#endif
return;
}
if (_wm->_webservercallback != NULL) {
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("[CB] _webservercallback calling"));
#endif
_wm->_webservercallback();
}
// Shell: only HTML document. JSON + actions + OTA below (no legacy /wifi, /info, … routes).
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_wifi_connect_status), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleApiWifiConnectStatus(request);
});
server->on(WM_G(R_api_wifi_connect_complete), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->_handlers->handleApiWifiConnectComplete(request);
});
server->on(WM_G(R_api_portal_timeout_reset), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->_handlers->handleApiPortalTimeoutReset(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_updatedone), HTTP_POST,
[this](AsyncWebServerRequest *request) {
this->_handlers->handleUpdateDone(request);
},
[this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len,
bool final) {
this->_handlers->handleUpdating(request, filename, index, data, len, final);
});
server->onNotFound([this](AsyncWebServerRequest *request) {
this->_handlers->handleNotFound(request);
});
server->begin();
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("HTTP server started"));
#endif
}
void WiFiManagerServer::setupDNSD() {
dnsServer.reset(new DNSServer());
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
#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());
}
void WiFiManagerServer::processDNS() {
if (dnsServer) {
dnsServer->processNextRequest();
}
}
void WiFiManagerServer::shutdownServer() {
#ifdef WM_DFTE_LOGGING
if (_wmOwnsDfteLogSink) {
deviceFrameworkTemplateEngineDisableLoggingForOwner(static_cast<const void*>(this));
_dfteLogger.reset();
_wmOwnsDfteLogSink = false;
}
#endif
if (server) {
server.reset();
}
if (dnsServer) {
dnsServer->stop();
dnsServer.reset();
}
}
#endif
+135
View File
@@ -0,0 +1,135 @@
/**
* WiFiManagerUtils.cpp
* Implementation of pure utility functions for WiFiManager
*
* @author alexhopeoconnor
* @license MIT
*/
#include "WiFiManagerUtils.h"
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
namespace WiFiManagerUtils {
// -----------------------------------------------------------------------------------------------
// WIFI STATUS ARRAYS
const char * const WIFI_STA_STATUS[] PROGMEM = {
"WL_IDLE_STATUS", // 0 STATION_IDLE
"WL_NO_SSID_AVAIL", // 1 STATION_NO_AP_FOUND
"WL_SCAN_COMPLETED", // 2
"WL_CONNECTED", // 3 STATION_GOT_IP
"WL_CONNECT_FAILED", // 4 STATION_CONNECT_FAIL, STATION_WRONG_PASSWORD(NI)
"WL_CONNECTION_LOST", // 5
"WL_DISCONNECTED", // 6
"WL_STATION_WRONG_PASSWORD" // 7 KLUDGE
};
#ifdef ESP32
const char * const AUTH_MODE_NAMES[] PROGMEM = {
"OPEN",
"WEP",
"WPA_PSK",
"WPA2_PSK",
"WPA_WPA2_PSK",
"WPA2_ENTERPRISE",
"MAX"
};
#elif defined(ESP8266)
const char * const AUTH_MODE_NAMES[] PROGMEM = {
"",
"",
"WPA_PSK", // 2 ENC_TYPE_TKIP
"",
"WPA2_PSK", // 4 ENC_TYPE_CCMP
"WEP", // 5 ENC_TYPE_WEP
"",
"OPEN", //7 ENC_TYPE_NONE
"WPA_WPA2_PSK", // 8 ENC_TYPE_AUTO
};
#endif
const char* const WIFI_MODES[] PROGMEM = { "NULL", "STA", "AP", "STA+AP" };
// -----------------------------------------------------------------------------------------------
// STRING CONVERSION UTILITIES
String getStatusString(uint8_t status) {
if(status <= 7) return FPSTR(WIFI_STA_STATUS[status]);
return F("Unknown");
}
String getModeString(uint8_t mode) {
if(mode <= 3) return FPSTR(WIFI_MODES[mode]);
return F("Unknown");
}
String getEncryptionString(uint8_t authmode) {
return FPSTR(AUTH_MODE_NAMES[authmode]);
}
// -----------------------------------------------------------------------------------------------
// HTML UTILITIES
String htmlEntities(const String& str, bool whitespace) {
String result = str;
result.replace("&","&amp;");
result.replace("<","&lt;");
result.replace(">","&gt;");
result.replace("'","&#39;");
if(whitespace) result.replace(" ","&#160;");
return result;
}
// -----------------------------------------------------------------------------------------------
// IP/STRING UTILITIES
bool isValidIP(const String& str) {
for (size_t i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
String ipToString(IPAddress ip) {
String res = "";
for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF);
return res;
}
bool isValidAPPassword(const String& password) {
if (password.length() < 8 || password.length() > 63) {
return false;
}
return true;
}
// -----------------------------------------------------------------------------------------------
// HELPER CALCULATIONS
int rssiToQuality(int rssi) {
int quality = 0;
if (rssi <= -100) {
quality = 0;
} else if (rssi >= -50) {
quality = 100;
} else {
quality = 2 * (rssi + 100);
}
return quality;
}
} // namespace WiFiManagerUtils
+75 -8
View File
@@ -1,13 +1,80 @@
{
"name": "WifiManager",
"keywords": "wifi, wi-fi",
"description": "ESP8266 WiFi Connection manager with fallback web configuration portal",
"repository":
{
"name": "WiFiManager",
"version": "3.2.5",
"keywords": [
"wifi",
"wi-fi",
"esp",
"esp8266",
"esp32",
"espressif8266",
"espressif32",
"nodemcu",
"wemos",
"arduino"
],
"description": "Maintained ESP8266/ESP32 WiFi configuration portal with asynchronous web support.",
"authors": [
{
"name": "tzapu",
"url": "https://github.com/tzapu"
},
{
"name": "tablatronix",
"url": "https://github.com/tablatronix",
"maintainer": true
},
{
"name": "Alex Hope-O'Connor",
"url": "https://github.com/alexhopeoconnor"
}
],
"repository": {
"type": "git",
"url": "https://github.com/tzapu/WiFiManager.git"
"url": "https://github.com/alexhopeoconnor/WiFiManager.git"
},
"frameworks": "arduino",
"platforms": "espressif",
"version": "0.11"
"platforms": [
"espressif8266",
"espressif32"
],
"dependencies": [
{
"owner": "esp32async",
"name": "ESPAsyncWebServer",
"version": "3.9.1"
},
{
"owner": "esp32async",
"name": "ESPAsyncTCP",
"version": "^2.0.0",
"platforms": "espressif8266"
},
{
"owner": "esp32async",
"name": "AsyncTCP",
"version": "^3.4.9",
"platforms": "espressif32"
},
{
"name": "DeviceFrameworkTemplateEngine",
"version": "https://github.com/alexhopeoconnor/DFTE.git#v1.2.1"
}
],
"build": {
"includeDir": "lib/WiFiManager/include",
"srcDir": "lib/WiFiManager/src"
},
"export": {
"include": [
"lib/WiFiManager/include",
"lib/WiFiManager/src",
"LICENSE",
"README.md",
"CHANGELOG.md",
"library.json"
]
},
"$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json",
"homepage": "https://github.com/alexhopeoconnor/WiFiManager"
}
-9
View File
@@ -1,9 +0,0 @@
name=WiFiManager
version=0.11
author=tzapu
maintainer=tzapu
sentence=ESP8266 WiFi Connection manager with fallback web configuration portal
paragraph=Library for configuring ESP8266 modules WiFi credentials at runtime.
category=Communication
url=https://github.com/tzapu/WiFiManager.git
architectures=esp8266
+47
View File
@@ -0,0 +1,47 @@
; PlatformIO Project Configuration File for WiFiManager Library
; This file is used for building tests
[env:esp8266]
platform = espressif8266
board = d1_mini
framework = arduino
; Postmortem jump relocation fix for large binaries (see ESP8266-LINKER-WORKAROUND.md in arduino-home-assistant)
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
monitor_speed = 115200
test_framework = unity
test_build_src = no
build_flags =
-DWM_LOG_LEVEL=5
-DUNIT_TEST
lib_deps =
ESP32Async/ESPAsyncWebServer@3.9.1
DeviceFrameworkTemplateEngine=https://github.com/alexhopeoconnor/DFTE.git#v1.2.1
ESP32Async/ESPAsyncTCP@2.0.0
[env:esp32]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
framework = arduino
monitor_speed = 115200
test_framework = unity
test_build_src = no
build_unflags =
-std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
-DWM_LOG_LEVEL=5
-DUNIT_TEST
lib_deps =
ESP32Async/ESPAsyncWebServer@3.9.1
DeviceFrameworkTemplateEngine=https://github.com/alexhopeoconnor/DFTE.git#v1.2.1
ESP32Async/AsyncTCP@^3.4.9
; 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
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 vMAJOR.MINOR.PATCH" >&2
exit 2
}
tag="${1:-}"
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || usage
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
version="${tag#v}"
repo_url="https://github.com/alexhopeoconnor/WiFiManager.git"
reference_files=(README.md docs/GETTING_STARTED.md)
current_version="$(sed -n 's/.*"version": "\([^"]*\)".*/\1/p' "$root/library.json" | head -n 1)"
[[ "$current_version" != "$version" ]] || {
echo "library.json already declares $version; choose a new version." >&2
exit 1
}
grep -q "^## $version$" "$root/CHANGELOG.md" && {
echo "CHANGELOG.md already has a $version section; choose a new version." >&2
exit 1
}
sed -i -E '0,/"version": "[0-9]+\.[0-9]+\.[0-9]+"/s//"version": "'"$version"'"/' "$root/library.json"
for file in "${reference_files[@]}"; do
sed -i -E "s|${repo_url}#v[0-9]+\.[0-9]+\.[0-9]+|${repo_url}#v${version}|g" "$root/$file"
done
temp_file="$(mktemp)"
trap 'rm -f "$temp_file"' EXIT
{
IFS= read -r changelog_heading < "$root/CHANGELOG.md"
[[ "$changelog_heading" == "# Changelog" ]] || {
echo "CHANGELOG.md must begin with # Changelog" >&2
exit 1
}
printf '%s\n\n## %s\n\n- TODO: Describe this release.\n' "$changelog_heading" "$version"
tail -n +2 "$root/CHANGELOG.md"
} > "$temp_file"
mv "$temp_file" "$root/CHANGELOG.md"
echo "Updated WiFiManager declarations and canonical install references to $tag."
echo "Replace the generated changelog TODO with the release summary, then run scripts/check-docs.sh and scripts/prepare-release.sh $tag."
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 --port /dev/serial/by-id/... [--timeout seconds]" >&2
exit 2
}
port=""
timeout_seconds=300
while [[ $# -gt 0 ]]; do
case "$1" in
--port) [[ $# -ge 2 ]] || usage; port="${2:-}"; shift 2 ;;
--timeout) [[ $# -ge 2 ]] || usage; timeout_seconds="${2:-}"; shift 2 ;;
*) usage ;;
esac
done
[[ -n "$port" && -e "$port" ]] || usage
[[ "$timeout_seconds" =~ ^[1-9][0-9]*$ ]] || usage
capture_file="$(mktemp -p /tmp wifimanager-unity.XXXXXX)"
monitor_pid=""
preserve_capture=false
cleanup() {
if [[ -n "$monitor_pid" ]] && kill -0 "$monitor_pid" 2>/dev/null; then
kill "$monitor_pid" 2>/dev/null || true
wait "$monitor_pid" 2>/dev/null || true
fi
if [[ "$preserve_capture" == "false" ]]; then
rm -f "$capture_file"
fi
}
trap cleanup EXIT
# Start immediately after upload. PlatformIO's interactive monitor cannot run
# without a TTY; socat opens only this port and streams its configured 115200
# baud output into the capture file without touching another board.
timeout --foreground "$timeout_seconds" socat -u "FILE:$port,raw,echo=0,b115200" STDOUT \
>"$capture_file" 2>&1 &
monitor_pid="$!"
while kill -0 "$monitor_pid" 2>/dev/null; do
if grep -aqE '[0-9]+ Tests [0-9]+ Failures' "$capture_file"; then
kill "$monitor_pid" 2>/dev/null || true
wait "$monitor_pid" 2>/dev/null || true
monitor_pid=""
if grep -aq "Tests 0 Failures" "$capture_file" && grep -aq "^OK" "$capture_file"; then
grep -aE '\[METRIC\]|Tests [0-9]+ Failures|^OK$' "$capture_file" || true
exit 0
fi
echo "Unity reported a test failure:" >&2
grep -anE ':FAIL|FAIL$|\[METRIC\]|Tests [0-9]+ Failures' "$capture_file" >&2 || true
tail -n 80 "$capture_file" >&2 || true
preserve_capture=true
echo "Full serial capture retained at $capture_file" >&2
exit 1
fi
sleep 0.25
done
wait "$monitor_pid" || true
monitor_pid=""
preserve_capture=true
echo "Serial monitoring ended before Unity produced a summary; capture retained at $capture_file" >&2
exit 1
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
failed=0
check_cpp_fence_scope() {
local markdown="$1"
awk '
function brace_delta(line, copy) {
copy = line
return gsub(/\{/, "{", copy) - gsub(/\}/, "}", copy)
}
/^```cpp[[:space:]]*$/ { in_cpp = 1; depth = 0; next }
in_cpp && /^```[[:space:]]*$/ { in_cpp = 0; next }
in_cpp {
line = $0
sub(/^[[:space:]]+/, "", line)
if (depth == 0 &&
(line ~ /^(if|for|while|switch)[[:space:]]*\(/ ||
line ~ /^[A-Za-z_][A-Za-z0-9_:]*::[A-Za-z0-9_]+[[:space:]]*\(/ ||
line ~ /^[A-Za-z_][A-Za-z0-9_]*\./ ||
line ~ /^[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\(/)) {
printf "%s:%d: C++ expression appears at namespace scope; wrap it in a function.\n", FILENAME, FNR > "/dev/stderr"
failed = 1
}
depth += brace_delta($0)
}
END { exit failed }
' "$markdown"
}
link_pattern='\]\(([^ )]+)'
while IFS= read -r file; do
in_fence=false
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*(\`\`\`|~~~) ]]; then
[[ "$in_fence" == true ]] && in_fence=false || in_fence=true
continue
fi
[[ "$in_fence" == true ]] && continue
remainder="$line"
while [[ "$remainder" =~ $link_pattern ]]; do
target="${BASH_REMATCH[1]}"
remainder="${remainder#*]($target)}"
case "$target" in
\#*|http://*|https://*|mailto:*|tel:*) continue ;;
esac
target="${target%%#*}"
[[ -z "$target" ]] && continue
if [[ "$target" == /* ]]; then
candidate="$root/${target#/}"
else
candidate="$(dirname "$file")/$target"
fi
if [[ ! -e "$candidate" ]]; then
printf 'Broken local Markdown link: %s -> %s\n' "${file#$root/}" "$target" >&2
failed=1
fi
done
done < "$file"
check_cpp_fence_scope "$file" || failed=1
done < <(find "$root" -path "$root/.git" -prune -o -path '*/.pio' -prune -o -type f -name '*.md' -print)
for required in README.md CHANGELOG.md docs/README.md docs/GETTING_STARTED.md docs/PORTAL_UI.md docs/PORTAL_API.md docs/TESTING.md docs/DEVELOPMENT.md; do
if [[ ! -f "$root/$required" ]]; then
printf 'Missing required documentation file: %s\n' "$required" >&2
failed=1
fi
done
check_readme_media() {
local asset="$1"
local expected_type="$2"
local max_bytes="$3"
local path="$root/docs/assets/readme/$asset"
if [[ ! -s "$path" ]]; then
printf 'Missing README media asset: %s\n' "docs/assets/readme/$asset" >&2
failed=1
return
fi
if [[ "$(file --brief --mime-type "$path")" != "$expected_type" ]]; then
printf 'Unexpected README media type: %s\n' "docs/assets/readme/$asset" >&2
failed=1
fi
if (( $(wc -c < "$path") > max_bytes )); then
printf 'README media exceeds its size limit: %s\n' "docs/assets/readme/$asset" >&2
failed=1
fi
}
check_readme_media portal-tour.gif image/gif $((2 * 1024 * 1024))
check_readme_media portal-overview.png image/png $((1024 * 1024))
check_readme_media portal-wifi-settings.png image/png $((1024 * 1024))
if [[ -n "$(git -C "$root" ls-files -- 'artifacts/readme-media/**')" ]]; then
printf 'Ignored README media artifacts must not be tracked.\n' >&2
failed=1
fi
while IFS= read -r example; do
for required in README.md platformio.ini; do
if [[ ! -f "$example/$required" ]]; then
printf 'Incomplete example: %s is missing %s\n' "${example#$root/}" "$required" >&2
failed=1
fi
done
if ! find "$example" -maxdepth 2 -type f \( -name '*.ino' -o -name '*.cpp' \) -print -quit | grep -q .; then
printf 'Incomplete example: %s has no sketch source\n' "${example#$root/}" >&2
failed=1
fi
done < <(find "$root/examples" -mindepth 1 -maxdepth 1 -type d -print | sort)
if [[ "$failed" -ne 0 ]]; then
exit 1
fi
echo "WiFiManager documentation checks passed"
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 vMAJOR.MINOR.PATCH [--tag]"
exit 2
}
tag="${1:-}"
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || usage
[[ "${2:-}" == "" || "${2:-}" == "--tag" ]] || usage
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/lib/platformio.sh
source "$root/tools/lib/platformio.sh"
version="${tag#v}"
manifest_version="$(sed -n 's/.*"version": "\([^"]*\)".*/\1/p' "$root/library.json" | head -n 1)"
if [[ "$manifest_version" != "$version" ]]; then
echo "library.json is $manifest_version; expected $version for $tag" >&2
exit 1
fi
grep -q "^## $version$" "$root/CHANGELOG.md" || {
echo "CHANGELOG.md has no $version heading" >&2
exit 1
}
if [[ -f "$root/library.properties" ]]; then
properties_version="$(sed -n 's/^version=//p' "$root/library.properties" | head -n 1)"
if [[ "$properties_version" != "$version" ]]; then
echo "library.properties is $properties_version; expected $version for $tag" >&2
exit 1
fi
fi
if awk -v heading="## $version" '
$0 == heading { found = 1; next }
found && /^## / { exit }
found { print }
' "$root/CHANGELOG.md" | grep -Fq 'TODO: Describe this release.'; then
echo "CHANGELOG.md still has the generated TODO for $version" >&2
exit 1
fi
repo_url="https://github.com/alexhopeoconnor/WiFiManager.git"
validate_reference() {
local file="$1"
local reference_count
reference_count="$(grep -F "$repo_url#v" "$root/$file" | wc -l)"
[[ "$reference_count" -eq 1 ]] || { echo "$file must contain exactly one canonical release reference" >&2; exit 1; }
grep -Fq "$repo_url#$tag" "$root/$file" || { echo "$file does not reference $tag" >&2; exit 1; }
}
validate_reference README.md
validate_reference docs/GETTING_STARTED.md
git -C "$root" diff --check
package_dir="$(mktemp -d)"
trap 'rm -rf "$package_dir"' EXIT
wm_pio pkg pack "$root" --output "$package_dir/package.tar.gz" >/dev/null
echo "Validated release metadata and PlatformIO package for $tag"
if [[ "${2:-}" == "--tag" ]]; then
git -C "$root" diff --quiet
git -C "$root" diff --cached --quiet
git -C "$root" tag -a "$tag" -m "Release $tag"
echo "Created $tag. Push the branch and tag; GitHub Actions will publish the release."
fi
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
tag="${1:-}"
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
echo "Usage: $0 vMAJOR.MINOR.PATCH" >&2
exit 2
}
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
version="${tag#v}"
notes="$(mktemp)"
trap 'rm -f "$notes"' EXIT
awk -v heading="## ${version}" '
$0 == heading { found = 1; next }
found && /^## / { exit }
found { print }
END { if (!found) exit 1 }
' "$root/CHANGELOG.md" > "$notes" || {
echo "CHANGELOG.md has no ${version} section" >&2
exit 1
}
if [[ ! -s "$notes" ]]; then
echo "No release notes found for $tag in CHANGELOG.md" >&2
exit 1
fi
printf '%s\n\n' "# WiFiManager $tag"
cat "$notes"
+176
View File
@@ -0,0 +1,176 @@
#!/usr/bin/env bash
set -euo pipefail
# Keep standalone compilation predictable on laptops and shared workstations.
# A developer may explicitly raise this for an isolated local diagnosis.
export PLATFORMIO_RUN_JOBS="${PLATFORMIO_RUN_JOBS:-2}"
usage() {
cat <<'USAGE' >&2
Usage:
./scripts/test.sh compile --platform esp8266|esp32
./scripts/test.sh unity --platform esp8266|esp32
./scripts/test.sh examples --platform esp8266|esp32
./scripts/test.sh ota-fixtures --platform esp8266|esp32
./scripts/test.sh hardware --platform esp8266|esp32 --port /dev/serial/by-id/...
USAGE
exit 2
}
mode="${1:-}"
[[ "$mode" == "compile" || "$mode" == "unity" || "$mode" == "examples" || "$mode" == "ota-fixtures" || "$mode" == "hardware" ]] || usage
shift
platform=""
port=""
while [[ $# -gt 0 ]]; do
case "$1" in
--platform) [[ $# -ge 2 ]] || usage; platform="${2:-}"; shift 2 ;;
--port) [[ $# -ge 2 ]] || usage; port="${2:-}"; shift 2 ;;
*) usage ;;
esac
done
case "$platform" in
esp8266|esp32) environment="$platform" ;;
*) usage ;;
esac
[[ "$mode" != "hardware" || -n "$port" ]] || usage
[[ "$mode" != "hardware" || -e "$port" ]] || { echo "Serial port not found: $port" >&2; exit 1; }
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/lib/platformio.sh
source "$root/tools/lib/platformio.sh"
# shellcheck source=tools/lib/ota-fixture-identity.sh
source "$root/tools/lib/ota-fixture-identity.sh"
pio_for_platform() {
if [[ "$platform" != "esp32" ]]; then
wm_pio "$@"
return
fi
# Keep the maintained Core 3.3.11 package form in a persistent project
# cache shared by the maintained framework repositories. It is never
# cleared by this script and avoids stale global package metadata selecting
# an incompatible uploader without redownloading this same pinned graph.
local core_dir packages_dir cache_dir
core_dir="${WIFIMANAGER_PLATFORMIO_CORE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/arduino-framework-platformio/core-3.3.11}"
packages_dir="${WIFIMANAGER_PLATFORMIO_PACKAGES_DIR:-$core_dir/packages}"
cache_dir="${WIFIMANAGER_PLATFORMIO_CACHE_DIR:-$core_dir/cache}"
install -d -m 700 "$core_dir" "$packages_dir" "$cache_dir"
PLATFORMIO_CORE_DIR="$core_dir" PLATFORMIO_PACKAGES_DIR="$packages_dir" \
PLATFORMIO_CACHE_DIR="$cache_dir" wm_pio "$@"
}
assert_ota_fixture_pair() {
local firmware_a="$1" firmware_b="$2" firmware size capacity
[[ -s "$firmware_a" && -s "$firmware_b" ]] || {
echo "Portal OTA fixture build did not produce both A and B images." >&2
return 1
}
if cmp -s "$firmware_a" "$firmware_b"; then
echo "Portal OTA fixture A and B are identical." >&2
return 1
fi
if [[ "$platform" == "esp32" ]]; then
capacity=$((0x1F0000))
for firmware in "$firmware_a" "$firmware_b"; do
size="$(wc -c < "$firmware" | tr -d '[:space:]')"
(( size <= capacity )) || {
echo "ESP32 OTA fixture $(basename "$firmware") is $size bytes; it exceeds the $capacity-byte app slot." >&2
return 1
}
done
fi
}
if [[ "$mode" == "hardware" ]]; then
# Unity uses only the named serial device; it does not own a portal AP or
# secondary adapter, so it may run beside an unrelated station test.
# shellcheck source=tools/lib/harness-locks.sh
source "$root/tools/lib/harness-locks.sh"
wm_harness_lock_serial_port "$port"
fi
if [[ "$mode" == "examples" ]]; then
mapfile -t examples < <(find "$root/examples" -mindepth 2 -maxdepth 2 -type f -name platformio.ini -printf '%h\n' | sort)
if (( ${#examples[@]} == 0 )); then
echo "No example projects found" >&2
exit 1
fi
for example in "${examples[@]}"; do
pio_for_platform run -d "$example" -e "$environment" </dev/null
done
echo "WiFiManager examples compile check passed for $platform"
exit 0
fi
if [[ "$mode" == "ota-fixtures" ]]; then
fixture_environment="${platform}_ota"
if [[ "$platform" == "esp32" ]]; then
"$root/tools/check-ota-partitions.sh"
fi
# The A/B marker is the only changed source input. Capture each resulting
# binary before rebuilding the same platform environment so CI proves the
# update images differ without paying for duplicate dependency builds.
fixture_dir="$(mktemp -d "${TMPDIR:-/tmp}/wifimanager-ota-fixtures.XXXXXX")"
chmod 700 "$fixture_dir"
export WIFIMANAGER_OTA_IDENTITY_DIR="$fixture_dir/identity"
fixture_build_dir="$fixture_dir/build/$fixture_environment"
wm_lock_ota_fixture_environment "$fixture_environment"
wm_write_ota_fixture_identity A
fixture_a="$fixture_dir/ota-a.bin"
fixture_b="$fixture_dir/ota-b.bin"
cleanup_ota_fixture_build() {
wm_remove_ota_fixture_identity
rm -rf -- "$fixture_dir"
}
on_ota_fixture_build_signal() {
local status="$1"
# Remove the generated identity before leaving. EXIT will call the
# same idempotent cleanup once more, which is intentional.
trap - HUP INT TERM
cleanup_ota_fixture_build
exit "$status"
}
trap cleanup_ota_fixture_build EXIT
trap 'on_ota_fixture_build_signal 129' HUP
trap 'on_ota_fixture_build_signal 130' INT
trap 'on_ota_fixture_build_signal 143' TERM
PLATFORMIO_BUILD_DIR="$fixture_dir/build" \
pio_for_platform run -d "$root/test/portal-harness" -e "$fixture_environment" </dev/null
install -m 600 "$fixture_build_dir/firmware.bin" "$fixture_a"
wm_write_ota_fixture_identity B
PLATFORMIO_BUILD_DIR="$fixture_dir/build" \
pio_for_platform run -d "$root/test/portal-harness" -e "$fixture_environment" </dev/null
install -m 600 "$fixture_build_dir/firmware.bin" "$fixture_b"
assert_ota_fixture_pair "$fixture_a" "$fixture_b"
echo "WiFiManager portal OTA fixture compile check passed for $platform"
exit 0
fi
if [[ "$mode" == "unity" ]]; then
# Compile WiFiManager's own fixtures without a board. This is separate
# from the clean-consumer fixture, which protects manifest resolution.
pio_for_platform test -d "$root" -e "$environment" --filter test_wifimanager \
--without-uploading --without-testing
echo "WiFiManager Unity compile check passed for $platform"
exit 0
fi
if [[ "$mode" == "hardware" ]]; then
# Upload first, then capture from the normal boot reset. The Unity sketch
# deliberately waits two seconds before it begins its test sequence.
pio_for_platform test -d "$root" -e "$platform" --filter test_wifimanager \
--upload-port "$port" --without-testing
"$root/scripts/capture-unity-serial.sh" --port "$port" --timeout 300
echo "WiFiManager hardware test passed for $platform on $port"
exit 0
fi
pio_for_platform run -d "$root/test/compile-project" -e "$environment"
echo "WiFiManager consumer compile check passed for $platform"
+32
View File
@@ -0,0 +1,32 @@
[platformio]
default_envs = esp8266
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
build_flags =
-DWM_LOG_LEVEL=3
lib_deps =
${common.lib_deps}
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
-DWM_LOG_LEVEL=3
lib_deps =
${common.lib_deps}
+46
View File
@@ -0,0 +1,46 @@
#include <Arduino.h>
#include <WiFiManager.h>
namespace {
const char kTitle[] PROGMEM = "Set up Compile Fixture";
const char kIdentity[] PROGMEM = "WiFiManager";
const char kTagline[] PROGMEM = "A branded portal compile check.";
const char kLogoAlt[] PROGMEM = "WiFiManager";
const char kLogo[] PROGMEM = "<svg viewBox='0 0 24 24'></svg>";
const char kPage[] PROGMEM = "#f4f7f3";
const char kSurface[] PROGMEM = "#ffffff";
const char kText[] PROGMEM = "#1c251e";
const char kMuted[] PROGMEM = "#607064";
const char kBorder[] PROGMEM = "#d6e0d7";
const char kAccent[] PROGMEM = "#347a45";
const char kAccentHover[] PROGMEM = "#245a32";
const char kAccentText[] PROGMEM = "#ffffff";
const WiFiManagerPortalConfig kPortalConfig = {
WiFiManagerPortalText::progmem(kTitle),
WiFiManagerPortalText::progmem(kIdentity),
WiFiManagerPortalText::progmem(kTagline),
WiFiManagerPortalAsset::svgFromProgmem(kLogo),
WiFiManagerPortalText::progmem(kLogoAlt),
{
WiFiManagerPortalText::progmem(kPage),
WiFiManagerPortalText::progmem(kSurface),
WiFiManagerPortalText::progmem(kText),
WiFiManagerPortalText::progmem(kMuted),
WiFiManagerPortalText::progmem(kBorder),
WiFiManagerPortalText::progmem(kAccent),
WiFiManagerPortalText::progmem(kAccentHover),
WiFiManagerPortalText::progmem(kAccentText),
{}, {}, {}, 10, 6,
},
};
} // namespace
WiFiManager wifiManager;
void setup() {
wifiManager.setPortalConfig(kPortalConfig);
wifiManager.setConfigPortalTimeout(1);
}
void loop() {}
+52
View File
@@ -0,0 +1,52 @@
# Portal browser harness
This test fixture starts only the WiFiManager captive portal. It intentionally has no station credentials, MQTT configuration, DeviceFramework dependency, or application logic.
Use it through the repository runner so a secondary Wi-Fi adapter is explicitly selected and protected from becoming the host default route:
```bash
./tools/portal-hardware run \
--platform esp8266 \
--port /dev/serial/by-id/... \
--client-interface wlx...
```
The ESP8266 portal SSID is `WM Test Harness ESP8266`; the ESP32 SSID is `WM Test Harness ESP32`. Both use `default1` exclusively for local development tests.
The runner cleans up only the temporary connection it creates on the named secondary interface. It refuses to run if that interface is the system default route.
NetworkManager authority is a host prerequisite, not a fixture secret. A GUI
Polkit session may authorize the adapter directly; a headless/SSH invocation
validates sudo before flashing, then elevates only the generated portal
connection actions. Leave the runner itself unprivileged so its private state
and browser artifacts remain owned by the developer. See
[`docs/TESTING.md`](../../docs/TESTING.md#networkmanager-authorization) for
the `WM_NMCLI_AUTH` options.
## A/B portal OTA fixture
The physical portal HTTP OTA test harness uses one `*_ota` environment per
platform. It writes a harness-only A/B identity header to an ignored, owner-only
directory unique to that run before each build, so PlatformIO reuses dependency
objects while the fixture-only `/api/test/firmware-marker` endpoint still proves
the newly booted image. The test harness requires the real form's successful response, its automatic
restart, and two fresh B-marker responses. Passive serial capture is retained
for failure diagnosis, but a product log-message wording change cannot turn a
successful A-to-B update into a failed test.
```bash
./tools/portal-hardware ota \
--platform esp32 \
--port /dev/serial/by-id/... \
--client-interface wlx...
```
ESP8266 explicitly uses `eagle.flash.4m1m.ld`. ESP32 uses the tracked two-slot
`partitions/esp32_ota_4m_no_fs.csv` layout on the maintained Arduino-ESP32
3.3.11 fixture lane. Both are 4 MB layouts. The runner builds and preserves A
and B before it touches the board, validates the matching ESP32 slots (or the
live ESP8266 updater capacity), then erases the explicitly selected test board
before serial-flashing A. A successful run leaves B installed in the
portal-only fixture. It requires Python PySerial and retains a passive,
no-reset `serial-ota.log` in the private run artifact directory for both
success and failure diagnosis.
@@ -0,0 +1,12 @@
# 4 MB ESP32 portal-harness OTA test layout.
#
# The fixture compiles portal assets into the application image, so it uses no
# filesystem. app0 and app1 are equal 0x1F0000-byte slots. The portal OTA
# runner validates B against that inactive-slot size before it flashes A or
# submits the browser upload.
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1F0000,
app1, app, ota_1, 0x200000, 0x1F0000,
coredump, data, coredump,0x3F0000, 0x10000,
1 # 4 MB ESP32 portal-harness OTA test layout.
2 #
3 # The fixture compiles portal assets into the application image, so it uses no
4 # filesystem. app0 and app1 are equal 0x1F0000-byte slots. The portal OTA
5 # runner validates B against that inactive-slot size before it flashes A or
6 # submits the browser upload.
7 # Name, Type, SubType, Offset, Size, Flags
8 nvs, data, nvs, 0x9000, 0x5000,
9 otadata, data, ota, 0xe000, 0x2000,
10 app0, app, ota_0, 0x10000, 0x1F0000,
11 app1, app, ota_1, 0x200000, 0x1F0000,
12 coredump, data, coredump,0x3F0000, 0x10000,
+50
View File
@@ -0,0 +1,50 @@
[platformio]
default_envs = esp8266
[common]
framework = arduino
lib_ldf_mode = deep+
lib_deps =
WiFiManager=symlink://../..
build_flags =
extra_scripts =
pre:tools/ota_fixture_input.py
[env:esp8266]
extends = common
platform = espressif8266
board = d1_mini
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#521ae60a89e64bb0d1eb7a0b7addf620ced5cad3
build_flags =
-DWM_LOG_LEVEL=4
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-DSOC_WIFI_SUPPORTED=1
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
-DWM_LOG_LEVEL=4
; The OTA test harness writes its A/B marker into an ignored header included
; only by the portal fixture. One environment per platform keeps the explicit
; update layout while allowing the A-to-B rebuild to reuse every library object.
[env:esp8266_ota]
extends = env:esp8266
board_build.ldscript = eagle.flash.4m1m.ld
build_flags =
${env:esp8266.build_flags}
${common.build_flags}
-DWM_PORTAL_OTA_TEST=1
[env:esp32_ota]
extends = env:esp32
board_build.partitions = partitions/esp32_ota_4m_no_fs.csv
build_flags =
${env:esp32.build_flags}
${common.build_flags}
-DWM_PORTAL_OTA_TEST=1
+137
View File
@@ -0,0 +1,137 @@
#include <Arduino.h>
#include <WiFiManager.h>
namespace {
// These markers belong only to the portal OTA fixture. The hardware runner
// writes the ignored header immediately before each A/B build, so the marker
// is compiled into firmware rather than saved in WiFiManager settings.
#if defined(WM_PORTAL_OTA_TEST)
#include <ota_fixture_identity.h>
#ifndef WM_OTA_FIXTURE_IMAGE
#error "Portal OTA fixture identity is missing."
#endif
// PlatformIO releases the serial port only after the upload-triggered reset.
// The physical OTA test harness then attaches passively, so give it the same
// explicit window as the DeviceFramework A/B fixtures before boot evidence or
// portal work begins. Normal portal test-harness builds keep the short delay.
constexpr unsigned long kSerialMonitorAttachDelayMs = 5000UL;
#else
#define WM_OTA_FIXTURE_IMAGE "portal-harness"
constexpr unsigned long kSerialMonitorAttachDelayMs = 300UL;
#endif
#if defined(ESP8266)
constexpr char kPortalSsid[] = "WM Test Harness ESP8266";
#else
constexpr char kPortalSsid[] = "WM Test Harness ESP32";
#endif
constexpr char kPortalPassword[] = "default1";
WiFiManager wifi;
WiFiManagerParameter kInstallationLabel(
"installation_label", "Installation label", "Harness fixture", 32);
// Keep the characters from upstream issue #1863 in the portal fixture. The
// browser test harness verifies this value through JSON, DOM rendering, save,
// and a subsequent reload rather than relying on a string-only serializer
// check.
WiFiManagerParameter kEscapedValue(
"escaped_value", "Escaped value", "7(f+4]2y3fsYTQt'Uhxc\"d\\<>&", 64);
WiFiManagerParameter kMqttHost(
"mqtt_host", "MQTT host", "broker.example.local", 64);
WiFiManagerParameter kMqttPort(
"mqtt_port", "MQTT port", "1883", 8);
WiFiManagerParameter kDeviceRoom(
"device_room", "Device room", "Workshop", 32);
WiFiManagerParameter kSensorName(
"sensor_name", "Sensor name", "Ambient temperature", 48);
WiFiManagerParameter kTelemetryTopic(
"telemetry_topic", "Telemetry topic", "sensors/ambient/temperature", 64);
WiFiManagerParameter kTimezone(
"timezone", "Timezone", "Australia/Brisbane", 48);
WiFiManagerParameter kLatitude(
"latitude", "Latitude", "-27.4698", 16);
WiFiManagerParameter kLongitude(
"longitude", "Longitude", "153.0251", 16);
WiFiManagerParameter kFirmwareChannel(
"firmware_channel", "Firmware channel", "stable", 16);
WiFiManagerParameter kOwnerName(
"owner_name", "Owner name", "Portal test harness", 48);
WiFiManagerParameter kNotes(
"notes", "Notes", "Thirteen-field rendering fixture", 64);
WiFiManagerParameter* const kPortalParameters[] = {
&kInstallationLabel,
&kEscapedValue,
&kMqttHost,
&kMqttPort,
&kDeviceRoom,
&kSensorName,
&kTelemetryTopic,
&kTimezone,
&kLatitude,
&kLongitude,
&kFirmwareChannel,
&kOwnerName,
&kNotes,
};
void registerOtaTestMarker() {
// setWebServerCallback runs after WiFiManager creates its server and
// before it registers built-in routes. This private fixture endpoint is
// intentionally not a WiFiManager product API.
wifi.setWebServerCallback([]() {
AsyncWebServer* const server = wifi.getServer();
if (server == nullptr) {
return;
}
server->on("/api/test/firmware-marker", HTTP_GET,
[](AsyncWebServerRequest* request) {
String response = F("{\"marker\":\"");
response += WM_OTA_FIXTURE_IMAGE;
response += F("\",\"freeSketchSpace\":");
response += String(ESP.getFreeSketchSpace());
response += F("}");
request->send(200, "application/json", response);
});
});
}
} // namespace
void setup() {
Serial.begin(115200);
delay(kSerialMonitorAttachDelayMs);
// The physical HTTP OTA test harness records this immutable marker before
// and after its browser upload. It cannot be faked by saved portal values
// or an HTTP response from a stale image.
Serial.print(F("WiFiManager portal OTA fixture image: "));
Serial.println(WM_OTA_FIXTURE_IMAGE);
// This fixture must be independent of whichever sketch was previously
// flashed to the board. Clear saved station credentials before starting
// the portal so browser artifacts always show the unconfigured flow.
wifi.resetSettings();
// A finite window exercises timeout reset without leaving a board in a
// permanent portal.
wifi.setConfigPortalTimeout(15 * 60);
wifi.setAPStaticIPConfig(
IPAddress(192, 168, 4, 1),
IPAddress(192, 168, 4, 1),
IPAddress(255, 255, 255, 0));
registerOtaTestMarker();
// Keep custom parameters on their own native Save parameters page. This
// lets the browser test harness exercise a parameter-only submit without
// starting a station connection as part of the regression test.
wifi.portalSetLayoutParamsLocation(PortalParamsLocation::SetupPage);
for (auto* parameter : kPortalParameters) {
wifi.portalAddParameter(parameter);
}
wifi.startConfigPortal(kPortalSsid, kPortalPassword);
}
void loop() {
wifi.process();
}
@@ -0,0 +1,23 @@
"""Add the run-owned A/B identity directory to this portal test-harness build."""
import os
from SCons.Script import Exit
Import("env")
if env["PIOENV"].endswith("_ota"):
identity_dir = os.environ.get("WIFIMANAGER_OTA_IDENTITY_DIR")
if not identity_dir:
print(
"WIFIMANAGER_OTA_IDENTITY_DIR is required; "
"run this fixture through its named test harness."
)
Exit(1)
identity_header = os.path.join(identity_dir, "ota_fixture_identity.h")
if not os.path.isfile(identity_header):
print(f"OTA fixture identity header is missing: {identity_header}")
Exit(1)
env.Append(CPPPATH=[identity_dir])
+5
View File
@@ -0,0 +1,5 @@
# Ignored local credentials for the optional station handoff test.
# The runner copies only these two values into a private one-run file mounted
# read-only into Docker; any other local env entries are not passed through.
WIFI_SSID=replace-me
WIFI_PASSWORD=replace-me
+188
View File
@@ -0,0 +1,188 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include "test_main.h"
// Test case array
TestCase tests[] = {
// Basic tests
TEST_ENTRY(test_basic_wifimanager_instantiation),
TEST_ENTRY(test_reset_settings),
// JSON API shape (buildApiInfoJson is large — run with fresh heap, before stress tests)
TEST_ENTRY(test_captive_redirect_host_rule),
TEST_ENTRY(test_api_wifi_meta_json_shape),
TEST_ENTRY(test_api_wifi_meta_password_field_type),
TEST_ENTRY(test_api_wifi_connect_status_success_redirect),
TEST_ENTRY(test_profile_portal_success_keeps_handoff_alive),
TEST_ENTRY(test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path),
TEST_ENTRY(test_api_info_json_shape),
TEST_ENTRY(test_api_params_json_shape),
TEST_ENTRY(test_api_params_json_escapes_custom_parameter_value),
TEST_ENTRY(test_api_status_json_shape),
// Configuration tests
TEST_ENTRY(test_set_and_get_hostname),
TEST_ENTRY(test_get_default_ap_name),
TEST_ENTRY(test_get_wifi_status_string),
TEST_ENTRY(test_get_mode_string),
TEST_ENTRY(test_get_rssi_as_quality),
// Portal lifecycle tests
TEST_ENTRY(test_start_config_portal),
TEST_ENTRY(test_start_config_portal_with_password),
TEST_ENTRY(test_start_config_portal_auto_name),
TEST_ENTRY(test_stop_config_portal),
TEST_ENTRY(test_config_portal_infrastructure),
TEST_ENTRY(test_start_web_portal),
TEST_ENTRY(test_stop_web_portal),
TEST_ENTRY(test_config_portal_multiple_start_stop),
TEST_ENTRY(test_config_portal_already_active),
TEST_ENTRY(test_get_config_portal_ssid),
TEST_ENTRY(test_bootstrap_json_portal_feature_flags),
TEST_ENTRY(test_portal_default_presentation),
TEST_ENTRY(test_bootstrap_json_schema_v3),
TEST_ENTRY(test_bootstrap_json_snapshot_consistency),
TEST_ENTRY(test_root_render_interleaved_context_isolation),
TEST_ENTRY(test_portal_presentation_configuration),
// Non-blocking tests
TEST_ENTRY(test_nonblocking_process),
TEST_ENTRY(test_client_check_setters),
TEST_ENTRY(test_process_required_for_timeout),
// Callback tests
TEST_ENTRY(test_ap_callback),
TEST_ENTRY(test_web_server_callback),
TEST_ENTRY(test_multiple_callbacks),
// Parameter tests
TEST_ENTRY(test_create_parameter),
TEST_ENTRY(test_add_parameter),
TEST_ENTRY(test_get_parameters),
TEST_ENTRY(test_parameter_with_custom_html),
TEST_ENTRY(test_parameter_value_length),
TEST_ENTRY(test_parameter_label_placement),
TEST_ENTRY(test_multiple_parameters),
TEST_ENTRY(test_parameter_placeholder),
// Static IP tests
TEST_ENTRY(test_set_ap_static_ip_config),
TEST_ENTRY(test_ap_static_ip_application),
// WiFi connection tests
TEST_ENTRY(test_autoconnect_fallback_to_portal),
TEST_ENTRY(test_connectwifi_ssid_not_found),
TEST_ENTRY(test_connection_state_transitions),
TEST_ENTRY(test_autoconnect_with_timeout),
// Callback firing tests
TEST_ENTRY(test_timeout_callback_fires),
TEST_ENTRY(test_config_reset_callback_fires),
TEST_ENTRY(test_ap_callback_fires_improved),
TEST_ENTRY(test_web_server_callback_fires_improved),
// DNS lifecycle tests
TEST_ENTRY(test_dns_server_created),
TEST_ENTRY(test_dns_server_cleanup),
TEST_ENTRY(test_dns_server_lifecycle_cycles),
// Error condition tests
TEST_ENTRY(test_connection_failure_handling),
TEST_ENTRY(test_resource_cleanup_after_error),
TEST_ENTRY(test_multiple_rapid_start_stop),
// Parameter value tests
TEST_ENTRY(test_parameter_value_set_directly),
TEST_ENTRY(test_parameter_value_length_validation),
TEST_ENTRY(test_parameter_value_persistence),
TEST_ENTRY(test_parameter_value_update),
TEST_ENTRY(test_multiple_parameters_different_values),
// WiFi scanning tests
TEST_ENTRY(test_wifi_scan_initiates),
TEST_ENTRY(test_async_scan_behavior),
TEST_ENTRY(test_scan_status_checking),
TEST_ENTRY(test_scan_completion_wait),
TEST_ENTRY(test_scan_cancels_when_connect_pending),
TEST_ENTRY(test_scan_cancels_when_lifecycle_blocked),
TEST_ENTRY(test_scan_generation_invalidated_on_reset),
TEST_ENTRY(test_scan_restart_interval_is_platform_appropriate),
TEST_ENTRY(test_real_async_scan_completes),
// Template rendering tests
TEST_ENTRY(test_shell_template_renders_core_placeholders),
TEST_ENTRY(test_shell_template_renders_dynamic_theme_with_percent_values),
// State transition tests
TEST_ENTRY(test_portal_to_connected_transition),
TEST_ENTRY(test_concurrent_operations),
TEST_ENTRY(test_state_consistency_during_portal),
TEST_ENTRY(test_state_transitions_multiple_cycles),
// Integration tests
TEST_ENTRY(test_autoconnect_fallback_flow),
TEST_ENTRY(test_portal_lifecycle_with_connection_attempt),
TEST_ENTRY(test_parameter_add_and_retrieve),
TEST_ENTRY(test_complete_flow_reset_autoconnect_portal),
TEST_ENTRY(test_portal_with_parameters_and_infrastructure),
// Stress tests
TEST_ENTRY(test_many_start_stop_cycles),
TEST_ENTRY(test_long_running_portal),
TEST_ENTRY(test_rapid_portal_start_stop),
TEST_ENTRY(test_multiple_parameters_stress),
TEST_ENTRY(test_portal_with_timeout_stress),
TEST_ENTRY(test_portal_resource_recovery),
TEST_ENTRY(test_scan_result_storage_released_when_portal_closes),
};
const size_t TEST_COUNT = sizeof(tests) / sizeof(TestCase);
// Test state variables
size_t next_index = 0;
bool begun = false;
// Test setup and teardown
void setUp(void) {
// No per-test setup needed
}
void tearDown(void) {
// No per-test teardown needed
}
// Arduino setup and loop functions (required by framework)
void setup() {
Serial.begin(115200);
delay(2000); // Give time for serial to initialize
Serial.println("\n[TEST] =============================================");
Serial.println("[TEST] === WiFiManager Test Setup ===");
Serial.println("[TEST] Starting WiFiManager tests...");
Serial.println("[TEST] =============================================");
UNITY_BEGIN(); // Start Unity test framework
begun = true; // Start tests immediately
}
void loop() {
// Run one test and return immediately
if (begun && next_index < TEST_COUNT) {
TestCase& t = tests[next_index];
Serial.print("\n[TEST] ==== Running test: ");
Serial.print(t.name);
Serial.println(" ====");
UnityDefaultTestRun(t.fn, t.name, t.line);
next_index++;
return; // yield quickly
}
// All tests completed
if (begun && next_index >= TEST_COUNT) {
Serial.println("\n[TEST] =============================================");
Serial.println("[TEST] === All tests completed ===");
Serial.println("[TEST] =============================================");
UNITY_END(); // prints Unity summary
begun = false; // avoid repeating
}
}
+151
View File
@@ -0,0 +1,151 @@
#ifndef TEST_MAIN_H
#define TEST_MAIN_H
#include <Arduino.h>
// Test function type
using TestFn = void(*)();
// Test case structure
struct TestCase {
const char* name;
TestFn fn;
uint16_t line;
};
#define TEST_ENTRY(fn) { #fn, fn, __LINE__ }
// Basic tests
void test_basic_wifimanager_instantiation();
void test_reset_settings();
// Configuration tests
void test_set_and_get_hostname();
void test_get_default_ap_name();
void test_get_wifi_status_string();
void test_get_mode_string();
void test_get_rssi_as_quality();
// Portal lifecycle tests
void test_start_config_portal();
void test_start_config_portal_with_password();
void test_start_config_portal_auto_name();
void test_stop_config_portal();
void test_config_portal_infrastructure();
void test_start_web_portal();
void test_stop_web_portal();
void test_config_portal_multiple_start_stop();
void test_config_portal_already_active();
void test_get_config_portal_ssid();
void test_bootstrap_json_portal_feature_flags();
void test_portal_default_presentation();
void test_bootstrap_json_schema_v3();
void test_bootstrap_json_snapshot_consistency();
void test_root_render_interleaved_context_isolation();
void test_portal_presentation_configuration();
// Non-blocking tests
void test_nonblocking_process();
void test_client_check_setters();
void test_process_required_for_timeout();
// Callback tests
void test_ap_callback();
void test_web_server_callback();
void test_multiple_callbacks();
// Parameter tests
void test_create_parameter();
void test_add_parameter();
void test_get_parameters();
void test_parameter_with_custom_html();
void test_parameter_value_length();
void test_parameter_label_placement();
void test_multiple_parameters();
void test_parameter_placeholder();
// Static IP tests
void test_set_ap_static_ip_config();
void test_ap_static_ip_application();
// Advanced options tests
// WiFi connection tests
void test_autoconnect_fallback_to_portal();
void test_connectwifi_ssid_not_found();
void test_connection_state_transitions();
void test_autoconnect_with_timeout();
// Callback firing tests
void test_timeout_callback_fires();
void test_config_reset_callback_fires();
void test_ap_callback_fires_improved();
void test_web_server_callback_fires_improved();
// DNS lifecycle tests
void test_dns_server_created();
void test_dns_server_cleanup();
void test_dns_server_lifecycle_cycles();
// Error condition tests
void test_connection_failure_handling();
void test_resource_cleanup_after_error();
void test_multiple_rapid_start_stop();
// Parameter value tests
void test_parameter_value_set_directly();
void test_parameter_value_length_validation();
void test_parameter_value_persistence();
void test_parameter_value_update();
void test_multiple_parameters_different_values();
// WiFi scanning tests
void test_wifi_scan_initiates();
void test_async_scan_behavior();
void test_scan_status_checking();
void test_scan_completion_wait();
void test_scan_cancels_when_connect_pending();
void test_scan_cancels_when_lifecycle_blocked();
void test_scan_generation_invalidated_on_reset();
void test_scan_restart_interval_is_platform_appropriate();
void test_real_async_scan_completes();
// Template rendering tests
void test_shell_template_renders_core_placeholders();
void test_shell_template_renders_dynamic_theme_with_percent_values();
// API JSON + captive helper tests
void test_captive_redirect_host_rule();
void test_api_wifi_meta_json_shape();
void test_api_wifi_meta_password_field_type();
void test_api_wifi_connect_status_success_redirect();
void test_profile_portal_success_keeps_handoff_alive();
void test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path();
void test_api_info_json_shape();
void test_api_params_json_shape();
void test_api_params_json_escapes_custom_parameter_value();
void test_api_status_json_shape();
// State transition tests
void test_portal_to_connected_transition();
void test_concurrent_operations();
void test_state_consistency_during_portal();
void test_state_transitions_multiple_cycles();
// Integration tests
void test_autoconnect_fallback_flow();
void test_portal_lifecycle_with_connection_attempt();
void test_parameter_add_and_retrieve();
void test_complete_flow_reset_autoconnect_portal();
void test_portal_with_parameters_and_infrastructure();
// Stress tests
void test_many_start_stop_cycles();
void test_long_running_portal();
void test_rapid_portal_start_stop();
void test_multiple_parameters_stress();
void test_portal_with_timeout_stress();
void test_portal_resource_recovery();
void test_scan_result_storage_released_when_portal_closes();
#endif // TEST_MAIN_H
@@ -0,0 +1,134 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
// Test advanced configuration options - consolidated into logical groups
// Test connection behavior options
void test_connection_behavior_options() {
Serial.println("[TEST] Testing connection behavior options...");
WiFiManager wm;
// Test connection options
wm.setBreakAfterConfig(true);
wm.setBreakAfterConfig(false);
wm.setSaveConnect(true);
wm.setSaveConnect(false);
wm.setRestorePersistent(true);
wm.setRestorePersistent(false);
wm.setConnectRetries(1);
wm.setConnectRetries(3);
wm.setConnectRetries(5);
wm.setSaveConnectTimeout(0);
wm.setSaveConnectTimeout(10);
wm.setSaveConnectTimeout(30);
wm.setEnableConfigPortal(true);
wm.setEnableConfigPortal(false);
wm.setDisableConfigPortal(true);
wm.setDisableConfigPortal(false);
wm.portalSetBehaviorConnectOnSave(true);
wm.portalSetBehaviorConnectOnSave(false);
wm.portalSetBehaviorExitAllowed(true);
wm.portalSetBehaviorExitAllowed(false);
wm.portalSetBehaviorConnectTimeoutSeconds(15);
wm.portalSetBehaviorPortalTimeoutSeconds(20);
wm.portalSetBehaviorAutoReconnect(true);
wm.portalSetBehaviorAutoReconnect(false);
wm.portalSetBehaviorApClientCheck(true);
wm.portalSetBehaviorApClientCheck(false);
wm.portalSetBehaviorWebClientCheck(true);
wm.portalSetBehaviorWebClientCheck(false);
wm.preloadWiFi("TestSSID", "TestPassword");
// All setters executed without crash
TEST_ASSERT_TRUE_MESSAGE(true, "Connection behavior options executed without crash");
Serial.println("[TEST] Connection behavior options test completed successfully");
}
// Test UI display options
void test_ui_display_options() {
Serial.println("[TEST] Testing UI display options...");
WiFiManager wm;
// Test display toggles
wm.portalSetFieldPasswordPlaceholderMode(PortalPasswordPlaceholderMode::Actual);
wm.portalSetFieldPasswordPlaceholderMode(PortalPasswordPlaceholderMode::Masked);
wm.portalSetFieldPasswordPlaceholderMode(PortalPasswordPlaceholderMode::Hidden);
wm.setScanDispPerc(true);
wm.setScanDispPerc(false);
wm.portalSetActionEraseVisible(true);
wm.portalSetActionEraseVisible(false);
wm.portalSetActionRestartVisible(true);
wm.portalSetActionRestartVisible(false);
wm.portalSetActionExitVisible(true);
wm.portalSetActionExitVisible(false);
wm.portalSetActionCloseCaptiveVisible(true);
wm.portalSetActionCloseCaptiveVisible(false);
wm.portalSetPageUpdateVisible(true);
wm.portalSetPageUpdateVisible(false);
wm.portalSetPageSetupVisible(true);
wm.portalSetPageSetupVisible(false);
wm.portalSetLayoutParamsLocation(PortalParamsLocation::WiFiPage);
wm.portalSetLayoutParamsLocation(PortalParamsLocation::SetupPage);
wm.portalSetActionBackVisible(true);
wm.portalSetActionBackVisible(false);
// All setters executed without crash
TEST_ASSERT_TRUE_MESSAGE(true, "UI display options executed without crash");
Serial.println("[TEST] UI display options test completed successfully");
}
// Test custom HTML/UI customization
void test_ui_customization() {
Serial.println("[TEST] Testing UI customization...");
WiFiManager wm;
// Minimal customization uses the complete static portal configuration.
WiFiManagerPortalConfig portal;
portal.title = WiFiManagerPortalText::ram("MyDevice");
TEST_ASSERT_TRUE(wm.setPortalConfig(portal));
// All setters executed without crash
TEST_ASSERT_TRUE_MESSAGE(true, "UI customization options executed without crash");
Serial.println("[TEST] UI customization test completed successfully");
}
void test_debug_soft_ap_config() {
Serial.println("[TEST] Testing debugSoftAPConfig()...");
WiFiManager wm;
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
// Call process() to simulate real usage
wm.process();
delay(100);
// Debug output should not crash
wm.debugSoftAPConfig();
wm.stopConfigPortal();
Serial.println("[TEST] debugSoftAPConfig() test completed successfully");
}
void test_debug_platform_info() {
Serial.println("[TEST] Testing debugPlatformInfo()...");
WiFiManager wm;
// Debug output should not crash
wm.debugPlatformInfo();
TEST_ASSERT_TRUE_MESSAGE(true, "debugPlatformInfo() executed without crash");
Serial.println("[TEST] debugPlatformInfo() test completed successfully");
}
@@ -0,0 +1,200 @@
#include <unity.h>
#include <Arduino.h>
#include <string.h>
#include <WiFiManager.h>
#include <WiFiManagerHandlers.h>
#include "../test_main.h"
void test_captive_redirect_host_rule() {
Serial.println("[TEST] Testing captive redirect host comparison...");
TEST_ASSERT_TRUE(WiFiManagerHandlers::shouldRedirectCaptiveForHost("captive.apple.com", "192.168.4.1"));
TEST_ASSERT_TRUE(WiFiManagerHandlers::shouldRedirectCaptiveForHost("192.168.4.2", "192.168.4.1"));
TEST_ASSERT_FALSE(WiFiManagerHandlers::shouldRedirectCaptiveForHost("192.168.4.1", "192.168.4.1"));
TEST_ASSERT_FALSE(WiFiManagerHandlers::shouldRedirectCaptiveForHost("example.com", ""));
Serial.println("[TEST] Captive redirect host rule test completed successfully");
}
void test_api_wifi_meta_json_shape() {
Serial.println("[TEST] Testing /api/wifi/meta JSON shape...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
String j = handlers.buildApiWifiMetaJson();
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"wifiFields\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"staticFields\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"params\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"actions\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"canRefreshScan\":true")));
WiFiManagerParameter fieldParam("mqtt_host", "MQTT host", "broker.local", 64, "placeholder='broker.local'");
WiFiManagerParameter htmlParam("<div class='wm-callout wm-callout--info'><p>GPS settings...</p></div>");
wm.portalAddParameter(&fieldParam);
wm.portalAddParameter(&htmlParam);
j = handlers.buildApiWifiMetaJson();
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"kind\":\"field\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"kind\":\"html\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"html\":\"<div class='wm-callout wm-callout--info'><p>GPS settings...</p></div>\"}")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"wifiFields\":[{\"id\":\"s\"")));
Serial.println("[TEST] WiFi meta JSON shape test completed successfully");
}
void test_api_wifi_meta_password_field_type() {
Serial.println("[TEST] Testing /api/wifi/meta password field type from custom attrs...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
WiFiManagerParameter pwd("mqttpass", "MQTT password", "secret", 24, " type='password' autocorrect='off'");
wm.portalAddParameter(&pwd);
String j = handlers.buildApiWifiMetaJson();
const char* p = j.c_str();
const char* chunk = strstr(p, "\"id\":\"mqttpass\"");
TEST_ASSERT_NOT_NULL_MESSAGE(chunk, "mqttpass param missing from meta JSON");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(chunk, "\"type\":\"password\""),
"customAttrs type=password must map to JSON type password");
Serial.println("[TEST] WiFi meta password field type test completed successfully");
}
void test_api_wifi_connect_status_success_redirect() {
Serial.println("[TEST] Testing /api/wifi/connect-status success redirect payload...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
#ifdef UNIT_TEST
wm.wmTestSetPortalConnectSuccess("WiFi connected. Redirecting to 192.168.1.42", "192.168.1.42");
#endif
String j = handlers.buildApiWifiConnectStatusJson();
const char* p = j.c_str();
TEST_ASSERT_NOT_NULL(strstr(p, "\"state\":\"success\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"stationIp\":\"192.168.1.42\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"redirectUrl\":\"http://192.168.1.42/\""));
Serial.println("[TEST] WiFi connect-status success redirect payload test completed successfully");
}
void test_profile_portal_success_keeps_handoff_alive() {
Serial.println("[TEST] Testing profile portal success hand-off delay...");
WiFiManager wm;
#ifdef UNIT_TEST
wm.wmTestCompleteProfilePortalConnectionSuccess();
TEST_ASSERT_EQUAL(WiFiManager::WM_CP_CONNECT_SUCCESS, wm.getConfigPortalConnectState());
TEST_ASSERT_TRUE_MESSAGE(
wm.isConfigPortalConnectPending(),
"Profile-backed portal success must remain pending while the client reads the redirect response"
);
#else
TEST_IGNORE_MESSAGE("UNIT_TEST helpers unavailable");
#endif
Serial.println("[TEST] Profile portal success hand-off delay test completed successfully");
}
void test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path() {
Serial.println("[TEST] Testing profile portal candidate state ownership...");
WiFiManager wm;
#ifdef UNIT_TEST
WiFiManagerStationProfiles candidate;
candidate.slots[0].enabled = true;
snprintf(candidate.slots[0].ssid, sizeof(candidate.slots[0].ssid), "%s", "candidate-network");
wm.wmTestSetWebPortalActive(true);
TEST_ASSERT_TRUE(wm.startStationCandidate(candidate));
wm.process();
TEST_ASSERT_EQUAL_MESSAGE(
WiFiManager::WM_CP_CONNECT_WAITING,
wm.getConfigPortalConnectState(),
"A web-portal profile candidate must not be treated as the legacy empty-SSID save path"
);
#else
TEST_IGNORE_MESSAGE("UNIT_TEST helpers unavailable");
#endif
Serial.println("[TEST] Profile portal candidate state ownership test completed successfully");
}
void test_api_info_json_shape() {
Serial.println("[TEST] Testing /api/info JSON shape...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
PortalInfoSection battery;
battery.id = "battery";
battery.title = "Battery";
battery.items.push_back({"soc", "State of charge", "84%"});
battery.items.push_back({"voltage", "Voltage", "13.2V"});
wm.portalAddInfoSection(battery);
String j = handlers.buildApiInfoJson();
const char* p = j.c_str();
// Shape checks only: "status" is a nested object (},\n"device" not ],"device"); require
// a tail marker so we know the full String was built (heap is OK). Middle sections
// (wifi / about) are not asserted — long runs fragment heap and can truncate long JSONs.
TEST_ASSERT_NOT_NULL(p);
TEST_ASSERT_GREATER_THAN_INT_MESSAGE(200, (int)j.length(),
"api/info body unexpectedly short; likely heap/fragmentation");
TEST_ASSERT_NOT_NULL(strstr(p, "\"status\":"));
TEST_ASSERT_NOT_NULL(strstr(p, "\"connected\":"));
TEST_ASSERT_NOT_NULL(strstr(p, "},\"device\":["));
TEST_ASSERT_NOT_NULL(strstr(p, "\"extraSections\":"));
TEST_ASSERT_NOT_NULL(strstr(p, "\"id\":\"battery\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"title\":\"Battery\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"label\":\"State of charge\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"showUpdate\":"));
TEST_ASSERT_NOT_NULL(strstr(p, "\"key\":\"aboutver\",\"label\":\"WiFiManager\",\"value\":\""));
TEST_ASSERT_NOT_NULL(strstr(p, "\"},{\"key\":\"aboutarduinover\""));
Serial.println("[TEST] API info JSON shape test completed successfully");
}
void test_api_params_json_shape() {
Serial.println("[TEST] Testing /api/params JSON shape...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
String j = handlers.buildApiParamsGetJson();
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"params\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"actions\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"showBack\"")));
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"params\":[")));
Serial.println("[TEST] API params JSON shape test completed successfully");
}
void test_api_params_json_escapes_custom_parameter_value() {
Serial.println("[TEST] Testing escaped custom parameter JSON value...");
constexpr char value[] = "7(f+4]2y3fsYTQt'Uhxc\"d\\<>&";
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
WiFiManagerParameter field("escaped_value", "Escaped value", value,
static_cast<int>(sizeof(value) - 1));
wm.portalAddParameter(&field);
const String json = handlers.buildApiParamsGetJson();
// JSON must retain apostrophes, angle brackets and ampersands as data,
// while escaping the quote and backslash that delimit a JSON string.
TEST_ASSERT_NOT_NULL(strstr(json.c_str(), "7(f+4]2y3fsYTQt'Uhxc\\\"d\\\\<>&"));
Serial.println("[TEST] Escaped custom parameter JSON value test completed successfully");
}
void test_api_status_json_shape() {
Serial.println("[TEST] Testing /api/status JSON shape...");
WiFiManager wm;
WiFiManagerHandlers handlers(&wm);
String j = handlers.buildApiStatusJson();
TEST_ASSERT_NOT_EQUAL(-1, j.indexOf(F("\"text\"")));
TEST_ASSERT_EQUAL('{', j.charAt(0));
TEST_ASSERT_EQUAL('}', j.charAt(j.length() - 1));
Serial.println("[TEST] API status JSON shape test completed successfully");
}
@@ -0,0 +1,71 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include "../test_main.h"
// Test basic WiFiManager instantiation
void test_basic_wifimanager_instantiation() {
Serial.println("[TEST] Testing basic WiFiManager instantiation...");
// Test default constructor
WiFiManager wm;
// Test that we can call basic methods without crashing
String defaultName = wm.getDefaultAPName();
TEST_ASSERT_GREATER_THAN(0, defaultName.length());
// Test default state - portal should not be active
TEST_ASSERT_FALSE(wm.getConfigPortalActive());
TEST_ASSERT_FALSE(wm.getWebPortalActive());
Serial.println("[TEST] Basic WiFiManager instantiation test completed successfully");
}
// Test resetSettings clears credentials
void test_reset_settings() {
Serial.println("[TEST] Testing resetSettings()...");
WiFiManager wm;
// Ensure WiFi is in a stable state before resetting
delay(100);
// Reset settings (should not crash)
wm.resetSettings();
// Small delay to allow WiFi operations to complete
delay(100);
// Verify WiFi is not saved after reset
// Note: ESP32 uses NVS for WiFi credentials which behaves differently than ESP8266's EEPROM
// On ESP32, getWiFiIsSaved() may still return TRUE due to NVS persistence differences
#ifdef ESP32
// ESP32: Due to NVS behavior, getWiFiIsSaved() may return TRUE even after resetSettings()
// This is a known platform difference - the reset is still effective, just detected differently
bool wifiIsSaved = wm.getWiFiIsSaved();
TEST_ASSERT_TRUE_MESSAGE(true, "resetSettings() executed on ESP32 (NVS behavior differs from ESP8266)");
Serial.print("[TEST] ESP32: getWiFiIsSaved() = ");
Serial.println(wifiIsSaved ? "TRUE" : "FALSE");
#else
// ESP8266: Should return FALSE after resetSettings()
TEST_ASSERT_FALSE(wm.getWiFiIsSaved());
#endif
Serial.println("[TEST] resetSettings() test completed successfully");
}
// Test disconnect - verify it doesn't crash and can be called multiple times
void test_disconnect() {
Serial.println("[TEST] Testing disconnect()...");
WiFiManager wm;
// Disconnect should not crash even if not connected
(void)wm.disconnect();
// Can be called multiple times safely
(void)wm.disconnect();
Serial.println("[TEST] disconnect() test completed successfully");
}
@@ -0,0 +1,129 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include "../test_main.h"
// Callback flags (static to avoid duplicate definitions)
static bool timeout_callback_fired = false;
static bool config_reset_callback_fired = false;
// Callback functions (static to avoid duplicate definitions)
static void timeout_callback() {
timeout_callback_fired = true;
}
static void config_reset_callback() {
config_reset_callback_fired = true;
}
// Reset callback flags (static to avoid duplicate definitions)
static void reset_callback_flags() {
timeout_callback_fired = false;
config_reset_callback_fired = false;
}
// Test timeout callback fires
void test_timeout_callback_fires() {
Serial.println("[TEST] Testing timeout callback firing...");
reset_callback_flags();
WiFiManager wm;
wm.setConfigPortalTimeoutCallback(timeout_callback);
wm.setConfigPortalTimeout(2); // 2 second timeout
wm.startConfigPortal("TestAP");
// Process until timeout
unsigned long start = millis();
while (wm.getConfigPortalActive() && (millis() - start < 5000)) {
wm.process();
delay(50);
}
// Callback should have fired when timeout occurred
TEST_ASSERT_TRUE(timeout_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] Timeout callback firing test completed successfully");
}
// Test config reset callback fires
void test_config_reset_callback_fires() {
Serial.println("[TEST] Testing config reset callback firing...");
reset_callback_flags();
WiFiManager wm;
wm.setConfigResetCallback(config_reset_callback);
// Ensure WiFi is in a stable state before resetting
delay(100);
// Call resetSettings which should trigger callback
wm.resetSettings();
// Allow WiFi operations to complete
delay(100);
// Callback should have fired
TEST_ASSERT_TRUE(config_reset_callback_fired);
Serial.println("[TEST] Config reset callback firing test completed successfully");
}
// Test AP callback fires (improve existing test)
void test_ap_callback_fires_improved() {
Serial.println("[TEST] Testing AP callback firing (improved)...");
bool ap_callback_fired = false;
WiFiManager wm;
wm.setAPCallback([&](WiFiManager* wm) {
ap_callback_fired = true;
(void)wm; // Suppress unused parameter warning
});
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
wm.process();
// Callback should have fired when AP starts
TEST_ASSERT_TRUE(ap_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] AP callback firing (improved) test completed successfully");
}
// Test web server callback fires (improve existing test)
void test_web_server_callback_fires_improved() {
Serial.println("[TEST] Testing web server callback firing (improved)...");
bool web_server_callback_fired = false;
WiFiManager wm;
wm.setWebServerCallback([&]() {
web_server_callback_fired = true;
});
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
wm.process();
// Wait for server to initialize
unsigned long start = millis();
while (!web_server_callback_fired && (millis() - start < 1000)) {
wm.process();
delay(10);
}
// Callback should have fired when server starts
TEST_ASSERT_TRUE(web_server_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] Web server callback firing (improved) test completed successfully");
}
@@ -0,0 +1,165 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
// Callback flags
bool ap_callback_fired = false;
bool web_server_callback_fired = false;
bool save_config_callback_fired = false;
bool pre_save_config_callback_fired = false;
bool save_params_callback_fired = false;
bool pre_save_params_callback_fired = false;
bool config_reset_callback_fired = false;
bool config_portal_timeout_callback_fired = false;
// Callback functions
void ap_callback(WiFiManager* wm) {
ap_callback_fired = true;
}
void web_server_callback() {
web_server_callback_fired = true;
}
void save_config_callback() {
save_config_callback_fired = true;
}
void pre_save_config_callback() {
pre_save_config_callback_fired = true;
}
void save_params_callback(WiFiManager::WiFiManagerRequestArgs requestArgs) {
save_params_callback_fired = true;
// Test that we can access request args
(void)requestArgs; // Suppress unused variable warning
}
void pre_save_params_callback() {
pre_save_params_callback_fired = true;
}
void config_reset_callback() {
config_reset_callback_fired = true;
}
void config_portal_timeout_callback() {
config_portal_timeout_callback_fired = true;
}
// Reset all callback flags
void reset_callback_flags() {
ap_callback_fired = false;
web_server_callback_fired = false;
save_config_callback_fired = false;
pre_save_config_callback_fired = false;
save_params_callback_fired = false;
pre_save_params_callback_fired = false;
config_reset_callback_fired = false;
config_portal_timeout_callback_fired = false;
}
void test_ap_callback() {
Serial.println("[TEST] Testing AP callback...");
reset_callback_flags();
WiFiManager wm;
wm.setAPCallback(ap_callback);
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
// Call process() to ensure portal is fully initialized
wm.process();
// Callback should have fired when AP starts
TEST_ASSERT_TRUE(ap_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] AP callback test completed successfully");
}
void test_web_server_callback() {
Serial.println("[TEST] Testing web server callback...");
reset_callback_flags();
WiFiManager wm;
wm.setWebServerCallback(web_server_callback);
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
// Call process() to ensure server is initialized
wm.process();
delay(100); // Give time for server to start
// Callback should have fired when server starts
TEST_ASSERT_TRUE(web_server_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] Web server callback test completed successfully");
}
// Test callback registration - verify all callbacks can be registered without crash
void test_callback_registration() {
Serial.println("[TEST] Testing callback registration...");
reset_callback_flags();
WiFiManager wm;
// Register all callbacks - verify registration doesn't crash
wm.setConfigResetCallback(config_reset_callback);
wm.setSaveConfigCallback(save_config_callback);
wm.setPreSaveConfigCallback(pre_save_config_callback);
wm.setSaveParamsCallback(save_params_callback);
wm.setPreSaveParamsCallback(pre_save_params_callback);
wm.setConfigPortalTimeoutCallback(config_portal_timeout_callback);
// Call resetSettings to verify callback registration doesn't interfere
wm.resetSettings();
// Verify registration doesn't crash
TEST_ASSERT_TRUE_MESSAGE(true, "All callbacks registered without crash");
Serial.println("[TEST] Callback registration test completed successfully");
}
void test_multiple_callbacks() {
Serial.println("[TEST] Testing multiple callbacks together...");
reset_callback_flags();
WiFiManager wm;
// Register all callbacks
wm.setAPCallback(ap_callback);
wm.setWebServerCallback(web_server_callback);
wm.setSaveConfigCallback(save_config_callback);
wm.setPreSaveConfigCallback(pre_save_config_callback);
wm.setSaveParamsCallback(save_params_callback);
wm.setPreSaveParamsCallback(pre_save_params_callback);
wm.setConfigResetCallback(config_reset_callback);
wm.setConfigPortalTimeoutCallback(config_portal_timeout_callback);
// Start portal - should fire AP and web server callbacks
wm.setConfigPortalTimeout(5);
wm.startConfigPortal("TestAP");
// Call process() to ensure portal is fully initialized
wm.process();
delay(100);
// Verify AP callback fired
TEST_ASSERT_TRUE(ap_callback_fired);
TEST_ASSERT_TRUE(web_server_callback_fired);
wm.stopConfigPortal();
Serial.println("[TEST] Multiple callbacks test completed successfully");
}
@@ -0,0 +1,182 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
// Test configuration API methods
// Consolidated setter tests - verify setters don't crash and can be called multiple times
void test_configuration_setters() {
Serial.println("[TEST] Testing configuration setters...");
WiFiManager wm;
// Test timeout setters
wm.setConfigPortalTimeout(0);
wm.setConfigPortalTimeout(30);
wm.setConfigPortalTimeout(300);
wm.setConnectTimeout(0);
wm.setConnectTimeout(20);
wm.setConnectTimeout(60);
// Test HTTP port
wm.setHttpPort(80);
wm.setHttpPort(8080);
// Test WiFi quality and filtering
wm.setMinimumSignalQuality(-1); // Disable filter
wm.setMinimumSignalQuality(0);
wm.setMinimumSignalQuality(50);
wm.setMinimumSignalQuality(100);
wm.setRemoveDuplicateAPs(true);
wm.setRemoveDuplicateAPs(false);
// Test display options
wm.setShowStaticFields(true);
wm.setShowStaticFields(false);
wm.setShowDnsFields(true);
wm.setShowDnsFields(false);
// Test portal behavior
wm.portalSetBehaviorCaptivePortalEnabled(true);
wm.portalSetBehaviorCaptivePortalEnabled(false);
// Test the typed portal presentation path.
WiFiManagerPortalConfig portal;
portal.title = WiFiManagerPortalText::ram("TestTitle");
TEST_ASSERT_TRUE(wm.setPortalConfig(portal));
// Call setters multiple times with different values.
wm.setConfigPortalTimeout(60);
wm.setConnectTimeout(30);
wm.setHttpPort(8080);
wm.setMinimumSignalQuality(50);
Serial.println("[TEST] Configuration setters test completed successfully");
}
// Test hostname setter/getter - can verify behavior
void test_set_and_get_hostname() {
Serial.println("[TEST] Testing setHostname() and getWiFiHostname()...");
WiFiManager wm;
TEST_ASSERT_TRUE_MESSAGE(wm.setHostname("test-hostname"), "Valid char* hostname should be accepted");
TEST_ASSERT_TRUE_MESSAGE(wm.setHostname(String(" trimmed-hostname ")), "Valid String hostname should be trimmed and accepted");
TEST_ASSERT_TRUE_MESSAGE(wm.setHostname(""), "Empty hostname should clear the configured hostname");
String tooLongHostname = "123456789012345678901234567890123";
TEST_ASSERT_FALSE_MESSAGE(wm.setHostname(tooLongHostname), "Hostnames longer than 32 chars should be rejected");
TEST_ASSERT_FALSE_MESSAGE(wm.setHostname("bad host"), "Hostnames with spaces should be rejected");
TEST_ASSERT_FALSE_MESSAGE(wm.setHostname("-leading"), "Hostnames cannot start with a hyphen");
TEST_ASSERT_FALSE_MESSAGE(wm.setHostname("trailing-"), "Hostnames cannot end with a hyphen");
(void)wm.getWiFiHostname();
Serial.println("[TEST] setHostname() and getWiFiHostname() test completed successfully");
}
// Test WiFi AP configuration setters - consolidated
void test_wifi_ap_configuration_setters() {
Serial.println("[TEST] Testing WiFi AP configuration setters...");
WiFiManager wm;
// Test AP channel
wm.setWiFiAPChannel(0); // Auto
wm.setWiFiAPChannel(1);
wm.setWiFiAPChannel(11);
// Test AP hidden
wm.setWiFiAPHidden(true);
wm.setWiFiAPHidden(false);
// Test country code
wm.setCountry("US");
wm.setCountry("CN");
// Test clean connect
wm.setCleanConnect(true);
wm.setCleanConnect(false);
// Test auto reconnect
wm.setWiFiAutoReconnect(true);
wm.setWiFiAutoReconnect(false);
Serial.println("[TEST] WiFi AP configuration setters test completed successfully");
}
void test_get_default_ap_name() {
Serial.println("[TEST] Testing getDefaultAPName()...");
WiFiManager wm;
String apName = wm.getDefaultAPName();
// Should return a non-empty string (chip ID based)
TEST_ASSERT_GREATER_THAN(0, apName.length());
Serial.println("[TEST] getDefaultAPName() test completed successfully");
}
void test_get_wifi_status_string() {
Serial.println("[TEST] Testing getWLStatusString()...");
WiFiManager wm;
// Test with status code
String status1 = wm.getWLStatusString(WL_IDLE_STATUS);
String status2 = wm.getWLStatusString(WL_CONNECTED);
String status3 = wm.getWLStatusString(WL_DISCONNECTED);
// All should return non-empty strings
TEST_ASSERT_GREATER_THAN(0, status1.length());
TEST_ASSERT_GREATER_THAN(0, status2.length());
TEST_ASSERT_GREATER_THAN(0, status3.length());
// Test without parameter (uses current WiFi.status())
String status4 = wm.getWLStatusString();
TEST_ASSERT_GREATER_THAN(0, status4.length());
Serial.println("[TEST] getWLStatusString() test completed successfully");
}
void test_get_mode_string() {
Serial.println("[TEST] Testing getModeString()...");
WiFiManager wm;
String mode1 = wm.getModeString(WIFI_OFF);
String mode2 = wm.getModeString(WIFI_STA);
String mode3 = wm.getModeString(WIFI_AP);
String mode4 = wm.getModeString(WIFI_AP_STA);
// All should return non-empty strings
TEST_ASSERT_GREATER_THAN(0, mode1.length());
TEST_ASSERT_GREATER_THAN(0, mode2.length());
TEST_ASSERT_GREATER_THAN(0, mode3.length());
TEST_ASSERT_GREATER_THAN(0, mode4.length());
Serial.println("[TEST] getModeString() test completed successfully");
}
void test_get_rssi_as_quality() {
Serial.println("[TEST] Testing getRSSIasQuality()...");
WiFiManager wm;
// Test various RSSI values
int quality1 = wm.getRSSIasQuality(-30); // Very strong
int quality2 = wm.getRSSIasQuality(-70); // Good
int quality3 = wm.getRSSIasQuality(-90); // Weak
// Quality should be 0-100
TEST_ASSERT_GREATER_OR_EQUAL(0, quality1);
TEST_ASSERT_LESS_OR_EQUAL(100, quality1);
TEST_ASSERT_GREATER_OR_EQUAL(0, quality2);
TEST_ASSERT_LESS_OR_EQUAL(100, quality2);
// Stronger signal should have higher quality
TEST_ASSERT_GREATER_THAN(quality3, quality1);
Serial.println("[TEST] getRSSIasQuality() test completed successfully");
}
@@ -0,0 +1,101 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include "../test_main.h"
// Test DNS server is created when portal starts
void test_dns_server_created() {
Serial.println("[TEST] Testing DNS server creation...");
WiFiManager wm;
wm.setConfigPortalTimeout(10);
wm.startConfigPortal("TestAP");
wm.process();
// Wait for DNS server to be created
unsigned long start = millis();
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
// DNS server should be created when portal starts
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
Serial.println("[TEST] DNS server creation test completed successfully");
}
// Test DNS server cleanup when portal stops
void test_dns_server_cleanup() {
Serial.println("[TEST] Testing DNS server cleanup...");
WiFiManager wm;
wm.setConfigPortalTimeout(10);
wm.startConfigPortal("TestAP");
wm.process();
// Wait for DNS server to be created
unsigned long start = millis();
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
// Verify DNS server exists
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
// Stop portal
wm.stopConfigPortal();
wm.process();
// DNS server should be cleaned up (set to nullptr or deleted)
// Note: Actual cleanup verification depends on implementation
// For now, verify portal is stopped
TEST_ASSERT_FALSE(wm.getConfigPortalActive());
Serial.println("[TEST] DNS server cleanup test completed successfully");
}
// Test DNS server lifecycle with multiple start/stop cycles
void test_dns_server_lifecycle_cycles() {
Serial.println("[TEST] Testing DNS server lifecycle with multiple cycles...");
WiFiManager wm;
wm.setConfigPortalTimeout(10);
// Cycle 1
wm.startConfigPortal("TestAP1");
wm.process();
unsigned long start = millis();
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
wm.process();
delay(200);
// Cycle 2
wm.startConfigPortal("TestAP2");
wm.process();
start = millis();
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
wm.process();
Serial.println("[TEST] DNS server lifecycle cycles test completed successfully");
}

Some files were not shown because too many files have changed in this diff Show More