Several networks, one board
Teach the board every network it might meet and let it choose when it arrives. It costs one scan and removes the reflash between the workshop and the house.
What run() is doing while it prints dots
WiFi.begin(): this list is built before any join is attempted, so the board can compare rather than guess.WiFi.begin(ssid, password) tries exactly one network and waits to be told it
failed. wifiMulti.run() scans first, builds the list above, sorts it by signal
strength, and joins the strongest one it has credentials for.
That is the entire difference, and it explains all the behaviour: it is slower to start, it prefers the near access point over the far one, and adding a network you are nowhere near costs one comparison in a list.
When it is the right tool
A board that moves — between a bench, a workshop and a house — and whose owner
is you. Three addAP lines and one firmware travels.
It is also a decent fallback ladder: your network, then a phone hotspot, then whatever the venue's Wi-Fi is called. The board works its way down without anybody plugging in a cable.
When it is not
If somebody else owns the board, they cannot edit your sketch, and the answer is provisioning: a captive portal that asks for the credentials once and stores them in flash.
If the board is on a battery, the scan is expensive — a second or two of radio at full power on every wake. Remember the channel and BSSID that worked last time, try that first, and only fall back to a scan when it fails.
Keep calling it
run() in setup() connects once. run() in loop() is what reconnects after
the router reboots at three in the morning. It returns immediately when the link
is already up, so the cost of leaving it there is nothing.
The code
Add as many networks as you like. run() scans, sorts what it found by signal strength, and joins the strongest one it has a password for.
#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti wifi;
void setup() {
Serial.begin(115200);
wifi.addAP("home-2g", "home-password");
wifi.addAP("workshop", "workshop-password");
wifi.addAP("phone-tether", "hotspot-password");
if (wifi.run(20000) == WL_CONNECTED)
Serial.printf("joined %s %d dBm %s\n",
WiFi.SSID().c_str(), WiFi.RSSI(),
WiFi.localIP().toString().c_str());
}
void loop() {
// Cheap when connected; re-scans and re-joins when it is not.
if (wifi.run(10000) != WL_CONNECTED) delay(1000);
}run() takes a timeout and returns a status, not a boolean. Calling it in loop() as well as setup() is what makes it reconnect after a network disappears.
There is no WiFiMulti in MicroPython, and there does not need to be — scan() returns the list and picking from it is four lines.
import network, time
KNOWN = {
"home-2g": "home-password",
"workshop": "workshop-password",
}
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
found = sorted(wlan.scan(), key=lambda n: n[3], reverse=True)
for ssid, _bssid, _ch, rssi, *_ in found:
name = ssid.decode()
if name in KNOWN:
print("joining", name, rssi, "dBm")
wlan.connect(name, KNOWN[name])
break
for _ in range(40):
if wlan.isconnected():
break
time.sleep(0.25)
print(wlan.ifconfig()[0] if wlan.isconnected() else "no known network here")Sorting by rssi is what WiFiMulti does under the covers. Writing it out is worth doing once, because it makes it obvious that "several networks" costs one scan and no magic.
When it does not work
None of the saved networks are in range, or all of them are 5 GHz. run() keeps scanning and never errors, so this looks identical to a hang. Print the scan results once to see what the board can actually hear.
A scan is a snapshot. If both APs share one SSID, the board picks a BSSID at that instant and stays with it until the link drops — it does not roam. This is a limitation of the stack, not of the sketch.
It does, and that is the trade. A scan is a second or two before any join is attempted. On a battery project, cache the SSID, channel and BSSID that worked and try that first with plain WiFi.begin.
A rejoin gives you a link, not your sockets. Everything layered on top has to be told: check WiFi.status() and reconnect the client when it changes, rather than assuming the first connect was the only one.
The version for boards you hand to somebody else, where the credentials arrive from a phone instead of from your editor.
Wi-Fi provisioning →Edit this page — content/esp32/multiple-networks-with-wifimulti.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.