Unit H - ESP32 Wireless

45. Credentials, Reconnect and SoftAP Provisioning

Build a first-boot WiFi setup path: try STA, then open SoftAP with a form that captures credentials on Serial.

Estimated time 3-4 hours

Learning outcomes

  • Explain why hardcoded credentials fail for products
  • Retry STA with millis then fall back to SoftAP
  • Serve a SoftAP setup form and read POSTed SSID/password
  • State how Preferences/NVS would store credentials next
  • Test both STA-success and SoftAP-fallback paths

Parts and preparation

ESP32 DevKit, USB, phone or PC that can join SoftAP ESP32-Setup.

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.

IncludeLibrary Manager nameAuthorInstall note
WiFi.hWiFiEspressifBuilt into the esp32 Arduino core.
WebServer.hWebServerEspressifBuilt into the esp32 Arduino core.
Credentials, Reconnect and SoftAP Provisioning instructional connection diagram

Project: First-boot WiFi setup

Shipped devices cannot embed every customer's WiFi password in source. First-boot SoftAP lets a phone join ESP32-Setup and submit credentials.

Sketch 1 proves STA fail -> SoftAP notice page. Sketch 2 is the useful setup form: POST ssid/password and print them on Serial. Saving with Preferences/NVS is the clear next product step (challenge).

STA fail then SoftAP setup with phone
Try STA; on failure open SoftAP for setup.

Non-blocking STA wait

Count millis gaps instead of blocking forever. After maxTries, start SoftAP.

PhaseWhat you see
STA tryingSerial dots
STA OKLAN IP; SoftAP off
STA failedSoftAP ESP32-Setup; open softAP IP

Form, then NVS

HTML form POSTs fields to a handler. server.hasArg("ssid") reads them. Preferences.h putString/getString would store them in NVS across resets - out of scope for the worked SoftAP form, required thinking for products.

How to test

Wrong placeholders force SoftAP. Correct placeholders show STA OK. softAPIP() is often 192.168.4.1.

Wiring and safe build sequence

  1. USB only
  2. Phone joins ESP32-Setup for SoftAP tests
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.

Worked sketch 1: STA fail to SoftAP notice

Download .ino sketch

What this sketch is for: Discovery: after repeated STA failures, SoftAP ESP32-Setup serves a configure-me page.

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

const int maxTries = 20;
const unsigned long retryMs = 500;

WebServer server(80);
bool provisioning = false;
int tries = 0;
unsigned long lastTry = 0;

void handleRoot() {
  server.send(200, "text/html",
    "<!DOCTYPE html><html><body style='font-family:sans-serif;text-align:center;margin-top:40px'>"
    "<h1>ESP32-Setup</h1>"
    "<p>STA join failed - SoftAP is active.</p>"
    "<p>Upload sketch 2 for a credentials form.</p>"
    "</body></html>");
}

void startSoftAP() {
  provisioning = true;
  WiFi.mode(WIFI_AP);
  WiFi.softAP("ESP32-Setup");
  Serial.print("SoftAP IP: ");
  Serial.println(WiFi.softAPIP());
  server.on("/", handleRoot);
  server.begin();
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  lastTry = millis();
  Serial.println("Trying STA...");
}

void loop() {
  if (provisioning) {
    server.handleClient();
    return;
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("STA OK ");
    Serial.println(WiFi.localIP());
    delay(10000);
    return;
  }
  if (millis() - lastTry >= retryMs) {
    lastTry = millis();
    tries++;
    Serial.print(".");
    if (tries >= maxTries) {
      Serial.println();
      startSoftAP();
    }
  }
}

How the code works

  1. Use wrong placeholders to force SoftAP in a demo.
  2. Join ESP32-Setup and open the printed SoftAP IP.

Worked sketch 2: SoftAP credentials form

Download .ino sketch

What this sketch is for: First-boot style form on SoftAP: submit SSID and password, see them printed on Serial. This does not yet save to NVS - that is the deliberate next step.

#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);

void handleRoot() {
  server.send(200, "text/html",
    "<!DOCTYPE html><html><body style='font-family:sans-serif;margin:24px'>"
    "<h1>ESP32-Setup</h1>"
    "<p>Enter WiFi credentials (printed on Serial only in this lab).</p>"
    "<form method='POST' action='/save'>"
    "<p>SSID<br><input name='ssid' style='width:90%'></p>"
    "<p>Password<br><input name='password' type='password' style='width:90%'></p>"
    "<button type='submit'>Save</button>"
    "</form></body></html>");
}

void handleSave() {
  String newSsid = server.hasArg("ssid") ? server.arg("ssid") : "";
  String newPass = server.hasArg("password") ? server.arg("password") : "";
  Serial.println("Form received:");
  Serial.print("  SSID=");
  Serial.println(newSsid);
  Serial.print("  PASS=");
  Serial.println(newPass);
  server.send(200, "text/html",
    "<!DOCTYPE html><html><body style='font-family:sans-serif;text-align:center;margin-top:40px'>"
    "<h1>Received</h1><p>Check Serial Monitor. Next step: store with Preferences/NVS.</p>"
    "<p><a href='/'>Back</a></p></body></html>");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_AP);
  WiFi.softAP("ESP32-Setup");
  Serial.print("SoftAP IP: ");
  Serial.println(WiFi.softAPIP());
  server.on("/", handleRoot);
  server.on("/save", HTTP_POST, handleSave);
  server.begin();
  Serial.println("Join ESP32-Setup and open the SoftAP IP");
}

void loop() {
  server.handleClient();
}

How the code works

  1. HTTP_POST maps the form action /save.
  2. server.arg reads field values by name.
  3. Do not treat Serial-printed passwords as a product storage design.

Test and record evidence

Expected result: Sketch 1 with wrong WiFi: SoftAP page after dots. With correct WiFi: STA OK. Sketch 2: join ESP32-Setup, submit the form, Serial prints SSID and password.

Practical evidence checklist

Common faults and checks
  • SoftAP missing: wait for maxTries; watch Serial.
  • Form does nothing: use POST /save; open softAPIP exactly.
  • Phone blocks page: try another device.
Extension challenge: Store submitted SSID/password with Preferences and reboot into STA using the saved values.

Check your understanding

Q1. What project is this?

Show answer

First-boot WiFi setup over SoftAP.

Q2. Why are hardcoded passwords a product problem?

Show answer

Each site differs; secrets should not live in shared firmware source.

Q3. What SSID does SoftAP use?

Show answer

ESP32-Setup.

Q4. What does sketch 2 add?

Show answer

An HTML form that POSTs credentials to Serial.

Q5. Is NVS required in the worked form?

Show answer

No - taught as the next step.

Q6. Typical SoftAP IP?

Show answer

Often 192.168.4.1.

Q7. How to force SoftAP in sketch 1?

Show answer

Use wrong YOUR_WIFI placeholders.

Q8. Why millis retries?

Show answer

Abandon STA after N tries without blocking forever.