ESP32: Create a Wi-Fi Manager (AsyncWebServer library)Setting Up the Web ServerUploading Code and FilesDemonstrationWrapping Up

In this guide, you’ll create and set up a Wi-Fi Manager with the ESPAsyncWebServer library that you can modify to use with your web server projects or with any project that needs a connection to a Wi-Fi network. The Wi-Fi Manager allows you to connect the ESP32 board to different Access Points (networks) without hard-coding network credentials (SSID and password) and upload new code to your board. Your ESP will automatically join the last saved network or set up an Access Point that you can use to configure the network credentials.

ESP32: Create a Simple Wi-Fi Manager (AsyncWebServer library)

To better understand how this project works, we recommend taking a look at the following tutorials:

We also use this Wi-Fi Manager approach on the following project:

How it Works

Take a look at the following diagram to understand how the Wi-Fi Manager we’ll create works.

ESP32 ESP8266 Wi-Fi Manager Web Server How it Works
  • When the ESP first starts, it tries to read the ssid.txt, pass.txt and ip.txt files* (1);
  • If the files are empty (2) (the first time you run the board, the files are empty), your board is set as an access point (3);
  • Using any Wi-Fi enabled device with a browser, you can connect to the newly created Access Point (default name ESP-WIFI-MANAGER);
  • After establishing a connection with the ESP-WIFI-MANAGER, you can go to the default IP address 192.168.4.1 to open a web page that allows you to configure your SSID and password (4);
  • The SSID, password, and IP address inserted in the form are saved in the corresponding files: ssid.txt, pass.txt, and ip.txt (5);
  • After that, the ESP board restarts (6);
  • This time, after restarting, the files are not empty, so the ESP will try to connect to the network in station mode using the settings you’ve inserted in the form (7);
  • If it establishes a connection, the process is completed successfully, and you can access the main web server page that can do whatever you want (control sensor readings, control outputs, display some text, etc.) (9). Otherwise, it will set the Access Point (3), and you can access the default IP address (192.168.4.1) to add another SSID/password combination.

* we also created a gateway field and a gateway.txt file to save the IP address gateway (this is not shown in the diagram).

To show you how to set the Wi-Fi Manager, we’ll set up a web server that controls one output (GPIO2—the built-in LED). You can apply the Wi-Fi Manager to any web server project built with the ESPAsyncWebServer library or to any project that requires the ESP to be connected to a wi-fi network.

Prerequisites

We’ll program the ESP32 board using Arduino IDE. So make sure you have the ESP32 board add-on installed.

If you want to program the ESP32 using VS Code + PlatformIO, follow the next tutorial:

Installing Libraries (Arduino IDE)

You need to install the following libraries in your Arduino IDE to build the web server for this project.

  • (.zip folder)
  • (.zip folder)

The ESPAsyncWebServer, AsynTCP, and ESPAsyncTCP libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino installation Libraries folder. Alternatively, in your Arduino IDE, you can go to Sketch > Include Library > Add .zip Library and select the libraries you’ve just downloaded.

Installing Libraries (VS Code + PlatformIO)

If you’re programming the ESP32 using PlatformIO, copy the following to the platformio.ini to include the ESPAsyncWebServer library (it will automatically include any dependencies like the AsynTCP or ESPAsyncTCP libraries), set the default filesystem to LittleFS and change the baud rate to 115200:

monitor_speed = 115200
lib_deps = ESP Async WebServer
board_build.filesystem = littlefs

Filesystem Uploader

Before proceeding, you need to have the ESP32 Uploader Plugin installed in your Arduino IDE.

If you’re using VS Code with PlatformIO, follow the next tutorials to learn how to upload files to the filesystem:

Organizing your Files

To keep the project organized and make it easier to understand, we’ll create four different files to build the web server:

  • Arduino sketch that handles the web server;
  • index.html: to define the content of the web page in station mode to control the output (or any other web page you want to build);
  • style.css: to style the web pages;
  • wifimanager.html: to define the web page’s content to display the Wi-Fi Manager when the ESP is in access point mode.
ESP32 ESP8266 Wi-Fi Manager Project Files

You should save the HTML and CSS files inside a folder called data inside the Arduino sketch folder, as shown in the previous diagram. We’ll upload these files to the ESP32 filesystem (LittleFS).

You can download all project files:

Creating the HTML Files

For this project, you need two HTML files. One to build the main page that controls the output (index.html) and another to build the Wi-Fi Manager page (wifimanager.html).

index.html

Here’s the text you should copy to your index.html file.

<!DOCTYPE html>
<html>
  <head>
    <title>ESP WEB SERVER</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="style.css">
    <link rel="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  </head>
  <body>
    <div class="topnav">
      <h1>ESP WEB SERVER</h1>
    </div>
    <div class="content">
      <div class="card-grid">
        <div class="card">
          <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 2</p>
          <p>
            <a href="on"><button class="button-on">ON</button></a>
            <a href="off"><button class="button-off">OFF</button></a>
          </p>
          <p class="state">State: %STATE%</p>
        </div>
      </div>
    </div>
  </body>
</html>

We won’t explain how this HTML file works because that’s not the purpose of this tutorial. The purpose of this tutorial is to explain the parts related to the Wi-Fi Manager.

wifimanager.html

The Wi-Fi Manager web page looks like this:

ESP32 ESP8266 Wi-Fi Manager Fields

Copy the following to the wifimanager.html file. This creates a web page with a form with three input fields and a Submit button.

<!DOCTYPE html>
<html>
<head>
  <title>ESP Wi-Fi Manager</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <div class="topnav">
    <h1>ESP Wi-Fi Manager</h1>
  </div>
  <div class="content">
    <div class="card-grid">
      <div class="card">
        <form action="/" method="POST">
          <p>
            <label for="ssid">SSID</label>
            <input type="text" id ="ssid" name="ssid"><br>
            <label for="pass">Password</label>
            <input type="text" id ="pass" name="pass"><br>
            <label for="ip">IP Address</label>
            <input type="text" id ="ip" name="ip" value="192.168.1.200"><br>
            <label for="gateway">Gateway Address</label>
            <input type="text" id ="gateway" name="gateway" value="192.168.1.1"><br>
            <input type ="submit" value ="Submit">
          </p>
        </form>
      </div>
    </div>
  </div>
</body>
</html>

In this HTML file, we create an HTML form that will make an HTTP POST request with the data submitted to the server.

<form action="/" method="POST">

The form contains three input fields and corresponding labels: SSID, password, and IP address.

This is the input field for the SSID:

<label for="ssid">SSID</label>
<input type="text" id ="ssid" name="ssid"><br>

This is the input field for the password.

<label for="pass">Password</label>
<input type="text" id ="pass" name="pass"><br>

There is an input field for the IP address that you want to attribute to the ESP in station mode. As default, we set it to 192.168.1.200 (you can set another default IP address, or you can delete the value parameter—it won’t have a default value).

<input type="text" id ="ip" name="ip" value="192.168.1.200">

Finally, there’s an input field for the gateway address. If the default IP address is 192.168.1.200, the gateway can be 192.168.1.1 by default.

<input type="text" id ="gateway" name="gateway" value="192.168.1.1"><br>

CSS File

Copy the following styles to your style.css file. We won’t explain how these styles work. We have already explained how similar styles work in .

html {
  font-family: Arial, Helvetica, sans-serif; 
  display: inline-block; 
  text-align: center;
}

h1 {
  font-size: 1.8rem; 
  color: white;
}

p { 
  font-size: 1.4rem;
}

.topnav { 
  overflow: hidden; 
  background-color: #0A1128;
}

body {  
  margin: 0;
}

.content { 
  padding: 5%;
}

.card-grid { 
  max-width: 800px; 
  margin: 0 auto; 
  display: grid; 
  grid-gap: 2rem; 
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.card { 
  background-color: white; 
  box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}

.card-title { 
  font-size: 1.2rem;
  font-weight: bold;
  color: #034078
}

input[type=submit] {
  border: none;
  color: #FEFCFB;
  background-color: #034078;
  padding: 15px 15px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  width: 100px;
  margin-right: 10px;
  border-radius: 4px;
  transition-duration: 0.4s;
  }

input[type=submit]:hover {
  background-color: #1282A2;
}

input[type=text], input[type=number], select {
  width: 50%;
  padding: 12px 20px;
  margin: 18px;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

label {
  font-size: 1.2rem; 
}
.value{
  font-size: 1.2rem;
  color: #1282A2;  
}
.state {
  font-size: 1.2rem;
  color: #1282A2;
}
button {
  border: none;
  color: #FEFCFB;
  padding: 15px 32px;
  text-align: center;
  font-size: 16px;
  width: 100px;
  border-radius: 4px;
  transition-duration: 0.4s;
}
.button-on {
  background-color: #034078;
}
.button-on:hover {
  background-color: #1282A2;
}
.button-off {
  background-color: #858585;
}
.button-off:hover {
  background-color: #252524;
} 

Setting Up the Web Server

If you’re using VS Code with the platformIO extension, you need to edit the platformio.ini file to look as shown below. If you’re using Arduino IDE, you can ignore this.

platformio.ini ESP32:

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed=115200
lib_deps = ESP Async WebServer

Code

Copy the following code to your Arduino IDE or to the main.cpp file if you’re using VS Code.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-wi-fi-manager-asyncwebserver/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include "LittleFS.h"

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "ssid";
const char* PARAM_INPUT_2 = "pass";
const char* PARAM_INPUT_3 = "ip";
const char* PARAM_INPUT_4 = "gateway";

//Variables to save values from HTML form
String ssid;
String pass;
String ip;
String gateway;

// File paths to save input values permanently
const char* ssidPath = "/ssid.txt";
const char* passPath = "/pass.txt";
const char* ipPath = "/ip.txt";
const char* gatewayPath = "/gateway.txt";

IPAddress localIP;
//IPAddress localIP(192, 168, 1, 200); // hardcoded

// Set your Gateway IP address
IPAddress localGateway;
//IPAddress localGateway(192, 168, 1, 1); //hardcoded
IPAddress subnet(255, 255, 0, 0);

// Timer variables
unsigned long previousMillis = 0;
const long interval = 10000;  // interval to wait for Wi-Fi connection (milliseconds)

// Set LED GPIO
const int ledPin = 2;
// Stores LED state

String ledState;

// Initialize LittleFS
void initLittleFS() {
  if (!LittleFS.begin(true)) {
    Serial.println("An error has occurred while mounting LittleFS");
  }
  Serial.println("LittleFS mounted successfully");
}

// Read File from LittleFS
String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s/r/n", path);

  File file = fs.open(path);
  if(!file || file.isDirectory()){
    Serial.println("- failed to open file for reading");
    return String();
  }
  
  String fileContent;
  while(file.available()){
    fileContent = file.readStringUntil('/n');
    break;     
  }
  return fileContent;
}

// Write file to LittleFS
void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s/r/n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- write failed");
  }
}

// Initialize WiFi
bool initWiFi() {
  if(ssid=="" || ip==""){
    Serial.println("Undefined SSID or IP address.");
    return false;
  }

  WiFi.mode(WIFI_STA);
  localIP.fromString(ip.c_str());
  localGateway.fromString(gateway.c_str());


  if (!WiFi.config(localIP, localGateway, subnet)){
    Serial.println("STA Failed to configure");
    return false;
  }
  WiFi.begin(ssid.c_str(), pass.c_str());
  Serial.println("Connecting to WiFi...");

  unsigned long currentMillis = millis();
  previousMillis = currentMillis;

  while(WiFi.status() != WL_CONNECTED) {
    currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      Serial.println("Failed to connect.");
      return false;
    }
  }

  Serial.println(WiFi.localIP());
  return true;
}

// Replaces placeholder with LED state value
String processor(const String& var) {
  if(var == "STATE") {
    if(digitalRead(ledPin)) {
      ledState = "ON";
    }
    else {
      ledState = "OFF";
    }
    return ledState;
  }
  return String();
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);

  initLittleFS();

  // Set GPIO 2 as an OUTPUT
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // Load values saved in LittleFS
  ssid = readFile(LittleFS, ssidPath);
  pass = readFile(LittleFS, passPath);
  ip = readFile(LittleFS, ipPath);
  gateway = readFile (LittleFS, gatewayPath);
  Serial.println(ssid);
  Serial.println(pass);
  Serial.println(ip);
  Serial.println(gateway);

  if(initWiFi()) {
    // Route for root / web page
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
      request->send(LittleFS, "/index.html", "text/html", false, processor);
    });
    server.serveStatic("/", LittleFS, "/");
    
    // Route to set GPIO state to HIGH
    server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request) {
      digitalWrite(ledPin, HIGH);
      request->send(LittleFS, "/index.html", "text/html", false, processor);
    });

    // Route to set GPIO state to LOW
    server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request) {
      digitalWrite(ledPin, LOW);
      request->send(LittleFS, "/index.html", "text/html", false, processor);
    });
    server.begin();
  }
  else {
    // Connect to Wi-Fi network with SSID and password
    Serial.println("Setting AP (Access Point)");
    // NULL sets an open Access Point
    WiFi.softAP("ESP-WIFI-MANAGER", NULL);

    IPAddress IP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(IP); 

    // Web Server Root URL
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send(LittleFS, "/wifimanager.html", "text/html");
    });
    
    server.serveStatic("/", LittleFS, "/");
    
    server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
      int params = request->params();
      for(int i=0;i<params;i++){
        AsyncWebParameter* p = request->getParam(i);
        if(p->isPost()){
          // HTTP POST ssid value
          if (p->name() == PARAM_INPUT_1) {
            ssid = p->value().c_str();
            Serial.print("SSID set to: ");
            Serial.println(ssid);
            // Write file to save value
            writeFile(LittleFS, ssidPath, ssid.c_str());
          }
          // HTTP POST pass value
          if (p->name() == PARAM_INPUT_2) {
            pass = p->value().c_str();
            Serial.print("Password set to: ");
            Serial.println(pass);
            // Write file to save value
            writeFile(LittleFS, passPath, pass.c_str());
          }
          // HTTP POST ip value
          if (p->name() == PARAM_INPUT_3) {
            ip = p->value().c_str();
            Serial.print("IP Address set to: ");
            Serial.println(ip);
            // Write file to save value
            writeFile(LittleFS, ipPath, ip.c_str());
          }
          // HTTP POST gateway value
          if (p->name() == PARAM_INPUT_4) {
            gateway = p->value().c_str();
            Serial.print("Gateway set to: ");
            Serial.println(gateway);
            // Write file to save value
            writeFile(LittleFS, gatewayPath, gateway.c_str());
          }
          //Serial.printf("POST[%s]: %s/n", p->name().c_str(), p->value().c_str());
        }
      }
      request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip);
      delay(3000);
      ESP.restart();
    });
    server.begin();
  }
}

void loop() {

}

How The Code Works

Let’s take a look at the code and see how the Wi-Fi Manager works.

The following variables are used to search for the SSID, password, IP address, and gateway on the HTTP POST request made when the form is submitted.

// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "ssid";
const char* PARAM_INPUT_2 = "pass";
const char* PARAM_INPUT_3 = "ip";
const char* PARAM_INPUT_4 = "gateway";

The ssid, pass, ip, and gateway variables save the values of the SSID, password, IP address, and gateway submitted in the form.

//Variables to save values from HTML form
String ssid;
String pass;
String ip;
String gateway;

The SSID, password, IP address, and gateway when submitted are saved in files in the ESP filesystem. The following variables refer to the path of those files.

// File paths to save input values permanently
const char* ssidPath = "/ssid.txt";
const char* passPath = "/pass.txt";
const char* ipPath = "/ip.txt";
const char* gatewayPath = "/gateway.txt";

The station IP address and gateway are submitted in the Wi-Fi Manager form. The subnet is hardcoded but you can easily modify this project with another field to include the subnet, if needed.

IPAddress localIP;
//IPAddress localIP(192, 168, 1, 200); // hardcoded

// Set your Gateway IP address
IPAddress localGateway;
//IPAddress localGateway(192, 168, 1, 1); //hardcoded
IPAddress subnet(255, 255, 0, 0);

initWiFi()

The initWiFi() function returns a boolean value (either true or false) indicating if the ESP board connected successfully to a network.

bool initWiFi() {
  if(ssid=="" || ip==""){
    Serial.println("Undefined SSID or IP address.");
    return false;
  }

  WiFi.mode(WIFI_STA);
  localIP.fromString(ip.c_str());

  if (!WiFi.config(localIP, gateway, subnet)){
    Serial.println("STA Failed to configure");
    return false;
  }
  WiFi.begin(ssid.c_str(), pass.c_str());
  Serial.println("Connecting to WiFi...");

  unsigned long currentMillis = millis();
  previousMillis = currentMillis;

  while(WiFi.status() != WL_CONNECTED) {
    currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      Serial.println("Failed to connect.");
      return false;
    }
  }

  Serial.println(WiFi.localIP());
  return true;
}

First, it checks if the ssid and ip variables are empty. If they are, it won’t be able to connect to a network, so it returns false.

if(ssid=="" || ip==""){

If that’s not the case, we’ll try to connect to the network using the SSID and password saved in the ssid and pass variables and set the IP address.

WiFi.mode(WIFI_STA);
localIP.fromString(ip.c_str());

if (!WiFi.config(localIP, gateway, subnet)){
  Serial.println("STA Failed to configure");
  return false;
}
WiFi.begin(ssid.c_str(), pass.c_str());
Serial.println("Connecting to WiFi...");

If it cannot connect to Wi-Fi after 10 seconds (interval variable), it will return false.

unsigned long currentMillis = millis();
previousMillis = currentMillis;

while(WiFi.status() != WL_CONNECTED) {
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    Serial.println("Failed to connect.");
    return false;
  }

If none of the previous conditions are met, it means that the ESP successfully connected to the network in station mode (returns true).

return true;

setup()

In the setup(), start reading the files to get the previously saved SSID, password, IP address, and gateway.

ssid = readFile(LittleFS, ssidPath);
pass = readFile(LittleFS, passPath);
ip = readFile(LittleFS, ipPath);
gateway = readFile (LittleFS, gatewayPath);

If the ESP connects successfully in station mode (initWiFi() function returns true), we can set the commands to handle the web server requests (or any other code that requires the ESP to be connected to the internet):

if(initWiFi()) {
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(LittleFS, "/index.html", "text/html", false, processor);
  });
  server.serveStatic("/", LittleFS, "/");
    
  // Route to set GPIO state to HIGH
  server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request) {
    digitalWrite(ledPin, HIGH);
    request->send(LittleFS, "/index.html", "text/html", false, processor);
  });

  // Route to set GPIO state to LOW
  server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request) {
    digitalWrite(ledPin, LOW);
    request->send(LittleFS, "/index.html", "text/html", false, processor);
  });
  server.begin();
}

If that’s not the case, the initWiFi() function returns false. The ESP will set an access point:

else {
  // Connect to Wi-Fi network with SSID and password
  Serial.println("Setting AP (Access Point)");
  // NULL sets an open Access Point
  WiFi.softAP("ESP-WIFI-MANAGER", NULL);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP); 

To set an access point, we use the softAP() method and pass as arguments the name for the access point and the password. We want the access point to be open, so we set the password to NULL. You can add a password if you wish. To learn more about setting up an Access Point, read one of the following tutorials:

When you access the Access Point, it shows the web page to enter the network credentials in the form. So, the ESP must send the wifimanager.html file when it receives a request on the root / URL.

// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(LittleFS, "/wifimanager.html", "text/html");
});

We must also handle what happens when the form is submitted via an HTTP POST request. The following lines save the submitted values in the ssid, pass, and ip variables and save those variables in the corresponding files.

server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
  int params = request->params();
  for(int i=0;i<params;i++){
    AsyncWebParameter* p = request->getParam(i);
    if(p->isPost()){
      // HTTP POST ssid value
      if (p->name() == PARAM_INPUT_1) {
        ssid = p->value().c_str();
        Serial.print("SSID set to: ");
        Serial.println(ssid);
        // Write file to save value
        writeFile(LittleFS, ssidPath, ssid.c_str());
      }
      // HTTP POST pass value
      if (p->name() == PARAM_INPUT_2) {
        pass = p->value().c_str();
        Serial.print("Password set to: ");
        Serial.println(pass);
        // Write file to save value
        writeFile(LittleFS, passPath, pass.c_str());
      }
      // HTTP POST ip value
      if (p->name() == PARAM_INPUT_3) {
        ip = p->value().c_str();
        Serial.print("IP Address set to: ");
        Serial.println(ip);
        // Write file to save value
        writeFile(LittleFS, ipPath, ip.c_str());
      }
     // HTTP POST gateway value
      if (p->name() == PARAM_INPUT_4) {
        gateway = p->value().c_str();
        Serial.print("Gateway set to: ");
        Serial.println(gateway);
        // Write file to save value
        writeFile(LittleFS, gatewayPath, gateway.c_str());
      }
      //Serial.printf("POST[%s]: %s/n", p->name().c_str(), p->value().c_str());
    }
  }

After submitting the form, send a response with some text so that we know that the ESP received the form details:

request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip);

After three seconds, restart the ESP board with ESP.restart():

delay(3000);
ESP.restart();

That’s a quick summary of how the code works.

You can apply this idea to any of the other web server projects built with the ESPAsyncWebServer library.

Uploading Code and Files

Upload the files in the data folder to your ESP32. On the Arduino IDE, press [Ctrl] + [Shift] + [P] on Windows or [] + [Shift] + [P] on MacOS to open the command palette. Search for the Upload LittleFS to Pico/ESP8266/ESP32 command and click on it.

Upload LittleFS to Pico ESP8266 ESP32 Arduino IDE

If you don’t have this option is because you didn’t install the filesystem uploader plugin..

Important: make sure the Serial Monitor is closed before uploading to the filesystem. Otherwise, the upload will fail.

If you’re using VS Code with the PlatformIO extension, follow one of the next tutorials to learn how to upload files to your boards:

After successfully uploading the files, upload the code to your board.

Arduino IDE 2 Upload Button

Demonstration

After successfully uploading all files and sketch, you can open the Serial Monitor. If it is running the code for the first time, it will try to read the ssid.txt, pass.txt, and ip.txt files, and it won’t succeed because those files weren’t created yet. So, it will start an Access Point.

ESP-Wi-Fi Manager Sets Access Point Serial Monitor

On your computer or smartphone, go to your network settings and connect to the ESP-WIFI-MANAGER access point.

Connect to ESP32 ESP8266 Access Point Wi-Fi Manager

Then, open your browser and go to 192.168.4.1. The Wi-Fi Manager web page should open.

ESP32 ESP8266 Wi-Fi Manager Fields

Enter your network credentials: SSID and Password and an available IP address on your local network.

After that, you’ll be redirected to the following page:

ESP32 ESP8266 connected to station success Wi-Fi Manager

At the same time, the ESP should print something in the Serial Monitor indicating that the parameters you’ve inserted were successfully saved in the corresponding files.

After a few seconds, the ESP will restart. And if you’ve inserted the correct SSID and password, it will start in station mode:

ESP32 ESP8266 Connected Successfully to Wi-Fi Station

This time, open a browser on your local network and insert the ESP IP address. You should get access to the web page to control the outputs:

ESP32 ESP8266 Control Outputs Web Server

Wrapping Up

In this tutorial, you’ve learned how to set up a Wi-Fi Manager for your web server projects or for any other project that requires the ESP to be connected to the internet. With the Wi-Fi Manager, you can easily connect your ESP boards to different networks without the need to hard-code network credentials. You can built with the ESPAsyncWebServer library.

One of our readers created a more advanced version of this project with more fields and features, .

If you want to learn more about building web servers with the ESP32 and ESP8266 boards, make sure you take a look at our eBook:

We hope you’ve found this tutorial useful.

Thanks for reading.