feat: prepare WiFiManager 3.1.0

This commit is contained in:
2026-08-27 14:25:38 +10:00
parent c10f1a3e92
commit 25977a7320
21 changed files with 1214 additions and 321 deletions
+21
View File
@@ -0,0 +1,21 @@
# 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
```
Before a release, update `library.json`, `CHANGELOG.md`, and the relevant public documentation, then run:
```bash
./scripts/check-docs.sh
./scripts/test.sh compile --platform esp8266
./scripts/test.sh compile --platform esp32
./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag
```
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).
+41
View File
@@ -0,0 +1,41 @@
# 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);
if (!wifi.autoConnect("Example Setup", "change-me")) {
ESP.restart();
}
}
void loop() {
// 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. Use a Wi-Fi-valid AP password.
## PlatformIO dependency
```ini
lib_deps =
WiFiManager=https://github.com/alexhopeoconnor/WiFiManager.git#v3.1.0
```
The package manifest resolves DFTE, ESPAsyncWebServer, and the correct TCP transport for ESP8266 or ESP32. A consuming project should not duplicate those dependencies unless it is deliberately testing an unreleased stack change.
## DeviceFramework applications
DeviceFramework creates and configures WiFiManager for its normal lifecycle. Use DeviceFramework’s persistent shared device-password API instead of separately configuring an AP, OTA, HTTP, and WebSerial password.
Next: [portal customisation](PORTAL_CUSTOMIZATION.md) or [portal API](PORTAL_API.md).
Back to [documentation](README.md) · [project overview](../README.md).
+34
View File
@@ -0,0 +1,34 @@
# Portal API
The portal uses JSON endpoints under `/api/...` for WiFi scans and saves, parameters, information, status, restart/erase/exit actions, captive-portal closure, and station-connect status. Consumers should treat the documented response shapes as the contract; portal HTML is not an API.
## Profile-mode WiFi metadata
When an application supplies a `WiFiManagerStationProfileStore`, `GET /api/wifi/meta` reports a primary profile and optional fallback without returning passwords. `POST /api/wifi/save` verifies a submitted candidate before committing it; see [station profiles](STATION_PROFILES.md) for fields and lifecycle.
## WiFi connect status
When `portalSetBehaviorConnectOnSave(true)` is enabled, saving credentials queues a station join. The SPA polls `GET /api/wifi/connect-status`:
```json
{
"state": "waiting | success | failed",
"message": "human readable status",
"wifiStatus": "WL_CONNECTED",
"stationIp": "192.168.1.42",
"redirectUrl": "http://192.168.1.42/"
}
```
`stationIp` and `redirectUrl` are present only after a successful join. If the portal server is not on port 80, `redirectUrl` includes that port.
On success, WiFiManager keeps the portal alive briefly so the client can read the final status and navigate before the AP is shut down. Captive-portal helpers, DHCP timing, browser behaviour, and network isolation can still prevent an automatic redirect, so clients must handle a visible address as well.
## API design rules
- Use JSON endpoint results for state and actions.
- Keep UI-visible capabilities in the portal bootstrap/API payloads.
- Add a documented endpoint contract before adding a new portal workflow.
- Do not derive state by parsing the rendered shell.
Back to [documentation](README.md) · [project overview](../README.md).
+65
View File
@@ -0,0 +1,65 @@
# Portal customisation
The stable extension surface is the `portal*` API and JSON API contract. Templates, undocumented DOM IDs, and SPA routing internals are not consumer extension points.
## Supported changes
- `portalSetBrand*` and `portalSetContextIdentityText()` for the visible identity.
- `portalSetPage*`, `portalSetAction*`, `portalSetLayout*`, and `portalSetBehavior*` for built-in capability and layout choices.
- `portalAddParameter()`, including raw HTML blocks inside parameter-rendering surfaces.
- `portalAddInfoSection()` and `portalAddHomeCard()` for structured content.
- `portalAppendCss()`, `portalOverrideCss()`, and `portalAppendJs()` for small presentation enhancements.
```cpp
WiFiManager wm;
wm.portalSetBrandTitle("Solar Battery Monitor Setup");
wm.portalSetContextIdentityText("Solar Battery Monitor");
wm.portalSetBrandHomeIntro(
"Connect the monitor to WiFi, then review its battery settings."
);
wm.portalSetPageUpdateVisible(false);
wm.portalSetActionEraseVisible(false);
wm.portalSetLayoutParamsLocation(PortalParamsLocation::SetupPage);
WiFiManagerParameter mqttHost(
"mqtt_host", "MQTT host", "broker.local", 64,
"placeholder='broker.local'"
);
wm.portalAddParameter(&mqttHost);
PortalHomeCard summary;
summary.id = "battery";
summary.title = "Battery";
summary.kind = PortalHomeCardKind::KeyValue;
summary.items.push_back({"voltage", "Voltage", "13.2V"});
wm.portalAddHomeCard(summary);
wm.portalAppendJs(
"document.addEventListener('wm:ready', function(event) {"
" console.log('Portal ready', event.detail.boot);"
"});"
);
```
## Enhancement events
Appended JavaScript may enhance the existing SPA through:
- `wm:ready`, with `event.detail.boot`;
- `wm:view-changed`, with `event.detail.route`.
It should not replace routing or built-in action flow.
## Intentional boundary
The following are fork-level changes, not supported consumer customisation:
- arbitrary home, information, navigation, or shell HTML injection;
- replacing built-in SPA routes or action flows;
- depending on undocumented DOM IDs or private templates;
- adding a new backend-to-frontend workflow without an API contract.
For data and endpoint behaviour, see [Portal API](PORTAL_API.md).
Back to [documentation](README.md) · [project overview](../README.md).
+20
View File
@@ -0,0 +1,20 @@
# WiFiManager documentation
This maintained fork intentionally has a narrower, explicit customisation boundary than upstream WiFiManager.
| I want to… | Read |
| --- | --- |
| Start a basic portal or install a released dependency | [Getting started](GETTING_STARTED.md) |
| Brand the SPA, add parameters/cards, or use the supported hooks | [Portal customisation](PORTAL_CUSTOMIZATION.md) |
| Configure primary/fallback station profiles or their portal workflow | [Station profiles](STATION_PROFILES.md) |
| Consume JSON endpoints or station-connect status | [Portal API](PORTAL_API.md) |
| Build a clean consumer | [Testing](TESTING.md) |
| Work on this fork or make a release | [Development and releases](DEVELOPMENT.md) |
## Documentation rules
- Portal customisation owns the supported `portal*` surface.
- Portal API owns HTTP response contracts.
- The root README is a short onboarding page, not an API reference.
Back to the [project overview](../README.md).
+62
View File
@@ -0,0 +1,62 @@
# Station profiles
WiFiManager 3.1.0 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.
DeviceFramework enables this controller and supplies its CRC-protected storage. A direct WiFiManager consumer supplies its own durable store, or can use the controller only for the current process.
## 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 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:
```cpp
class MyProfileStore final : public WiFiManagerStationProfileStore {
public:
bool load(WiFiManagerStationProfiles& profiles) override;
bool save(const WiFiManagerStationProfiles& profiles) override;
bool clear() override;
};
WiFiManager wifi;
MyProfileStore profiles;
void setup() {
wifi.setStationProfileStore(&profiles);
wifi.setStationRecoveryInterval(30000);
wifi.startStationConnection("Example Setup", "setup-password");
}
void loop() {
wifi.process();
}
```
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.
To stage profiles supplied by another subsystem, use `startStationCandidate(candidate)`. It connects the primary/fallback set first and calls the store only after success. Use `saveStationProfiles(profiles)` only when deliberately saving without a connection check. `clearStationProfiles()` clears the supplied store and disconnects the station.
## Portal contract
In profile mode, the existing Wi-Fi page becomes a two-profile form. It remains driven by the same JSON endpoints:
- `GET /api/wifi/meta` returns `profiles`, `activeSlot`, and controller `state`.
- `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. Poll `GET /api/wifi/connect-status` for its result.
- Set `stationAction=save` only to store the submitted profiles for a later connection attempt.
The portal requires a non-empty primary SSID. Its API never returns a password; it only reports whether one is set.
See [Portal API](PORTAL_API.md) for the shared connection-status response and [DeviceFramework configuration](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/CONFIGURATION.md) for the local-profile JSON that supplies these slots.
Back to [documentation](README.md) · [project overview](../README.md).
+12
View File
@@ -0,0 +1,12 @@
# Testing
The clean-consumer check builds a project that declares only WiFiManager. It proves the package manifest resolves DFTE, ESPAsyncWebServer, and the correct ESP8266 or ESP32 TCP dependency without a sibling checkout or attached board.
```bash
./scripts/test.sh compile --platform esp8266
./scripts/test.sh compile --platform esp32
```
CI runs both checks for pushes to the maintained branch and pull requests. They compile only; hardware portals remain a local integration concern for an application or DeviceFramework’s connected-device suite.
Back to [documentation](README.md) · [project overview](../README.md).