mirror of
https://github.com/alexhopeoconnor/WiFiManager.git
synced 2026-10-04 02:48:13 +10:00
docs: improve portal guidance and examples
This commit is contained in:
+17
-6
@@ -7,12 +7,21 @@ lib_deps =
|
||||
WiFiManager=symlink:///path/to/WiFiManager
|
||||
```
|
||||
|
||||
The ESP32 environments pin the PlatformIO-compatible pioarduino 51.03.05
|
||||
platform package, which packages official Arduino-ESP32 3.0.5. This avoids the
|
||||
known six-second asynchronous scan failure in the older 2.0.17 framework. Core
|
||||
3 also requires the `SOC_WIFI_SUPPORTED`, `Network/src`, and ESP8266-transport
|
||||
ignore settings shown in this repository `platformio.ini`; keep those settings
|
||||
when adding an ESP32 environment.
|
||||
## Target pins
|
||||
|
||||
The ESP32 test environments pin the pioarduino `51.03.05` platform package,
|
||||
which selects Arduino-ESP32 3.0.5 / ESP-IDF 5.1.4+. This is a test-target
|
||||
contract, not a library-manifest dependency: a consuming application chooses
|
||||
its own `platform` and must validate the complete framework/toolchain stack.
|
||||
Core 3 Wi-Fi builds need the C++14, `SOC_WIFI_SUPPORTED`, `Network/src`, and
|
||||
ESP8266-transport ignore settings in this repository's `platformio.ini`; keep
|
||||
those settings together when adding an ESP32 environment.
|
||||
|
||||
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 the scoped repair for a stale
|
||||
global PlatformIO tool package, see [DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md).
|
||||
|
||||
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:
|
||||
|
||||
@@ -22,6 +31,8 @@ Start a release with `bump-version.sh`. It updates package metadata and canonica
|
||||
./scripts/check-docs.sh
|
||||
./scripts/test.sh compile --platform esp8266
|
||||
./scripts/test.sh compile --platform esp32
|
||||
./scripts/test.sh examples --platform esp8266
|
||||
./scripts/test.sh examples --platform esp32
|
||||
./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag
|
||||
```
|
||||
|
||||
|
||||
+6
-2
@@ -65,7 +65,7 @@ A normal accepted save returns 202 and directs the portal to poll /api/wifi/conn
|
||||
|
||||
~~~json
|
||||
{
|
||||
"state": "idle | waiting | success | failed",
|
||||
"state": "success",
|
||||
"message": "human readable status",
|
||||
"wifiStatus": "WL_CONNECTED",
|
||||
"stationIp": "192.168.1.42",
|
||||
@@ -73,7 +73,11 @@ A normal accepted save returns 202 and directs the portal to poll /api/wifi/conn
|
||||
}
|
||||
~~~
|
||||
|
||||
stationIp and redirectUrl are present only after success. If WiFiManager uses a non-default HTTP port, redirectUrl includes it.
|
||||
`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.
|
||||
|
||||
|
||||
+28
-10
@@ -18,18 +18,36 @@ A candidate submitted by the portal or another application subsystem is only com
|
||||
|
||||
## Direct WiFiManager use
|
||||
|
||||
Implement a small store appropriate to the application. WiFiManager neither allocates nor owns it:
|
||||
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 MyProfileStore final : public WiFiManagerStationProfileStore {
|
||||
```cpp
|
||||
class MemoryProfileStore final : public WiFiManagerStationProfileStore {
|
||||
public:
|
||||
bool load(WiFiManagerStationProfiles& profiles) override;
|
||||
bool save(const WiFiManagerStationProfiles& profiles) override;
|
||||
bool clear() override;
|
||||
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;
|
||||
MyProfileStore profiles;
|
||||
MemoryProfileStore profiles; // Must outlive WiFiManager's asynchronous connection work.
|
||||
|
||||
void setup() {
|
||||
wifi.setStationProfileStore(&profiles);
|
||||
@@ -38,11 +56,11 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
wifi.process();
|
||||
wifi.process(); // Advances profile retries and serves the fallback portal.
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
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 to false for an open network.
|
||||
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.
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ WiFiManager portal;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
portal.setConfigPortalTimeout(180);
|
||||
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 {
|
||||
@@ -14,4 +15,6 @@ void setup() {
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { portal.process(); }
|
||||
void loop() {
|
||||
portal.process(); // Keeps DNS, HTTP, and station-recovery work responsive.
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
#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);
|
||||
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;
|
||||
@@ -28,7 +29,7 @@ void setup() {
|
||||
portal.portalAddHomeCard(hint);
|
||||
|
||||
portal.setSaveParamsCallback([](WiFiManager::WiFiManagerRequestArgs) {
|
||||
// A product validates and persists this value here; this demo only prints it.
|
||||
// Validate and persist a copy in the application; this example only reports it.
|
||||
Serial.print("MQTT broker selected: ");
|
||||
Serial.println(brokerHost.getValue());
|
||||
});
|
||||
@@ -37,4 +38,6 @@ void setup() {
|
||||
portal.autoConnect("WiFiManager Content", "example-pass");
|
||||
}
|
||||
|
||||
void loop() { portal.process(); }
|
||||
void loop() {
|
||||
portal.process(); // Serves portal requests until provisioning completes or times out.
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@ struct StoredProfiles {
|
||||
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));
|
||||
@@ -25,6 +27,7 @@ public:
|
||||
StoredProfiles stored{};
|
||||
EEPROM.get(0, stored);
|
||||
if (stored.magic != kStoreMagic) {
|
||||
// Treat erased or unrelated EEPROM as having no profiles.
|
||||
return false;
|
||||
}
|
||||
profiles = stored.profiles;
|
||||
@@ -32,6 +35,7 @@ public:
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -53,11 +57,12 @@ void setup() {
|
||||
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();
|
||||
portal.process(); // Advances connection attempts and serves provisioning when needed.
|
||||
}
|
||||
|
||||
@@ -4,6 +4,32 @@ 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
|
||||
@@ -33,6 +59,7 @@ while IFS= read -r file; do
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user