ESP32/Joining a network/44. Wi-Fi provisioning
Your chip
Your language
Joining a network · 44 of 81

Wi-Fi provisioning

Hard-coding the password works exactly once, on your own network. Getting somebody else's credentials into a device with no keyboard is a five-state problem, and the state everybody forgets is what happens when they move house.

/esp32/wifi-provisioning · arduino · S3

Five states, and the one everybody forgets

From no password to a board that stays connected
step 1 of 5
State
Nothing stored
First boot, or after a factory reset. NVS has no credentials, so there is nothing to try. Start an access point called something identifiable — not ESP_1A2B.

Do not make them type the network name

Scan, and offer a list. A typed SSID is a typo, and a typo is indistinguishable from a wrong password from the user's side. The scan also tells you the signal strength, which is worth showing — "this network is very weak here" prevents a support call later.

Which library

WiFiManager is the well-worn one and it does everything on this page. Espressif also ship a provisioning system that works over BLE from a phone app, which is nicer for a product and more work for a project. Either is better than writing it yourself; the value of this page is knowing what the library is doing and which of the five states it forgot.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

Try what is stored, and fall back to a setup portal when it fails. The button check at the top is the way back out - without it, a device on a changed network can only be fixed with a cable.

provision.ino
#include <WiFi.h>
#include <Preferences.h>

Preferences prefs;
const int RESET_BUTTON = 0;      // BOOT button, held at power-on

bool tryStored() {
  prefs.begin("wifi", true);
  String ssid = prefs.getString("ssid", "");
  String pass = prefs.getString("pass", "");
  prefs.end();
  if (ssid.isEmpty()) return false;

  WiFi.begin(ssid.c_str(), pass.c_str());
  unsigned long t = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - t < 20000) delay(250);
  return WiFi.status() == WL_CONNECTED;
}

void setup() {
  Serial.begin(115200);
  pinMode(RESET_BUTTON, INPUT_PULLUP);

  if (digitalRead(RESET_BUTTON) == LOW) {     // held at boot = forget
    prefs.begin("wifi", false);
    prefs.clear();
    prefs.end();
  }

  if (!tryStored()) {
    Serial.println("starting setup portal");
    // bring up the access point and the form - see Access point mode
  }
}

void loop() {}

Preferences stores the credentials in NVS, which survives a firmware update. That is what you want, and it is also why a factory reset has to erase it explicitly.

When it does not work

The user typed the password correctly and it still failed

Show them why. Reason 15 is a bad password, 201 is a network that does not exist. Reporting failed is what generates the support email.

The device works and then stops after the customer changes routers

There is no way back to the portal. Always ship an escape - a button held at power-on that clears the stored credentials.

The setup page will not open on a phone

No captive portal. Run a DNS server on the access point that answers every name with the board's own address, or the phone leaves before anyone types anything.

Credentials survive a firmware update that was meant to reset the device

They live in NVS, which is a separate partition. Erase it deliberately - do not assume flashing clears it.

Where this goes next

The credentials are in. On a C6 there is one more thing the radio can do that changes battery life more than anything else here.

Wi-Fi 6 features

Edit this page — content/esp32/wifi-provisioning.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.

Browse ESP32 on the forum