AutoNetwork manages WiFi lifecycle for ESP32 applications:
- Automatic connection to saved networks
- Captive portal for credential configuration
- Visual LED feedback via ticker patterns
- Persistent credential storage in NVS
- AsyncWebServer integration
- Connection monitoring and callbacks
- Automatic root page management with error handling
Minimal working example:
#include <AutoNetwork.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);
AutoNetwork autonetwork(&server);
String rootPage() {
return R"(
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
{{AUTONETWORK_MENU}}
<h1>Hello from ESP32</h1>
</body>
</html>
)";
}
void setup() {
Serial.begin(115200);
autonetwork.setRootContent(rootPage);
autonetwork.begin();
}
void loop() {
autonetwork.loop();
}The {{AUTONETWORK_MENU}} placeholder is replaced with a hamburger menu icon linking to /_an. This relative link works regardless of the device's IP address, which changes depending on whether the ESP32 is in AP mode (192.168.4.1) or connected to a network (router-assigned IP).
- First boot (no saved credentials): ESP32 creates AP named "AutoNetwork"
- Connect to AP: Join the WiFi network from your phone/laptop
- Captive portal opens: Configure your WiFi credentials
- Device connects: ESP32 connects to your network and serves your webpage
- Access settings: Click the menu icon to return to WiFi settings
- Web Interface - Portal documentation
AutoNetworkConfig config;
// Device identification
config.apSSID = "MyDevice";
config.apPassword = "";
config.staHostName = "mydevice";
// Ticker LED
config.tickerEnable = true;
config.tickerPin = LED_BUILTIN;
config.tickerActiveLevel = LOW; // ESP32 DevKit active-LOW
// Timeouts
config.portalTimeout = 300; // 5 minutes, 0=never
// Credential saving
config.credentialSaveMode = AutoNetworkCredentialSaveMode::AUTO;
// Logging
config.logLevel = AN_LOG_WARN;
autonetwork.config(config);| Parameter | Type | Description | Default |
|---|---|---|---|
apSSID |
String | AP mode SSID | "AutoNetwork" |
apPassword |
String | AP password (min 8 chars or empty) | "" |
staHostName |
String | Station mode hostname | "autonetwork" |
tickerEnable |
bool | Enable LED ticker | false |
tickerPin |
uint8_t | Ticker GPIO pin | LED_BUILTIN |
tickerActiveLevel |
uint8_t | LED active level (HIGH/LOW) | LOW |
portalTimeout |
uint32_t | Portal timeout ms (0=never) | 300000 |
credentialSaveMode |
enum | ALWAYS, AUTO, NEVER | AUTO |
logLevel |
enum | AN_LOG_NONE to AN_LOG_VERBOSE | AN_LOG_WARN |
AutoNetwork(AsyncWebServer* server);Create AutoNetwork instance with server pointer.
AsyncWebServer server(80);
AutoNetwork autonetwork(&server);Apply configuration settings.
AutoNetworkConfig config;
config.apSSID = "Device";
config.tickerEnable = true;
autonetwork.config(config);Set mDNS hostname.
autonetwork.setHostname("mydevice");Set WiFi connection timeout.
autonetwork.setConnectTimeout(30000); // 30 secondsSet captive portal timeout (0 = infinite).
autonetwork.setPortalTimeout(300000); // 5 minutesSet root page content from LittleFS file.
autonetwork.setRootContent("/index.html");Set root page content from callback (dynamic).
autonetwork.setRootContent([]() {
return "<html><body>Time: " + String(millis()) + "</body></html>";
});Set root page content from embedded string.
autonetwork.setRootContentHTML(R"rawliteral(
<!DOCTYPE html>
<html><body><h1>My App</h1></body></html>
)rawliteral");Use the {{AUTONETWORK_MENU}} placeholder in your HTML to include a hamburger menu icon linking to /_an. This relative link works regardless of the device's IP address, which changes depending on whether the ESP32 is in AP mode (192.168.4.1) or connected to a network (router-assigned IP):
autonetwork.setRootContentHTML(R"rawliteral(
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
{{AUTONETWORK_MENU}}
<h1>My Application</h1>
<p>Content here...</p>
</body>
</html>
)rawliteral");The placeholder is automatically replaced with a styled hamburger menu button. You can also customize the menu link:
autonetwork.setRootMenuReplacement("<a href='/_an'>Settings</a>");Initialize WiFi and start connection process. Returns true if connected immediately.
if (autonetwork.begin()) {
Serial.println("Connected!");
} else {
Serial.println("Portal started");
}Process WiFi state machine. Call first in main loop.
Note: loop() is the only method for processing AutoNetwork tasks. Previous alias methods (handleClient(), handleRequest()) have been removed for clarity.
void loop() {
autonetwork.loop();
}Check if WiFi is connected.
if (autonetwork.isConnected()) {
sendData();
}Get connected or configured SSID.
String ssid = autonetwork.getSSID();Get local IP address.
IPAddress ip = autonetwork.getIP();Get current connection status.
auto status = autonetwork.getConnectionStatus();Set library logging verbosity.
autonetwork.setLogLevel(AN_LOG_DEBUG);Log levels:
AN_LOG_NONE- SilentAN_LOG_ERROR- Critical errors onlyAN_LOG_WARN- Warnings and errors (default)AN_LOG_INFO- Informational messagesAN_LOG_DEBUG- Debug detailsAN_LOG_VERBOSE- Everything
Visual feedback for WiFi status:
| Pattern | Timing | Meaning | When Used |
|---|---|---|---|
| SLOW_BLINK | 500ms on / 500ms off | Portal active | No saved networks |
| SOLID_ON | Continuously on | Connected | WiFi connected |
| FAST_BLINK | 150ms on / 150ms off | Reconnecting | Lost connection |
| OFF | LED off | Uninitialized | Before begin() |
AutoNetwork portal; // ERROR: No default constructorFix:
AsyncWebServer server(80);
AutoNetwork autonetwork(&server);autonetwork.config(config);
WiFi.mode(WIFI_STA); // Breaks library
autonetwork.begin();Fix:
autonetwork.config(config);
autonetwork.begin(); // Library controls modevoid loop() {
doStuff(); // Missing autonetwork.loop()
}Fix:
void loop() {
autonetwork.loop(); // Required first
doStuff();
}void setup() {
autonetwork.begin();
webSocket.begin(); // WiFi may not be ready
}Fix:
autonetwork.onConnectionStatus([](AutoNetworkConnectionStatus status) {
if (status == AutoNetworkConnectionStatus::CONNECTED) {
webSocket.begin(); // Start when ready
}
});#include <Arduino.h>
#include <LittleFS.h>
#include <AutoNetwork.h>
#include <ESPAsyncWebServer.h>
// Global objects
AsyncWebServer server(80);
AutoNetwork autonetwork(&server);
void setup() {
Serial.begin(115200);
LittleFS.begin(true);
// Get MAC for unique AP name
WiFi.mode(WIFI_STA);
String mac = WiFi.macAddress();
mac.replace(":", "");
// Configure
AutoNetworkConfig config;
config.apSSID = "ESP32_" + mac;
config.staHostName = config.apSSID;
config.tickerEnable = true;
config.tickerPin = LED_BUILTIN;
config.tickerActiveLevel = LOW;
config.credentialSaveMode = AutoNetworkCredentialSaveMode::AUTO;
config.logLevel = AN_LOG_WARN;
autonetwork.config(config);
autonetwork.setRootContent("/index.html");
// Register callbacks
autonetwork.onConnectionStatus([](AutoNetworkConnectionStatus status) {
if (status == AutoNetworkConnectionStatus::CONNECTED) {
Serial.printf("Connected: %s\n", WiFi.SSID().c_str());
Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
} else if (status == AutoNetworkConnectionStatus::DISCONNECTED) {
Serial.println("Disconnected");
}
});
autonetwork.onPortalState([](AutoNetworkPortalState state) {
if (state == AutoNetworkPortalState::WAITING_FOR_CONNECTION) {
Serial.printf("Portal at: http://%s\n",
WiFi.softAPIP().toString().c_str());
}
});
// Start
if (autonetwork.begin()) {
Serial.println("WiFi connected!");
} else {
Serial.printf("Connect to %s for setup\n", config.apSSID.c_str());
}
}
void loop() {
autonetwork.loop();
}config.logLevel = AN_LOG_DEBUG;
autonetwork.config(config);Or after config:
autonetwork.setLogLevel(AN_LOG_DEBUG);Constructor Pattern:
AsyncWebServer server(80);
AutoNetwork autonetwork(&server);Setup Pattern:
autonetwork.config(config);
autonetwork.setRootContent("/index.html");
autonetwork.onConnectionStatus(callback);
autonetwork.begin();Loop Pattern:
void loop() {
autonetwork.loop(); // Required first
}MIT License