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"} {"type":"wifi_clear"}
AP mode remains enabled as the recovery path. 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"> <div class="tempList" style="margin-top:12px">
<input id="w1s" placeholder="Network 1 SSID"> <input id="w1s" placeholder="Network 1 SSID">
<input id="w1p" placeholder="Network 1 password" type="password"> <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="w2s" placeholder="Network 2 SSID">
<input id="w2p" placeholder="Network 2 password" type="password"> <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="w3s" placeholder="Network 3 SSID">
<input id="w3p" placeholder="Network 3 password" type="password"> <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="saveWifi()">Save WiFi</button>
<button onclick="connectWifi()">Connect Now</button> <button onclick="connectWifi()">Connect Now</button>
</div> </div>
@@ -169,6 +172,8 @@ async function loadWifiConfig(){
const n=nets[i]||{}; const n=nets[i]||{};
const s=$("w"+(i+1)+"s"); const s=$("w"+(i+1)+"s");
if(s) s.value=n.ssid||""; if(s) s.value=n.ssid||"";
const pr=$("w"+(i+1)+"r");
if(pr) pr.value=n.priority||i+1;
} }
}catch(e){} }catch(e){}
} }
@@ -177,7 +182,8 @@ async function saveWifi(){
for(let i=1;i<=3;i++){ for(let i=1;i<=3;i++){
const ssid=$("w"+i+"s").value.trim(); const ssid=$("w"+i+"s").value.trim();
const password=$("w"+i+"p").value; 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",{ await fetch("/config/wifi",{
method:"POST", method:"POST",
@@ -218,8 +224,11 @@ Preferences wifiPrefs;
const int MAX_WIFI_NETWORKS = 3; const int MAX_WIFI_NETWORKS = 3;
String staSsids[MAX_WIFI_NETWORKS]; String staSsids[MAX_WIFI_NETWORKS];
String staPasswords[MAX_WIFI_NETWORKS]; String staPasswords[MAX_WIFI_NETWORKS];
int staPriorities[MAX_WIFI_NETWORKS];
int wifiNetworkCount = 0; int wifiNetworkCount = 0;
String activeStaSsid = ""; String activeStaSsid = "";
unsigned long lastStaReconnectAttempt = 0;
const unsigned long STA_RECONNECT_INTERVAL_MS = 30000;
void loadWifiConfig() { void loadWifiConfig() {
wifiPrefs.begin("wifi", true); wifiPrefs.begin("wifi", true);
@@ -232,6 +241,7 @@ void loadWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) { for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = wifiPrefs.getString(("ssid" + String(i)).c_str(), ""); staSsids[i] = wifiPrefs.getString(("ssid" + String(i)).c_str(), "");
staPasswords[i] = wifiPrefs.getString(("pass" + 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 // Migration path from old single-network config
@@ -242,6 +252,7 @@ void loadWifiConfig() {
if (oldSsid.length() > 0) { if (oldSsid.length() > 0) {
staSsids[0] = oldSsid; staSsids[0] = oldSsid;
staPasswords[0] = oldPassword; staPasswords[0] = oldPassword;
staPriorities[0] = 1;
wifiNetworkCount = 1; wifiNetworkCount = 1;
} }
} }
@@ -257,6 +268,7 @@ void saveWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) { for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
wifiPrefs.putString(("ssid" + String(i)).c_str(), staSsids[i]); wifiPrefs.putString(("ssid" + String(i)).c_str(), staSsids[i]);
wifiPrefs.putString(("pass" + String(i)).c_str(), staPasswords[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 // Keep legacy keys updated for easier debugging
@@ -277,9 +289,30 @@ void clearWifiConfig() {
for (int i = 0; i < MAX_WIFI_NETWORKS; i++) { for (int i = 0; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = ""; staSsids[i] = "";
staPasswords[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() { void connectStaWifi() {
if (wifiNetworkCount <= 0) { if (wifiNetworkCount <= 0) {
Serial.println("STA WiFi not configured."); Serial.println("STA WiFi not configured.");
@@ -289,12 +322,20 @@ void connectStaWifi() {
WiFi.disconnect(false); WiFi.disconnect(false);
activeStaSsid = ""; activeStaSsid = "";
for (int i = 0; i < wifiNetworkCount; i++) { bool tried[MAX_WIFI_NETWORKS] = {false, false, false};
if (staSsids[i].length() == 0) {
continue; 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]); Serial.println(staSsids[i]);
WiFi.begin(staSsids[i].c_str(), staPasswords[i].c_str()); 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."); 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() { void printNetworkStatus() {
Serial.println("Network:"); Serial.println("Network:");
Serial.print(" AP IP: "); Serial.print(" AP IP: ");
@@ -441,6 +495,14 @@ void buildStatusDocument(JsonDocument& doc) {
network["sta_ssid"] = activeStaSsid; network["sta_ssid"] = activeStaSsid;
network["sta_ip"] = WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : ""; network["sta_ip"] = WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : "";
network["saved_network_count"] = wifiNetworkCount; 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"); JsonObject alarmObj = doc.createNestedObject("alarms");
alarmObj["low_soc"] = alarms.lowSoc; alarmObj["low_soc"] = alarms.lowSoc;
@@ -958,6 +1020,7 @@ void handleDebugSerial() {
if (command.startsWith("wifi ssid ")) { if (command.startsWith("wifi ssid ")) {
staSsids[0] = command.substring(10); staSsids[0] = command.substring(10);
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1; if (wifiNetworkCount < 1) wifiNetworkCount = 1;
Serial.println("OK WiFi SSID 1 updated"); Serial.println("OK WiFi SSID 1 updated");
Serial.println("Run: wifi save"); Serial.println("Run: wifi save");
@@ -966,6 +1029,7 @@ void handleDebugSerial() {
if (command.startsWith("wifi pass ")) { if (command.startsWith("wifi pass ")) {
staPasswords[0] = command.substring(10); staPasswords[0] = command.substring(10);
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1; if (wifiNetworkCount < 1) wifiNetworkCount = 1;
Serial.println("OK WiFi password 1 updated"); Serial.println("OK WiFi password 1 updated");
Serial.println("Run: wifi save"); Serial.println("Run: wifi save");
@@ -986,8 +1050,21 @@ void handleDebugSerial() {
return; return;
} }
staSsids[wifiNetworkCount] = rest.substring(0, split); String ssid = rest.substring(0, split);
staPasswords[wifiNetworkCount] = rest.substring(split + 1); 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++; wifiNetworkCount++;
Serial.println("OK WiFi network added"); Serial.println("OK WiFi network added");
@@ -1310,6 +1387,7 @@ void sendWifiConfigJson() {
JsonObject network = networks.createNestedObject(); JsonObject network = networks.createNestedObject();
network["index"] = i + 1; network["index"] = i + 1;
network["ssid"] = staSsids[i]; network["ssid"] = staSsids[i];
network["priority"] = staPriorities[i];
network["password_set"] = staPasswords[i].length() > 0; network["password_set"] = staPasswords[i].length() > 0;
} }
@@ -1348,23 +1426,30 @@ void handleUpdateWifiConfig() {
continue; continue;
} }
int priority = network["priority"] | (wifiNetworkCount + 1);
if (priority <= 0) priority = wifiNetworkCount + 1;
staSsids[wifiNetworkCount] = ssid; staSsids[wifiNetworkCount] = ssid;
staPasswords[wifiNetworkCount] = password; staPasswords[wifiNetworkCount] = password;
staPriorities[wifiNetworkCount] = priority;
wifiNetworkCount++; wifiNetworkCount++;
} }
for (int i = wifiNetworkCount; i < MAX_WIFI_NETWORKS; i++) { for (int i = wifiNetworkCount; i < MAX_WIFI_NETWORKS; i++) {
staSsids[i] = ""; staSsids[i] = "";
staPasswords[i] = ""; staPasswords[i] = "";
staPriorities[i] = i + 1;
} }
} else { } else {
if (doc["ssid"].is<String>()) { if (doc["ssid"].is<String>()) {
staSsids[0] = doc["ssid"].as<String>(); staSsids[0] = doc["ssid"].as<String>();
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1; if (wifiNetworkCount < 1) wifiNetworkCount = 1;
} }
if (doc["password"].is<String>()) { if (doc["password"].is<String>()) {
staPasswords[0] = doc["password"].as<String>(); staPasswords[0] = doc["password"].as<String>();
staPriorities[0] = 1;
if (wifiNetworkCount < 1) wifiNetworkCount = 1; if (wifiNetworkCount < 1) wifiNetworkCount = 1;
} }
} }
@@ -1635,6 +1720,7 @@ void setup() {
void loop() { void loop() {
server.handleClient(); server.handleClient();
maintainStaWifi();
handleDebugSerial(); handleDebugSerial();
updateBms(); updateBms();
updateAlarms(); updateAlarms();