Add priority WiFi failover

This commit is contained in:
2026-06-04 13:43:52 -06:00
parent 31ba93c68b
commit 69c745e883
2 changed files with 108 additions and 7 deletions
+15
View File
@@ -190,3 +190,18 @@ Pico sends:
{"type":"wifi_clear"}
AP mode remains enabled as the recovery path.
## WiFi Priority
WiFi configuration supports multiple saved networks.
Lower priority numbers are tried first.
Example:
{"type":"config_wifi","networks":[{"ssid":"Starlink","password":"password","priority":1},{"ssid":"Home WiFi","password":"password","priority":2}]}
Runtime behavior:
If STA disconnects, the ESP32 retries saved networks by priority every 30 seconds.
AP mode remains available as a recovery path.
@@ -83,10 +83,13 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral(
<div class="tempList" style="margin-top:12px">
<input id="w1s" placeholder="Network 1 SSID">
<input id="w1p" placeholder="Network 1 password" type="password">
<input id="w1r" placeholder="Network 1 priority, lower = first" inputmode="numeric">
<input id="w2s" placeholder="Network 2 SSID">
<input id="w2p" placeholder="Network 2 password" type="password">
<input id="w2r" placeholder="Network 2 priority, lower = first" inputmode="numeric">
<input id="w3s" placeholder="Network 3 SSID">
<input id="w3p" placeholder="Network 3 password" type="password">
<input id="w3r" placeholder="Network 3 priority, lower = first" inputmode="numeric">
<button onclick="saveWifi()">Save WiFi</button>
<button onclick="connectWifi()">Connect Now</button>
</div>
@@ -169,6 +172,8 @@ async function loadWifiConfig(){
const n=nets[i]||{};
const s=$("w"+(i+1)+"s");
if(s) s.value=n.ssid||"";
const pr=$("w"+(i+1)+"r");
if(pr) pr.value=n.priority||i+1;
}
}catch(e){}
}
@@ -177,7 +182,8 @@ async function saveWifi(){
for(let i=1;i<=3;i++){
const ssid=$("w"+i+"s").value.trim();
const password=$("w"+i+"p").value;
if(ssid) networks.push({ssid,password});
const priority=parseInt($("w"+i+"r").value||i,10);
if(ssid) networks.push({ssid,password,priority});
}
await fetch("/config/wifi",{
method:"POST",
@@ -218,8 +224,11 @@ Preferences wifiPrefs;
const int MAX_WIFI_NETWORKS = 3;
String staSsids[MAX_WIFI_NETWORKS];
String staPasswords[MAX_WIFI_NETWORKS];
int staPriorities[MAX_WIFI_NETWORKS];
int wifiNetworkCount = 0;
String activeStaSsid = "";
unsigned long lastStaReconnectAttempt = 0;
const unsigned long STA_RECONNECT_INTERVAL_MS = 30000;
void loadWifiConfig() {
wifiPrefs.begin("wifi", true);
@@ -232,6 +241,7 @@ void loadWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = wifiPrefs.getString(("ssid" + String(i)).c_str(), "");
staPasswords[i] = wifiPrefs.getString(("pass" + String(i)).c_str(), "");
staPriorities[i] = wifiPrefs.getInt(("priority" + String(i)).c_str(), i + 1);
}
// Migration path from old single-network config
@@ -242,6 +252,7 @@ void loadWifiConfig() {
if (oldSsid.length() > 0) {
staSsids[0] = oldSsid;
staPasswords[0] = oldPassword;
staPriorities[0] = 1;
wifiNetworkCount = 1;
}
}
@@ -257,6 +268,7 @@ void saveWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
wifiPrefs.putString(("ssid" + String(i)).c_str(), staSsids[i]);
wifiPrefs.putString(("pass" + String(i)).c_str(), staPasswords[i]);
wifiPrefs.putInt(("priority" + String(i)).c_str(), staPriorities[i]);
}
// Keep legacy keys updated for easier debugging
@@ -277,9 +289,30 @@ void clearWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = "";
staPasswords[i] = "";
staPriorities[i] = i + 1;
}
}
int findNextWifiIndexByPriority(bool tried[]) {
int bestIndex = -1;
int bestPriority = 1000000;
for (int i = 0; i < wifiNetworkCount; i++) {
if (tried[i]) continue;
if (staSsids[i].length() == 0) continue;
int priority = staPriorities[i];
if (priority <= 0) priority = i + 1;
if (priority < bestPriority) {
bestPriority = priority;
bestIndex = i;
}
}
return bestIndex;
}
void connectStaWifi() {
if (wifiNetworkCount <= 0) {
Serial.println("STA WiFi not configured.");
@@ -289,12 +322,20 @@ void connectStaWifi() {
WiFi.disconnect(false);
activeStaSsid = "";
for (int i = 0; i < wifiNetworkCount; i++) {
if (staSsids[i].length() == 0) {
continue;
bool tried[MAX_WIFI_NETWORKS] = {false, false, false};
for (int attempt = 0; attempt < wifiNetworkCount; attempt++) {
int i = findNextWifiIndexByPriority(tried);
if (i < 0) {
break;
}
Serial.print("Connecting STA WiFi to: ");
tried[i] = true;
Serial.print("Connecting STA WiFi priority ");
Serial.print(staPriorities[i]);
Serial.print(" to: ");
Serial.println(staSsids[i]);
WiFi.begin(staSsids[i].c_str(), staPasswords[i].c_str());
@@ -323,6 +364,19 @@ void connectStaWifi() {
Serial.println("All STA WiFi attempts failed. AP remains available.");
}
void maintainStaWifi() {
if (wifiNetworkCount <= 0) return;
if (WiFi.status() == WL_CONNECTED) return;
if (millis() - lastStaReconnectAttempt < STA_RECONNECT_INTERVAL_MS) return;
lastStaReconnectAttempt = millis();
Serial.println("STA WiFi disconnected. Trying saved networks by priority...");
connectStaWifi();
}
void printNetworkStatus() {
Serial.println("Network:");
Serial.print(" AP IP: ");
@@ -441,6 +495,14 @@ void buildStatusDocument(JsonDocument& doc) {
network["sta_ssid"] = activeStaSsid;
network["sta_ip"] = WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : "";
network["saved_network_count"] = wifiNetworkCount;
JsonArray savedNetworks = network.createNestedArray("saved_networks");
for (int i = 0; i < wifiNetworkCount; i++) {
JsonObject saved = savedNetworks.createNestedObject();
saved["index"] = i + 1;
saved["ssid"] = staSsids[i];
saved["priority"] = staPriorities[i];
saved["active"] = staSsids[i] == activeStaSsid;
}
JsonObject alarmObj = doc.createNestedObject("alarms");
alarmObj["low_soc"] = alarms.lowSoc;
@@ -958,6 +1020,7 @@ void handleDebugSerial() {
if (command.startsWith("wifi ssid ")) {
staSsids[0] = command.substring(10);
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1;
Serial.println("OK WiFi SSID 1 updated");
Serial.println("Run: wifi save");
@@ -966,6 +1029,7 @@ void handleDebugSerial() {
if (command.startsWith("wifi pass ")) {
staPasswords[0] = command.substring(10);
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1;
Serial.println("OK WiFi password 1 updated");
Serial.println("Run: wifi save");
@@ -986,8 +1050,21 @@ void handleDebugSerial() {
return;
}
staSsids[wifiNetworkCount] = rest.substring(0, split);
staPasswords[wifiNetworkCount] = rest.substring(split + 1);
String ssid = rest.substring(0, split);
String passAndPriority = rest.substring(split + 1);
int secondSplit = passAndPriority.indexOf('|');
String password = passAndPriority;
int priority = wifiNetworkCount + 1;
if (secondSplit >= 0) {
password = passAndPriority.substring(0, secondSplit);
priority = passAndPriority.substring(secondSplit + 1).toInt();
if (priority <= 0) priority = wifiNetworkCount + 1;
}
staSsids[wifiNetworkCount] = ssid;
staPasswords[wifiNetworkCount] = password;
staPriorities[wifiNetworkCount] = priority;
wifiNetworkCount++;
Serial.println("OK WiFi network added");
@@ -1310,6 +1387,7 @@ void sendWifiConfigJson() {
JsonObject network = networks.createNestedObject();
network["index"] = i + 1;
network["ssid"] = staSsids[i];
network["priority"] = staPriorities[i];
network["password_set"] = staPasswords[i].length() > 0;
}
@@ -1348,23 +1426,30 @@ void handleUpdateWifiConfig() {
continue;
}
int priority = network["priority"] | (wifiNetworkCount + 1);
if (priority <= 0) priority = wifiNetworkCount + 1;
staSsids[wifiNetworkCount] = ssid;
staPasswords[wifiNetworkCount] = password;
staPriorities[wifiNetworkCount] = priority;
wifiNetworkCount++;
}
for (int i = wifiNetworkCount; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = "";
staPasswords[i] = "";
staPriorities[i] = i + 1;
}
} else {
if (doc["ssid"].is<String>()) {
staSsids[0] = doc["ssid"].as<String>();
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1;
}
if (doc["password"].is<String>()) {
staPasswords[0] = doc["password"].as<String>();
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1;
}
}
@@ -1635,6 +1720,7 @@ void setup() {
void loop() {
server.handleClient();
maintainStaWifi();
handleDebugSerial();
updateBms();
updateAlarms();