E12. Credentials, Reconnect and SoftAP Provisioning
Try to join Wi-Fi and fall back to the ESP32's own network if it fails, then collect a network name and password from a phone.
Learning outcomes
- Explain why real products do not have the Wi-Fi password typed into the code
- Give up joining after a set number of tries and start an access point instead
- Serve a form and read what the user typed into it
Parts and preparation
ESP32 DevKit, USB, phone or PC that can join the ESP32's network.
Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.
Libraries for this lesson
In Arduino IDE 2 open Tools → Manage Libraries…. Search by the Library Manager name and install the package by the exact author below. Similar names from other authors can use different APIs and will break the example.
| Include | Library Manager name | Author | Install note |
|---|---|---|---|
WiFi.h | WiFi | Espressif | Built into the esp32 Arduino core. |
WebServer.h | WebServer | Espressif | Built into the esp32 Arduino core. |
What you will do
A smart plug you buy cannot have your Wi-Fi password in its code. Instead, the first time it starts it makes its own network, you join it with your phone, and you type your password into a page. This is called provisioning.
Sketch 1 tries your Wi-Fi for 10 seconds and makes its own network if that fails. Sketch 2 shows a form where you type a network name and password.
Give up after a while
The Wi-Fi sketches so far wait for ever. Sketch 1 counts its tries and stops after 20 (20 x half a second = 10 seconds). The while loop keeps going only while both things are true: not connected AND fewer than 20 tries. && means AND.
| What happens | What you see |
|---|---|
| Trying | Dots on Serial |
| Joined | The IP address |
| Gave up | ESP32-Setup appears in your phone's Wi-Fi list |
Forms
An HTML form has boxes to type in and a button. Each box has a name, such as name='ssid'. When you press the button, the browser sends what you typed to /save, and server.arg("ssid") reads it.
Sketch 2 only prints what you typed. A real product would save it with the Preferences library so it is kept after power-off, then restart and join the network. The optional extension at the end of this lesson does exactly that.
How to test
Leave YOUR_WIFI_SSID in sketch 1 to see it give up and make ESP32-Setup. Type your real network to see it join. The setup network's address is usually 192.168.4.1.
Wiring and safe build sequence
- USB only
- Phone joins ESP32-Setup for the tests
Worked sketch 1: Join, or make a setup network
Download .inoWhat this sketch is for: Upload it with the placeholders left in. After 10 seconds, ESP32-Setup appears on your phone.
#include <WiFi.h> // the Wi-Fi commands
String ssid = "YOUR_WIFI_SSID"; // your Wi-Fi network name
String password = "YOUR_WIFI_PASSWORD"; // your Wi-Fi password
void setup() { // runs once
Serial.begin(115200); // start Serial at the ESP32 speed
WiFi.begin(ssid, password); // start joining the network
Serial.print("Trying Wi-Fi"); // tell the user we are trying
int tries = 0; // how many times we have checked
while (WiFi.status() != WL_CONNECTED && tries < 20) { // not joined AND under 20 tries
delay(500); // wait half a second
Serial.print("."); // print a dot each time
tries = tries + 1; // count this try
}
Serial.println(); // end the line of dots
if (WiFi.status() == WL_CONNECTED) { // did we join?
Serial.print("Joined. IP address: "); // yes - say so
Serial.println(WiFi.localIP()); // and show the address
} else { // no - we gave up
WiFi.softAP("ESP32-Setup"); // make our own network (no password)
Serial.print("Could not join. Connect to ESP32-Setup, address: "); // tell the user
Serial.println(WiFi.softAPIP()); // usually 192.168.4.1
}
}
void loop() { // nothing to repeat in this sketch
}How the code works
- && means AND: the loop stops as soon as either test is false.
- WiFi.softAP("ESP32-Setup") with no password makes an open network, which is fine for a short setup step.
Worked sketch 2: A setup form
Download .inoWhat this sketch is for: Join ESP32-Setup on your phone, open http://192.168.4.1, fill in the form and press Send. Serial shows what you typed. Use a made-up password for testing.
#include <WiFi.h> // the Wi-Fi commands
#include <WebServer.h> // the web server commands
WebServer server(80); // a web server on port 80
void sendForm() { // runs when a browser asks for /
String page = "<h1>Wi-Fi setup</h1>"; // a heading
page += "<form method='POST' action='/save'>"; // a form that sends to /save
page += "<p>Network name <input name='ssid'></p>"; // a box called ssid
page += "<p>Password <input name='password'></p>"; // a box called password
page += "<button>Send</button>"; // the send button
page += "</form>"; // end of the form
server.send(200, "text/html", page); // send the page to the browser
}
void handleSave() { // runs when the form is sent to /save
Serial.print("Network name: "); // a label
Serial.println(server.arg("ssid")); // what was typed in the ssid box
Serial.print("Password: "); // a label
Serial.println(server.arg("password")); // what was typed in the password box
server.send(200, "text/html", "<h1>Received - thank you</h1>"); // reply to the phone
}
void setup() { // runs once
Serial.begin(115200); // start Serial at the ESP32 speed
WiFi.softAP("ESP32-Setup"); // make our own network
Serial.print("Join ESP32-Setup and open http://"); // tell the user what to do
Serial.println(WiFi.softAPIP()); // usually 192.168.4.1
server.on("/", sendForm); // path / shows the form
server.on("/save", handleSave); // path /save reads the form
server.begin(); // start the web server
}
void loop() { // runs over and over
server.handleClient(); // answer any browser that is asking
}How the code works
- method='POST' sends the boxes hidden inside the request, not in the address bar.
- The names in name='ssid' and server.arg("ssid") must match exactly.
- Printing a password is only for learning - a real product saves it and never prints it.
Test and record evidence
Practical evidence checklist
Common faults and checks
- ESP32-Setup missing: wait the full 10 seconds and watch Serial.
- Phone switches back to home Wi-Fi: it may dislike networks without internet - tell it to stay connected.
- Form page does not open: type http://192.168.4.1 exactly, while joined to ESP32-Setup.
Check your understanding
Q1. Why do real products not have the Wi-Fi password in their code?
Show answer
Every home has a different network, so the user types it in at setup.
Q2. What is provisioning?
Show answer
Giving a new device its Wi-Fi details, usually from a phone.
Q3. What does && mean?
Show answer
AND - both tests must be true.
Q4. How long does sketch 1 try before giving up?
Show answer
10 seconds: 20 tries of half a second.
Q5. What is the usual address of the ESP32's own network?
Show answer
192.168.4.1.
Q6. How does handleSave read the network name?
Show answer
server.arg("ssid") - the name of the form box.
Q7. What would a real product do instead of printing the password?
Show answer
Save it with the Preferences library and use it to join the network.
Save the Wi-Fi details with Preferences
This sketch joins sketch 1 and sketch 2 together and adds saving. When it starts, it reads the saved network name and password and tries to join. If nothing is saved yet, or joining fails, it makes ESP32-Setup and shows the form. When you press Send, it saves what you typed and restarts. This time it joins your network.
Preferences is a small storage area in the ESP32's flash memory. It keeps values after power-off, like a notebook. Each value has a name: saved.putString("ssid", ...) writes the name, and saved.getString("ssid", "") reads it back, giving "" (nothing) if nothing was saved yet.
To test: upload, join ESP32-Setup on your phone, open http://192.168.4.1 and type your real network name and password. The ESP32 restarts and Serial shows Joined. Unplug it and plug it back in: it joins again without the form. There is no password in the code at all.
#include <WiFi.h> // the Wi-Fi commands
#include <WebServer.h> // the web server commands
#include <Preferences.h> // saves small values that survive power-off
WebServer server(80); // a web server on port 80
Preferences saved; // our notebook of saved values
void sendForm() { // runs when a browser asks for /
String page = "<h1>Wi-Fi setup</h1>"; // a heading
page += "<form method='POST' action='/save'>"; // a form that sends to /save
page += "<p>Network name <input name='ssid'></p>"; // a box called ssid
page += "<p>Password <input name='password'></p>"; // a box called password
page += "<button>Send</button>"; // the send button
page += "</form>"; // end of the form
server.send(200, "text/html", page); // send the page to the browser
}
void handleSave() { // runs when the form is sent to /save
saved.putString("ssid", server.arg("ssid")); // save the network name
saved.putString("password", server.arg("password")); // save the password
server.send(200, "text/html", "<h1>Saved - restarting</h1>"); // reply to the phone
delay(1000); // give the reply time to reach the phone
ESP.restart(); // start again, this time with the saved details
}
void setup() { // runs once
Serial.begin(115200); // start Serial at the ESP32 speed
saved.begin("wifi", false); // open the notebook called wifi (false = we may write)
String ssid = saved.getString("ssid", ""); // the saved name, or "" if none yet
String password = saved.getString("password", ""); // the saved password, or "" if none yet
WiFi.begin(ssid, password); // start joining the saved network
Serial.print("Trying Wi-Fi"); // tell the user we are trying
int tries = 0; // how many times we have checked
while (WiFi.status() != WL_CONNECTED && tries < 20) { // not joined AND under 20 tries
delay(500); // wait half a second
Serial.print("."); // print a dot each time
tries = tries + 1; // count this try
}
Serial.println(); // end the line of dots
if (WiFi.status() == WL_CONNECTED) { // did we join?
Serial.print("Joined. IP address: "); // yes - say so
Serial.println(WiFi.localIP()); // and show the address
} else { // no - nothing saved, or the details were wrong
WiFi.softAP("ESP32-Setup"); // make our own network
Serial.print("Join ESP32-Setup and open http://"); // tell the user what to do
Serial.println(WiFi.softAPIP()); // usually 192.168.4.1
server.on("/", sendForm); // path / shows the form
server.on("/save", handleSave); // path /save saves the form
server.begin(); // start the web server
}
}
void loop() { // runs over and over
server.handleClient(); // answer any browser (only in setup mode)
}How the saving sketch works
The very first time, nothing is saved, so it tries an empty network name for 10 seconds and then makes ESP32-Setup. That is expected.
"wifi" in saved.begin("wifi", false) is the notebook's name. Other sketches can use their own notebook without mixing values.
If you type the password wrong, it will fail to join after the restart and show the form again, so you can fix it.
Uploading a new sketch does not wipe Preferences. The saved details stay until you save new ones.