Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE

In this guide, you’ll learn how to create an ESP32/ESP8266 web server with three input fields to pass values to your ESP using an HTML form. Then, you can use those values as variables in your code. We’ll be using the Arduino IDE to program the boards.

ESP32 ESP8266 Input Data on HTML Form Web Server using Arduino IDE

Project Overview

In this tutorial we’ll build an asynchronous web server using the ESPAsyncWebServer library that displays three input fields to pass values that you can use in your code to update variables.

We’ll take a look at two similar examples. The following figure illustrates how the first example works.

ESP32 ESP8266 HTML Form Input Data Project Overview

You have a web page with three input fields that you can access with any browser in your network. When you type a new value and press the “Submit” button, your ESP will update a variable with the new value.

If you ever needed to update a variable through an ESP web server, you should follow this project. With this method, you avoid hard coding variables because you can create an input field in a web page to update any variable with a new value. This can be specially useful to set threshold values, set SSID/password, change API Keys, etc…

Later, we’ll also show you how to save those variables permanently using LittleFS and how to access them. Here’s how this second example works.

ESP32 ESP8266 HTML Form Input Data Project Overview LittleFS

This web page allows you to enter three types of variables: String, Int and Float. Then, every time you submit a new value, that value is stored in a file in the LittleFS filesystem. This web page also contains a placeholder to show the current values.

Prerequisites

Make sure you check all the prerequisites in this section before continuing with the project in order to compile the code.

1. Install ESP32/ESP8266 Board in Arduino IDE

We’ll program the ESP32 and ESP8266 using Arduino IDE. So, you must have the ESP32 or ESP8266 add-on installed. Follow one of the next tutorials to install the ESP add-on:

2. Installing Libraries

To build the asynchronous web server, you need to install these libraries.

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

3. Parts Required

To follow this tutorial you just need an ESP32 or ESP8266 (read ESP32 vs ESP8266). There’s no circuit for this project.


1. ESP32/ESP8266 Handle Input Fields on Web Page with HTML Form

Copy the following code to the Arduino IDE. Then, type your network credentials (SSID and password) to make it work for you.

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-input-data-html-form/
  
  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>
#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);

// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const char* PARAM_INPUT_1 = "input1";
const char* PARAM_INPUT_2 = "input2";
const char* PARAM_INPUT_3 = "input3";

// HTML web page to handle 3 input fields (input1, input2, input3)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>ESP Input Form</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head><body>
  <form action="/get">
    input1: <input type="text" name="input1">
    <input type="submit" value="Submit">
  </form><br>
  <form action="/get">
    input2: <input type="text" name="input2">
    <input type="submit" value="Submit">
  </form><br>
  <form action="/get">
    input3: <input type="text" name="input3">
    <input type="submit" value="Submit">
  </form>
</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

  // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
    }
    // GET input2 value on <ESP_IP>/get?input2=<inputMessage>
    else if (request->hasParam(PARAM_INPUT_2)) {
      inputMessage = request->getParam(PARAM_INPUT_2)->value();
      inputParam = PARAM_INPUT_2;
    }
    // GET input3 value on <ESP_IP>/get?input3=<inputMessage>
    else if (request->hasParam(PARAM_INPUT_3)) {
      inputMessage = request->getParam(PARAM_INPUT_3)->value();
      inputParam = PARAM_INPUT_3;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                     + inputParam + ") with value: " + inputMessage +
                                     "<br><a href=\"/\">Return to Home Page</a>");
  });
  server.onNotFound(notFound);
  server.begin();
}

void loop() {
  
}

View raw code

How the code works

Let’s take a quick look at the code and see how it works.

Including libraries

First, include the necessary libraries. You include different libraries depending on the board you’re using. If you’re using an ESP32, the code loads the following libraries:

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

If you’re using an ESP8266, you include these libraries:

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>

Network credentials

Don’t forget to insert your network credentials in the following variables, so that the ESP32 or ESP8266 can connect to your network.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

HTML Forms and Input Fields

First, let’s take a look at the HTML that we need to display the input fields.

In our example, we display three input fields and each field has a “Submit” button. When the user enters data and presses the “Submit” button, that value is sent to the ESP and updates the variable.

For that, create three forms:

<form action="/get">
  input1: <input type="text" name="input1">
  <input type="submit" value="Submit">
</form><br>
<form action="/get">
  input2: <input type="text" name="input2">
  <input type="submit" value="Submit">
</form><br>
<form action="/get">
  input3: <input type="text" name="input3">
  <input type="submit" value="Submit">
</form>

In HTML, the <form> tag is used to create an HTML form for user input. In our case, the form should contain an input field and a submit button.

ESP32 ESP8266 Web Server with Input Fields

Let’s take a look at the first form to see how it works (the other forms work in a similar way).

<form action="/get">
  input1: <input type="text" name="input1">
  <input type="submit" value="Submit">
</form>

The action attribute specifies where to send the data inserted on the form after pressing submit. In this case, it makes an HTTP GET request to /get?input1=value. The value refers to the text you enter in the input field.

Then, we define two input fields: one text field and one submit button.

The following line defines a one line text input field.

input1: <input type="text" name="input1">

The type attribute specifies we want a text input field, and the name attribute specifies the name of the input element.

The next line defines a button for submitting the HTML form data.

<input type="submit" value="Submit">

In this case, the type attribute specifies you want a submit button, and the value specifies the text on the button.

Connect to your network

In the setup(), connect to your local network.

Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
  Serial.println("WiFi Failed!");
  return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());

Handle HTTP GET requests

Then, you need to handle the HTTP GET requests.

When, you access the route URL, you send the HTML page to the client. In this case, the HTML text is saved on the index_html variable.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html);
});

Then, you need to handle what happens when you receive a request on the /get routes.

server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {

We create two variables: inputMessage and inputParam to save the input value and the input field.

Then, we need to check whether the HTTP GET request contains the input1, input2, or input3 parameters. These are saved on the PARAM_INPUT_1, PARAM_INPUT_2 and PARAM_INPUT_3 variables.

If the request contains the PARAM_INPUT_1 (i.e. input1), we set the inputMessage to the value inserted in the input1 field.

inputMessage = request->getParam(PARAM_INPUT_1)->value();

Now you have the value you’ve just inserted on the first form saved on the inputMessage variable.

Then, set the inputParam variable to PARAM_INPUT_1 so that we know where the input value comes from.

When you submit the form, you get a message saying the value you’ve inserted and in which field. We also display a link to get back to the route URL (Home Page).

request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                + inputParam + ") with value: " + inputMessage +
                                "<br><a href=\"/\">Return to Home Page</a>");
ESP32 ESP8266 HTML Form Input Data HTTP GET Request

If you make a request on an invalid URL, we call the notFound() function, defined at the beginning of the sketch.

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

Finally, start the server to handle clients.

server.begin();

Demonstration

After uploading code to your board, open your Arduino IDE Serial Monitor at a baud rate of 115200 to find the ESP IP address.

ESP32 ESP8266 IP Address Arduino IDE Serial Monitor

Then, open your browser and type the IP address. This web page should load:

ESP32 ESP8266 HTML Form 3 Input Fields and Save data to ESP using Arduino IDE

For example, type 123456 on input1 field, then press the “Submit” button. A new page should load saying that value 123456 was sent to your ESP:

ESP32 ESP8266 HTML Form Input Data demonstration

2. ESP32/ESP8266 Save Input Fields to LittleFS

Now, let’s proceed to the second example. This example saves the data inserted on the input fields permanently on LittleFS. We’ve also added placeholders on the web page to show the current values.

Copy the following sketch to Arduino IDE. Then, before uploading type your network credentials (SSID and password).

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-input-data-html-form/
  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>
#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
  #include <LittleFS.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
  #include <Hash.h>
  #include <LittleFS.h>
#endif
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);

// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const char* PARAM_STRING = "inputString";
const char* PARAM_INT = "inputInt";
const char* PARAM_FLOAT = "inputFloat";

// HTML web page to handle 3 input fields (inputString, inputInt, inputFloat)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>ESP Input Form</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script>
    function submitMessage() {
      alert("Saved value to ESP LittleFS");
      setTimeout(function(){ document.location.reload(false); }, 500);   
    }
  </script></head><body>
  <form action="/get" target="hidden-form">
    inputString (current value %inputString%): <input type="text" name="inputString">
    <input type="submit" value="Submit" onclick="submitMessage()">
  </form><br>
  <form action="/get" target="hidden-form">
    inputInt (current value %inputInt%): <input type="number " name="inputInt">
    <input type="submit" value="Submit" onclick="submitMessage()">
  </form><br>
  <form action="/get" target="hidden-form">
    inputFloat (current value %inputFloat%): <input type="number " name="inputFloat">
    <input type="submit" value="Submit" onclick="submitMessage()">
  </form>
  <iframe style="display:none" name="hidden-form"></iframe>
</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);
  File file = fs.open(path, "r");
  if(!file || file.isDirectory()){
    Serial.println("- empty file or failed to open file");
    return String();
  }
  Serial.println("- read from file:");
  String fileContent;
  while(file.available()){
    fileContent+=String((char)file.read());
  }
  file.close();
  Serial.println(fileContent);
  return fileContent;
}

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\r\n", path);
  File file = fs.open(path, "w");
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- write failed");
  }
  file.close();
}

// Replaces placeholder with stored values
String processor(const String& var){
  //Serial.println(var);
  if(var == "inputString"){
    return readFile(LittleFS, "/inputString.txt");
  }
  else if(var == "inputInt"){
    return readFile(LittleFS, "/inputInt.txt");
  }
  else if(var == "inputFloat"){
    return readFile(LittleFS, "/inputFloat.txt");
  }
  return String();
}

void setup() {
  Serial.begin(115200);
  // Initialize LittleFS
  #ifdef ESP32
    if(!LittleFS.begin(true)){
      Serial.println("An Error has occurred while mounting LittleFS");
      return;
    }
  #else
    if(!LittleFS.begin()){
      Serial.println("An Error has occurred while mounting LittleFS");
      return;
    }
  #endif

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/get?inputString=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    // GET inputString value on <ESP_IP>/get?inputString=<inputMessage>
    if (request->hasParam(PARAM_STRING)) {
      inputMessage = request->getParam(PARAM_STRING)->value();
      writeFile(LittleFS, "/inputString.txt", inputMessage.c_str());
    }
    // GET inputInt value on <ESP_IP>/get?inputInt=<inputMessage>
    else if (request->hasParam(PARAM_INT)) {
      inputMessage = request->getParam(PARAM_INT)->value();
      writeFile(LittleFS, "/inputInt.txt", inputMessage.c_str());
    }
    // GET inputFloat value on <ESP_IP>/get?inputFloat=<inputMessage>
    else if (request->hasParam(PARAM_FLOAT)) {
      inputMessage = request->getParam(PARAM_FLOAT)->value();
      writeFile(LittleFS, "/inputFloat.txt", inputMessage.c_str());
    }
    else {
      inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/text", inputMessage);
  });
  server.onNotFound(notFound);
  server.begin();
}

void loop() {
  // To access your stored values on inputString, inputInt, inputFloat
  String yourInputString = readFile(LittleFS, "/inputString.txt");
  Serial.print("*** Your inputString: ");
  Serial.println(yourInputString);
  
  int yourInputInt = readFile(LittleFS, "/inputInt.txt").toInt();
  Serial.print("*** Your inputInt: ");
  Serial.println(yourInputInt);
  
  float yourInputFloat = readFile(LittleFS, "/inputFloat.txt").toFloat();
  Serial.print("*** Your inputFloat: ");
  Serial.println(yourInputFloat);
  delay(5000);
}

View raw code

How the Code Works

This code is very similar with the previous one with a few tweaks. Let’s take a quick look at it and see how it works.

Including libraries

The code loads the following libraries if you’re using the ESP32. You need to load the LittleFS library to write to the LittleFS filesystem.

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <LittleFS.h>

If you’re using an ESP8266, you need to include the following libraries instead.

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsyncTCP.h>
#include <Hash.h>
#include <LittleFS.h>

HTML Form

In this example, when you submit the values, a window opens saying the value was saved to LittleFS, instead of being redirected to another page as in the previous example.

For that, we need to a add a JavaScript function, in this case it’s called submitMessage() that pops an alert message saying the value was saved to LittleFS. After that pop up, it reloads the web page so that it displays the current values.

<script>
  function submitMessage() {
    alert("Saved value to ESP LittleFS");
    setTimeout(function(){ document.location.reload(false); }, 500);
  }
</script>

The forms are also a bit different from the previous ones. Here’s the form for the first input.

<form action="/get" target="hidden-form">
  inputString (current value %inputString%): <input type="text" name="inputString">
  <input type="submit" value="Submit" onclick="submitMessage()">
</form>

In this case, the target attribute and an <iframe> are used so that you remain on the same page after submitting the form.

The name that shows up for the input field contains a placeholder %inputString% that will then be replaced by the current value of the inputString variable.

The onclick=”submitMessage()” calls the submitMessage() JavaScript function after clicking the “Submit” button.

Read and Write to LittleFS

Then, we have some functions to read and write from LittleFS.

The readFile() reads the content from a file:

String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);
  File file = fs.open(path, "r");
  if(!file || file.isDirectory()){
    Serial.println("- empty file or failed to open file");
    return String();
  }
  Serial.println("- read from file:");
  String fileContent;
  while(file.available()){
    fileContent+=String((char)file.read());
  }
  Serial.println(fileContent);
  return fileContent;

The writeFile() writes content to a file:

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\r\n", path);
  File file = fs.open(path, "w");
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- write failed");
  }
}

processor()

The processor() is responsible for searching for placeholders in the HTML text and replacing them with actual values saved on LittleFS.

String processor(const String& var){
  //Serial.println(var);
  if(var == "inputString"){
    return readFile(LittleFS, "/inputString.txt");
  }
  else if(var == "inputInt"){
    return readFile(LittleFS, "/inputInt.txt");
  }
  else if(var == "inputFloat"){
    return readFile(LittleFS, "/inputFloat.txt");
  }
  return String();
}

Handle HTTP GET requests

Handling the HTTP GET requests works the same way as in the previous example, but this time we save the variables on LittleFS.

For example, for the inputString field:

if (request->hasParam(PARAM_STRING)) {
  inputMessage = request->getParam(PARAM_STRING)->value();
  writeFile(LittleFS, "/inputString.txt", inputMessage.c_str());
}

When the request contains inputString (i.e. PARAM_STRING), we set the inputMessage variable to the value submitted on the inputString form.

inputMessage = request->getParam(PARAM_STRING)->value();

Then, save that value to LittleFS.

writeFile(LittleFS, "/inputString.txt", inputMessage.c_str());

A similar process happens for the other forms.

Accessing the variables

In the loop(), we demonstrate how you can access the variables.

For example, create a String variable called yourInputString that reads the content of the inputString.txt file on LittleFS.

String yourInputString = readFile(LittleFS, "/inputString.txt");

Then, print that variable in the Serial Monitor.

Serial.println(yourInputString);

Demonstration

After uploading code to your board, open your Arduino IDE Serial Monitor at a baud rate of 115200 to find the ESP IP address.

ESP32 ESP8266 IP Address Arduino IDE Serial Monitor

Open your browser and type the IP address. A similar web page should load (at first your current values will be blank).

ESP32 ESP8266 HTML Form 3 Input Fields and Save data to ESP SPIFFS files using Arduino IDE

Type a String in the first input field and press “Submit”, repeat the same process for the Int and Float input values. Every time you press the Submit button for a field, you’ll see an alert message like this:

ESP32 ESP8266 HTML Form Input Data demonstration alert message web page reload

Press the “OK” button to reload the web page and see the current values updated.

If you have your Arduino IDE Serial Monitor open, you’ll see that the stored values are being printed over and over again:

ESP32 ESP8266 Input Fields HTML Form Demonstration Arduino IDE Serial Monitor

For a final project, you can delete all those lines in your loop() that print all stored values every 5 seconds, we just left them on purpose for debugging.

Wrapping Up

In this tutorial you’ve learned how to handle input fields in a web page to update the ESP variable values. You can modify this project to set thresholds, change API Key values, set a PWM value, change a timer, set SSID/password, etc.

Here’s other projects that you might like:

Learn more about the ESP32 with our best-selling course:

Thank you for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

187 thoughts on “Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE”

  1. Hi,
    Can we upload the HTML script into SPIFFS? and what’s the difference between uploading html file to SPIFFS and including it inside the code?

    Reply
    • Hi.
      Yes, you can upload the HTLM script to SPIFFS if you want.
      The main difference is how you organize your files.
      If want to have the HTML in a separated file so that it is easier to modify later on, uploading to SPIFFS is a better idea.
      Regards,
      Sara

      Reply
      • Hi Sara,
        I’m making a guess that uploading HTML scripts could save some RAM as compared to including it inside the code. Am I correct?

        Reply
      • Can we use above code for wifi access point network, i tried but failed why it is connecting and responding to hotspot only.
        If you possible can please upload a code for wifi access point data (updating variables) tranfer to esp32 advance thank you

        Reply
          • Thank you very much for your reply
            I know and i watch acesspoint code previously and your tutorial as well,My question is how to “pass variables and update variables” through accesspoint network What are the modification did i change to below code .

            #include <WiFi.h>
            #include <WiFiClient.h>
            #include <WiFiAP.h>

            #define LED_BUILTIN 2 // Set the GPIO pin where you connected your test LED or comment this line out if your dev board has a built-in LED

            // Set these to your desired credentials.
            const char *ssid = “yourAP”;
            const char *password = “yourPassword”;

            WiFiServer server(80);

            void setup() {
            pinMode(LED_BUILTIN, OUTPUT);

            Serial.begin(115200);
            Serial.println();
            Serial.println(“Configuring access point…”);

            // You can remove the password parameter if you want the AP to be open.
            WiFi.softAP(ssid, password);
            IPAddress myIP = WiFi.softAPIP();
            Serial.print(“AP IP address: “);
            Serial.println(myIP);
            server.begin();

            Serial.println(“Server started”);
            }

            void loop() {
            WiFiClient client = server.available(); // listen for incoming clients

            if (client) { // if you get a client,
            Serial.println(“New Client.”); // print a message out the serial port
            String currentLine = “”; // make a String to hold incoming data from the client
            while (client.connected()) { // loop while the client’s connected
            if (client.available()) { // if there’s bytes to read from the client,
            char c = client.read(); // read a byte, then
            Serial.write(c); // print it out the serial monitor
            if (c == ‘\n’) { // if the byte is a newline character

            // if the current line is blank, you got two newline characters in a row.
            // that's the end of the client HTTP request, so send a response:
            if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> to turn ON the LED.<br>");
            client.print("Click <a href=\"/L\">here</a> to turn OFF the LED.<br>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
            } else { // if you got a newline, then clear currentLine:
            currentLine = "";
            }
            } else if (c != '\r') { // if you got anything else but a carriage return character,
            currentLine += c; // add it to the end of the currentLine
            }

            // Check to see if the client request was "GET /H" or "GET /L":
            if (currentLine.endsWith("GET /H")) {
            digitalWrite(LED_BUILTIN, HIGH); // GET /H turns the LED on
            }
            if (currentLine.endsWith("GET /L")) {
            digitalWrite(LED_BUILTIN, LOW); // GET /L turns the LED off
            }
            }
            }
            // close the connection:
            client.stop();
            Serial.println("Client Disconnected.");

            }
            }

            How do i create a text box and pass parmeters and update variables… in above code all those stuff, please kindly give update to me thank you very much in advance . I hope you give your best effort.

        • WiFi.mode(WIFI_AP_STA);
          delay(100); // Recommended delay
          WiFi.softAP(ssid, password);

          //WiFi.mode(WIFI_STA);
          //WiFi.begin(ssid, password);
          // if (WiFi.waitForConnectResult() != WL_CONNECTED) {
          // Serial.println(“WiFi Failed!”);
          // return;
          // }
          Serial.println();
          Serial.print(“IP Address: “);
          Serial.println(WiFi.localIP());

          Reply
  2. Waouw, that’s great !
    Very useful, and very well explained.
    I’m looking forward to have some time to my own project based on your tutorial 😉
    Thank you very much !

    Reply
  3. Keep a default value
    perform a reasonableness test on a ‘html’ value, say for 0 to 100 for percentage values, or 0 to 255 for PWM values

    Reply
  4. Hi, I am using a Wemos D1 Mini (8266). When I try to compile the SPIFFS version I get the following error msg:
    class fs::File’ has no member named ‘isDirectory

    Any suggestions?

    Reply
  5. Hi,

    Thanks for the excellent tutorial.

    I though wouldn’ recommend to use the GET method to update anything and use a POST instead. See also: w3.org/2001/tag/doc/whenToUseGet.html#checklist

    Reply
    • Thanks for the suggestion. However, in this case the connection is not encrypted, so it will not make any difference (for security).
      You can change to HTTP POST with this simple change in your code (change the 2nd argument to HTTP_POST ):

      server.on(“/get”, HTTP_POST, [](AsyncWebServerRequest *request){

      In the HTML form tag add: method=”post” as an attribute

      That’s it, now it’s an HTTP post request.
      Thanks!

      Reply
  6. As always another fantastic project tutorial with excellent detail, many thanks Rui. Will you be revising this project to work with your previous project “Visualize Your Sensor Readings from Anywhere in the World (ESP32/ESP8266 + MySQL + PHP)” sometime in the future? I have invested in a BlueHost website and now have good graphical results of my IAQ sensors. To be able to communicate values back to the ESP32 would be great.

    Reply
    • Hi Richard.
      Thank you for the suggestion.
      Yes, we’ll probably make something combining these tutorials and other related subjects in the future. We’re having great feedback about these projects that use hosting account and domain name.
      But I’m not sure when those projects will be released.

      Congratulations for your website. It looks great! 😀

      Regards,
      Sara

      Reply
      • Hi Sara,
        Thanks for your reply and comment about my website. It took me a while to learn how to get and display the last values in the sql database but as you see I got there in the end!

        It sounds like my suggested tutorial isn’t going to happen in the near future, any clues or pointers as to how I can do it would be appreciated.

        Once again, thank you both for the well documented tutorials. At the age of 65 I’m still learning and your projects are the best, you have taught me so much.

        Reply
  7. Hi, This is a great project and very timely as I am building your water meter project but am using different sensors with different values for their respective pulse/liter value and would like to be able to change this via a web interface.

    Unfortunately when I try to compile your raw code I get the following error. Yes I have enabled SPIFFS (1M SPIFFS):

    ‘class fs::File’ has no member named ‘isDirectory’

    Any thoughts would be appreciated.
    Thanks.

    Reply
    • Please update your board definitions by going into the boards manager and your problem will get solved i was suffering from the exact same issue and this solved my problem .
      Thanks

      Reply
  8. Hello Rui.
    I tried to adjust the first sketch.
    I would like to have the data on an OLED or LCD screen.
    But I don’t succeed. All libs. are present for this.
    Things are still going well in the setup routine.
    Where can I place the routine that puts the data on the OLED.
    The program now always starts.
    On the oled I get nothing to see after the text (start).
    I think I am confusing sketch, but I don’t know why.
    Thank you for your fantastic work.
    This old man (73) is learning a lot from you and I enjoy it.
    Greetings Bert heideveld (the Netherlands).

    Reply
    • Hi Bert.
      Are you writing the OLED routine on the loop()?
      Note that you need to call display.display(); for the changes to make effect (every time you want to write something new in the OLED).
      What lines of code are you using to display text in the OLED?
      Regards,
      Sara

      Reply
      • Hello, and thanks for your quick response.
        I used this routine in the loop.

           display.clearDisplay ();
           display.display ();
           display.setCursor (32, 16);
           display.println (inputMessage);
           display.display ();
           delay (2000);

        This routine works “Text” in the setup.
        So the libs. etc etc are okay.

        If I put the above routine in the loop, the Wemos D1 keeps
        logging out and logging in again after text input in the text
        box that can be seen in the browser.
        If the text could go to an OLED or LCD screen you could
        work without a PC and monitor.
        I can really use that.
        Thank you for your beautiful work.

        Greetings Bert

        Reply
        • Hi Bert.
          I’ve tested your routine and it is working fine for me (I’ve tested in an ESP32 but it should work fine in an ESP8266 too.
          Did you set the text size and color?
          display.setTextSize(1);
          display.setTextColor(WHITE);

          You can see my code here: pastebin.com/h2g2z1vu

          Regards,
          Sara

          Reply
          • Hello Sara.

            Yes I missed these two rules.
            display.setTextSize (1);
            display.setTextColor (WHITE);
            I was under the assumption that I only had to enter it once in the sketch.
            Now it works fine and we are already using it.
            I also make a version with an LCD screen with running text from right to left. Then you can send a longer message.
            A short tone then indicates when there is a new message.
            Do you also have a sketch for a clock that takes the time off the internet for the Eps32?
            Until now, thank you very much and good luck with your beautiful work.
            It is inspiring.
            Greetings Bert in the Netherlands.

          • Just a little test give this error.

            sketch_sep16a:58:30: error: ‘class NTPClient’ has no member named ‘getFormattedDate’

            formattedDate = timeClient.getFormattedDate();

            Sorry dont no wat it means.

          • Hello Sarah.
            I had that lib. already installed via IDE. But I did it again and now the sketch works.
            Thanks for your patience .
            Greetings Bert

  9. Hey so i wanted to know that how do i host this web server like my esp8266 creates a wifi of its own named “xyz” i connect to it . Type 192.168.4.1 and input the data and store the value into spiffs . Basically i want to make it standalone so i dont require any other router for it to connect to …

    Reply
  10. Hello, great tutorial, it helped me a lot. I’m trying to make a captive portal with your second example, but I can’t. Did you have any reason not to do the second example with captive portal? Do you know if it really won’t work for some reason I don’t know?

    Reply
  11. Hi guys,

    Thanks a lot for this detailed tutorial.
    I am trying to re-use part of it but I am getting an error on ‘server.on’ function. It states the class WiFiServer has no member named ‘on’.
    Am I missing anything? I have included all the libraries you mentioned.

    Many thanks.

    Reply
    • Hi Matos.
      That seems to be an issue with the libraries.
      How did you install them?
      And which board are you using? You need to install different libraries depending if you’re using an ESP32 or ESP8266.
      Regards,
      Sara

      Reply
  12. Hi,
    is it possible to use the variable web transfer in parallel with ESP-Now (used to receive other data on the same ESP8266)?
    Thanks!
    Martin

    Reply
  13. Hello Sarah and Rui!
    I’m probably bit OT, but i hope to get an answer.
    I’ve used this sketch for some sensors reading with the possibility to fill in the webpage, some user/pwd parameters . Unfortunately i’ve found out that to let the params being applied, i need to reset the ESP.
    I had the idea then to add a “button” in the webpage to “call” the ESP.restart() function of the ESP: i’ve tried lot of way and read all over the internet , but i had no lucky…. could you give me some help?
    Thanks in advance!
    Nicola

    Reply
  14. Hello Sara,

    Will this code work for an arduino mega with wifi/ethernet shield with some modification?
    If so can you help regarding what parts of the code need to be changed.

    Reply
  15. First, you guys are awesome. I love your projects and you explain things so well. I encourage everyone here to help support your efforts. Anyone just getting started with Arduino or ESPxx will do well to follow this team and purchase their courses.

    I am using your example in this project on an automated blinds project to store positional information of the blinds. Each blind (currently 3) has it’s own ESP8266 so each would have it’s own IP address and EEPROM where i store the data. Using your code I can collect the data and store it but all three of the web pages look identical and I would like to be able to have a header that uniquely identifies the blind. All of the blinds use the same Arduino code and I identify which blind using the MAC address.

    What I would like to know is how I can use a variable in the HTML web page so that it reflects which blind I am controlling. I tried adding just a variable name in the code but on the page it just showed the variable name, not the value of the variable.

    Is this possible?
    Thanks,
    Bruce

    Reply
  16. This is a great resource.
    I would like to create and authenticate ID and password using this material, but I do not know how to implement it.

    Reply
  17. Hi,
    Thank you for this tutorial. It is very close to what I have dreamed. But I wanted to submit six parameters with one button and then write those parameters in order as a file to SPIFFS. Is it much more complicated?

    Reply
  18. Hi

    Thank you for your great tutorials. I don’t have any prior web development experience, but hanks to you I have been able to build a web server with a combination of DS18B20 thermostat, timed/pulsed button and relay control for controlling an aquarium. I was even able to make it a multi page web server so that I can use one page for settings and form inputs and the other page as a dashboard to view the status of all my sensors and relays.

    I have one question regarding this specific tutorial:
    Each time that I press the submit button, the text file is submitted to the ESP8266 as it should, but this also triggers a download so the text file is downloaded to my computer/phone as well. Is there any way that I can prevent the file from downloading to my computer too?

    Thanks again.

    Reply
    • Hi, is it possible for you to share the code which allow this to happen? I am trying to fetch a file from my SD card after typing the file name in the input box. I have tried several combination but it still open the file in the browser instead of downloading it. Thank you

      Reply
  19. Hello Sara and Ruis,

    Thank you for this great tutorial. As always it works ‘out of the box’ !

    When I submit a change (string, int or float), I receive a download window asking if I want to download a ‘get’ file containing the text submitted. I guess this is the same issue as Egon above.

    I am working on an ESP32, Firefox and this doesn’t happen with Android.

    How can I fix this ?

    Thank you,

    JM

    Reply
    • Hi.
      I think it might be an issue with the browser.
      Try it with google chrome and see if you get the same results.
      Regards,
      Sara

      Reply
      • Dear Sara,

        effectively this doesn’t happen on Chrome. I will look into the Firefox settings.

        Thank you for your support !
        Have a nice day,

        JM

        Reply
  20. Hi Thanks for a great site and awesome projects of which I have built several. I am currently using an ESP12E and getting an error about “\Arduino\libraries\AsyncTCP\src/AsyncTCP.h:26:23: fatal error: sdkconfig.h: No such file or directory”. I have googled without success, any ideas?

    Thanks again!

    Reply
    • Hi Neil.
      I think I got that issue some time ago.
      I didn’t remember how I solved it.
      I think I needed to delete all installations and install everything from the start.
      Alternatively, you can try update your Boards installation and see if that solves the problem.
      Regards,
      Sara

      Reply
  21. Hi to The Santos 🙂

    You guys are amazing – 2 weeks ago I got an ESP32 Dev Board in my hand and knew nothing. Reading and reading your tutorials have been THE greatest inspiration on my steeeep learning curve 🙂 Thank you so far 🙂 !

    Though, I do have a question; I used the second example for my project, but I can’t seem to save an email address? I’ve tried to change the input type=”text” to input type=”email”, still my ESP32 panics and reboot.

    What am I missing? I assume this is due to the characters @ and .

    Please please help me resolve this 🙂

    Reply
    • Hi.
      In your code, what do you do with the email address?
      Are you saving it as a String variable? How does your request looks like?
      Regards,
      Sara

      Reply
      • Hi Sara, quite embarrassed here – I found the mistake last night 🙂 I had forgotten to change one of the PARAM’s in the IF statement causing it to panic.

        Though, I do have an issue with CSS with your example. The page only result in a white page, not loading anything. The code works great inside a W3C simulator. Could you enlighten why I have issues with it on the ESP32?

        Title

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

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

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

        input[type=submit] {

        background-color: #007bff;
        color: white;
        padding: 14px 20px;
        margin: 8px 0;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        }

        input[type=submit]:hover {
        background-color: #009bff;
        }

        div {
        border-radius: 5px;
        background-color: #fff;
        padding: 20px;
        }

        div.center {
        text-align: center;
        }

        SSID (nåværende: %ap_ssid%)

        Passord (nåværende: %ap_pwd%)

        Epost (nåværende: %email%)

        ZZ (nåværende: %amount%)

        Velg ml fra listen
        1
        2
        3

        Reply
  22. Hi Sara & Rui,
    Thanks for these great tutorials

    Your code is working fine till yesterday for Access Point i have test everything and design webpages every things for my design project … but now my esp32 not going into AP mode while the same code is working perfect as before …i tried change the esp32 as well but same issue exits ….(not Found show in browser) i just want to track the error .
    Do you have any idea what is the problem ?

    Thanks in advance

    Reply
  23. Hi Sara and Rui,
    Thanks for your tutorials.
    I am a newbie in html.
    My task is to send to esp data from html page.
    I am wondering how can we update all 3 or more inputs with just one submit button.
    Thank you

    Reply
  24. Hi guys, thanks for the useful tutorials, I have just buyed your Ebooks and I’m very happy to support your activities.

    Currently, I’m trying to integrate different tutorials from your website, to obtain a more complex html page. What I want to do is to have some real-time sensors plots and some buttons/sliders/textbox to control my home automation system.

    Considering this tutorial, I would like to know if there is a way to sent data from the client to the server, avoiding the page refresh (the real-time plot are refreshed everytime).

    Thanks in advance!

    Reply
    • Hi Vito.
      Yes, you can use a websocket connection to send data from the client to the server without having to refresh the web page.
      As you are one of our students, if you need closer assistance, I recommend that you post your questions and doubts in the RNTLAB forum. I can follow closer there.
      Here’s the link: https://rntlab.com/forum/
      Regards,
      Sara

      Reply
  25. Sara and Rui,
    Great work! Your tutorials are not-too-short, not-too-long, and just right – and excellent too. And the forum Q&A’s are rich with supplemental info.
    One question: I’ve noticed that the “server.on” methods used in both examples above are in the Setup() loop. So does that mean that the webpage is constructed once and sent to a browser? That would mean any button action update is manifest in the HTML code that resides on the browser? But on the ESP, I’m guessing that the “.on” method operates like an interrupt to trigger the file reading/writing.
    Thanks,
    Craig

    Reply
    • Hi.
      Yes, the .on method is like an interrupt.When it receives a request on a specific path, it tirggers something.
      Regards,
      Sara

      Reply
  26. Hi,

    I bought your course and within few days I was able master a lot. Thank you very much. I am starting ESP-01 in STA and AP mode. I used above example store STA mode SSID, PSK and Static IP configuration and modify via web interface. On boot it will load the values from the file if not null rather than hardcoded.
    I am doing it following way but it does not work. Please advice. Thank you
    IPAddress local_IP(192, 168, 200, 99);
    String Sip = processor(“input_ip”);
    Serial.print(“SIP “);
    Serial.println(Sip);
    if(Sip != NULL){
    local_IP.fromString(Sip);
    }

    Reply
    • Hi Johan.
      Since you are a RNT costumer, post your issue in the RNTLAB forum: https://rntlab.com/forum/
      It is easier for me to follow your question there.
      Additionally, can you provide more details?
      Otherwise, it is very difficult to find out what might be wrong.
      Regards,
      Sara

      Reply
  27. This is, what I always looked for! Thogether with the other tutorials on SPIFFS installation, etc.

    Your tutorials are so wonderful. Finally someone like me understands realy how these things work.

    I have achieved to splitt my html, css and javascript codes; – together with some data files (*.txt) into the SPIFFS and have all linked together. Now I can save data into the SPIFFS *.txt files and in case I have to restart the ESPs – no problem. They take the data from the SPIFFS. This is much more comfort than with the EEPROM.

    As I am originally coming from the webdesign side (html, etc.) I could now create nice layouts into the browsers of the ESP created clients, which is now much more comfort for the user and for me when changing something.

    You are just genious!

    Your work is great. Thanks a lot all!

    Konrad

    Reply
  28. Hi Sara and Thanos;

    The link of Sara goes into the right way. Your problem is very likely, that you have filled in only the first field (here input1). As you probably have not filled in the other fields, they have been overwritten by “” (nothing); – therefore no text/number.

    input1: <input type=”text” name=”input1″
    input2: <input type=”text” name=”input2″
    etc.

    But You have to
    a.) either fill in every time in all fields something and confirm with the one submit button
    b.) or you give the relevant tag additionally a value, containing the processor, which is then visible in the field, like

    input1: <input type=”text” name=”input1″ value=”%input1%”
    etc.

    and confirm with the one submit button

    Hope this helps.

    Konrad

    Reply
  29. Hi,
    First of all, Thank you very much for such a wonderful tutorial.

    Please guide to achieve the Data Input using ESP as Access Point.

    Thanks and Regards,
    Anand Raj Gupta

    Reply
  30. Hi!
    It looks like this will do exactly what I’m looking for except I have a few issues:
    1) Where / how in the code do I modify using LittleFS.h rather than SPIFFS, which is now deprecated? I’m using an ESP8266.
    I’m also trying to migrate from Arduino IDE to platformio. Several things are unclear when trying to load and what to load to flash. Please clarify if you would.

    Thank you

    Reply
  31. Hi
    thanks for this tutorial and sorry for English
    i have a question
    is there a way we could input data on HTML form with esp while we are using esp as access point?
    i’ve seen the AP tutorial but i didn’t get the answer .
    thank you
    Fati

    Reply
  32. Hello, first great tutorial. Love your posts.
    I was wondering if the ESP IP address for web server is always the same?
    So it can be written down to housing of ESP32 module, that anyone on their network can reach the web server to put own values.
    Like in ESP32 WiFiManager library, the IP address is always 192.168.4.1
    How is here, how can someone know IP address if can not look on COM port?

    Mark

    Reply
  33. Hey, Thanks for the tutorial. Gave me a good start to using the webserver.
    Particular to this example, how would I go about filling the input fields with pre-stored/current values (in preferences/spiffs, etc.) This is so that the user does not need to fill in all the values each time the page loads.
    Thanks a bunch!

    Reply
  34. How can I proceed if i save the html page in the spiffs and want to write and read it in the input field and save it in an ESP RAM variable?
    Taking an example from the random nerd SPIFFS WEB SERVER in the following code it is possible to write a value but it was not possible to read the value on the html page, I added an input field. I noticed that there is a variable String that converts to a pointer.

    String processor(const String& var){
    .
    .
    .
    server.on(“/”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, “/index.html”, String(), false, processor);
    });

    Reply
  35. The example works only with a field. Is there a simple way to submit a complex form (more fields like text, checkbox, radio, …) to esp32 and load value from esp32?
    I use a webserver and I’d like use this for save and load sketch settings: 1) show settings by a html form (saved on file by LittleFS); 2) submit the form to esp32, save new data to file (by LittleFS) and use the new data to chenge current esp32 sketch settings.
    I like use file to save/load data to have settings data on next boot.

    Reply
  36. Hi,

    Guys you are doing a great job. Because of you guys, I have learned a lot.
    Can you tell me how to get the submiiting values into variables of my code, instead of saving them in SPIFFS.

    Thank you

    Reply
    • Hi.
      In this example, the values are being saved on the inputMessage variable.
      You can create a different variable for each request to save the different values.
      Regards,
      Sara

      Reply
  37. Hi Sara,
    I was hoping you could do an example (or maybe you already have and I cant find it), on constantly updating variables on a web page. I have not found any that handle more than one and most rely on some form of input to update. It would be nice to have a subroutine to call for the variables.

    another thing that is cooking my noodle is why your code is all in the setup function and not in loop? How does this work as I thought the setup routine only runs once?

    Reply
  38. Olá, quando eu crio um arquivo com spiffs ele salva normalmente na flash, porém quando eu faço upload dos arquivos pelo firmware data ele apaga os arquivos que foram criados pelo código diretamente? Tem como resolver isso?

    Att

    Reply
  39. Hello Rui and Sara.
    I can’t find a way to receive and process the selection when adding option button and checkbox cases in this tutorial form in addition to the displayed text boxes.
    As I show below.

    Date select:
    1492
    1789
    1917

    Interests:
    HTML5
    Cars
    Sports
    Videogame
    <input type = "submit" value = "Send selection"

    Thanks.

    Reply
  40. Have you found a way to enter the wifi ssid and password from a web link so they don’t have to be hard coded in the sketch?
    This means you would have to connect to the board a different way than the ssid and password you want. For example maybe using the guest wifi or something.

    Thanks, Steve

    Reply
  41. Hi Rui& Sara, I have tested it on ESP32, It works with SPIFFS and I select the “Default 1.5M SPIFFS”. It is a great tutorial and help me a lot in beginning of learning stage !!!

    Reply
  42. Hi there! I’m having an issue trying to send the extracted data from the page. I’m trying to send the data using SoftwareSerial and the ESP8266 doesn’t connect to Wi-Fi, the serial monitor shows me “{d$œ¾ŽŒdà|Œdäb|Žƒì’r“cŒp„òNn¾looœÂbbpìŽdrlrlpûoà‚lŒœboã|$ìàŽp„òNnîlŒ$2oNlNrŽ“›o”Ülr’ŸÎBœlœ{œã€älŒl ü‚nÜ
    WiFi Failed!”
    In a first moment the code worked very well, but when I connected the UART cables (using D8 and D7 pins) the program stopped working. Now, when I disconnect the cables the program still not working. Help please!

    Reply
  43. I am struggling with trying to assign the result from inputMessage to a variable in my sketch.

    The variable in question is defined as const char*. When I do the assignment, the contents of the variable turn into garbage characters. I have modified this tutorial sketch slightly to demonstrate the issue. “hostip” is the variable I am trying to use. Can you help?

    #include <Arduino.h>
    #include <WiFi.h>
    #include <AsyncTCP.h>
    #include <ESPAsyncWebServer.h>

    AsyncWebServer server(80);

    // REPLACE WITH YOUR NETWORK CREDENTIALS
    const char* ssid = "Wokwi-GUEST";
    const char* password = "";
    const char* hostip;
    const char* PARAM_INPUT_1 = "input1";

    // HTML web page to handle 3 input fields (input1, input2, input3)
    const char index_html[] PROGMEM = R"rawliteral(
    <!DOCTYPE HTML><html><head>
    <title>ESP Input Form</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    </head><body>
    <form action="/get">
    input1: <input type="text" name="input1">
    <input type="submit" value="Submit">
    </form>
    </body></html>)rawliteral";

    void notFound(AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
    }

    void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
    }
    Serial.println();
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

    // Send web page with input fields to client
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
    });

    // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
    server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
    inputMessage = request->getParam(PARAM_INPUT_1)->value();
    inputParam = PARAM_INPUT_1;
    int str_len = inputMessage.length() + 1;
    char char_array[str_len];
    inputMessage.toCharArray(char_array, str_len);
    hostip = strtok(char_array, " ");
    }
    else {
    inputMessage = "No message sent";
    inputParam = "none";
    }
    Serial.println(hostip);
    Serial.println(inputMessage);
    request->send(200, "text/html", "HTTP GET request sent to your ESP on input field ("
    + inputParam + ") with value: " + inputMessage +
    "<br><a href=\"/\">Return to Home Page</a>");
    });
    server.onNotFound(notFound);
    server.begin();
    }

    void loop() {

    }

    Reply
  44. Hi Rui, Sara,
    I have used this method for several applications now, thank you.
    As my project grows I have now created several different webpages, each with forms for different settings including AP and STN settings, NTP settings and timers, just to name a few.
    What I have been looking for without success is how to create a form, multiple inputs like above, but with only one submit button. Creating the webpage form is the simple part. I think it would create a POST something like:
    process.html?input1=text1&input2=text2&input3=text3

    I can’t figure it out how to go about parsing this string. Any examples I have found are in python or C++ and they don’t explain it very well. I use Arduino IDE.

    Reply
  45. Hello you wonderful people. I have worked my way through several of your fantastic esp32 soft AP and webserver tutorials now, thank you so much.
    I am attempting to do something that i can’t find a tutorial for exactly, and i was wondering if you can point to anything of yours i may have missed that might help.

    I have a made a device for printing hall passes for my students with the push of a button. The key components are a thermal printer and an rtc. The only problem is the RTC periodically loses the time for some reason and i thought a great way to fix it without having to reupload all the code would be to log into the esp32 brains via soft ap and then check the time the rtc currently has, and be able to change it and that be stored in the RTC. I just can’t manage to piece together a way to achieve this.

    So my question is simple, is this possible, and if so, what do you recommend i look into to work out a solution. Maybe one of your courses would give me this skills if i followed it all the way through? or maybe you already have a tutorial that is appropriate but have missed it?

    anyway, i hope you find the time to answer, but if not and all you do is read this, thank you for publishing so much amazing stuff for us to learn from for free.

    Reply
    • Hi.
      We don’t have a tutorial for that specific project.

      But, depending on the RTC library you’re using, there’s usually a command that allows you to set the time.
      First, store your input string in a variable.
      Then, slice the string to get hours, minutes, etc… Or create an input field for each of those values.
      Then, the RTC library should have a method that accepts those parameters to set the time.

      I hope this helps.
      Regards,
      Sara

      Reply
  46. When running SPIFFS.begin I get printed “An Error has occurred while mounting SPIFFS”. Should the latter code still work? If not, are you planning to make an update?

    Reply
    • Sorry, I noticed that there already is a question related to this. Now I replaced all SPIFFS with LittleFS, and my code works. So I still use the code from this great tutorial.

      Reply
  47. Thanks for your great article – one thing I’m trying to understand, in handleRoot():
    Why can you not do multiple requests, e.g:
    void handleRoot() {
    server.send(200, “text/plain”, “Hello world!”);
    server.send(200, “text/plain”, “Hello again!”);
    }
    I understand that for one request you can send only one response – but is each server.send(..) not a separate request? Or is handleRoot() {…} a single request?
    Thanks and regards

    Reply
  48. Hi Sara and Rui
    Do you know how integrate drop down menus?? to get data from individual menu or couple of drop down menus at onece??

    Reply
  49. Hello, I need a little help. I would like to combine your code from this project with some code from your other projects to create the following:
    A device that has an ESP32 and a GSM module. That device should have some configuration. I would like to be able to configure it via the phone, so that the ESP32 will work in AP mode, but not via the router, because there is no internet connection where it will be. He must display the WEB interface (HTML) on the phone, like the Tasmota configuration, and via the web interface some variables must be entered into the input fields, which will be directly updated in the ESP32 microcontroller. Let’s say I want to enter emergency phone numbers of users to which the GSM module will send SMS messages. You should have, for example, 5 input fields in the web interface of the smartphone, and when the user enters 5 different numbers, those variables should be saved, for example, in eeprom or wherever they are needed. The point is that the user will not be able to open the device and have to insert numbers into the code and compile it, but that the configuration should be via the web interface, as Tasmota has done. Do you have any idea how to make it? Any advice is welcome. Thanks in advance!

    Reply
    • I tried same because i’m building something similiar, but i can’t find example for this. Problem in combining these two codes you eant to combine are using dofferent libraries and its not that easy to combine it without some knowledge in programming

      Reply
  50. For me your code did not work sometimes, since Wifi connection failed.
    Maybe you can add these lines to your project that helped me out.
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(“.”);
    }

    Reply
  51. Love the articles. This is one of the last pieces I needed to finish up a project. Few questions and most likely some follow up questions.

    User in 2020 had asked about adding a restart button to restart the esp. How can this be acheived? The variables I am doing this for are ones that are only set during the setup functions such as display.displayRemap for the SSD1306 OLED. Reset button would be good so users dont have to unplug/plug back in power.

    What would need to be changed to do multiple string/int/etc? Obviously the file name has to change, but what else?

    Someone else also asked about being able to change const char’s but I dont think there was a reply. This device is already acting as a wifi_sta_ap and will always have the softap running. Would like to present some fields so users can provide the SSID & password for the STA side of the wifi & have it connect to their own wifi. AP mode will still always be running though as that is one of the purposes of this device. Looking to be able to have users be able to enter & submit the following (change what is in quotes ” ”
    const char ClientSSID[] = “ssid”;
    const char ClientPassword[] = “password”;
    const char* mqtt_server = “x.x.x.x”;
    const char* mqtt_user = “”;
    const char* mqtt_pass = “”;

    static IP info for STA
    IPAddress ip(192, 168, 1, 1);
    IPAddress gateway(192, 168, 1, 1);
    IPAddress subnet(255, 255, 255, 0);
    IPAddress dns(192, 168, 1, 1);

    Reply
    • I figured out the 1st part of multiple inputs. created new Parm_string & inputstring’s. Good to go on that front, now on to the rest.

      Reply
      • Thanks for the reply.

        I know to use esp.restart but I dont know how to add that as a button in your example above.

        Wifi manager would be OK but it has some shortcomings. 1) Anyone ever realize that it doesn’t have subnet mask as an input? Networking 101 there to not have that.
        2) I am not a programmer so trying to incorporate multiple examples into 1 doesn’t usually end well.
        3) Haven’t seen a wifi manager that keeps SoftAP on at all times AND STA mode. I had been either or. I want both.

        Bigger problem is there are underlying issues with the ESP IDF. Multiple examples and bugs reported and no fix in sight. Example: Programming in the ssid/password to look at a file and have it connect as a client. Works. Now, unplug the device and take it somewhere. AP mode wont start or will start and then shut down because the STA is trying to reconnect to the AP it knew last and keeps trying to connect every 3 seconds.

        Back to topic though. I have multiple stings setup and they are all working as expected, including SSID/password. I dropped trying to do static IP for now, will be such a low use case and have ways to address that with clients. Only thing outstanding is how to add a button using the above example to do a restart.

        Now…would would be really cool is if you did an example where you combined multiple examples into 1. For example the above but using html files in SPIFFS (or actually FS), Elegant OTA and reading things like sensors (https://randomnerdtutorials.com/esp32-dht11-dht22-temperature-humidity-web-server-arduino-ide/)

        You have some great articles and they really do help, just a little scattered when trying to do multiple things on a device.

        In the end I would like to have in index page that shows charts, config page that let’s users put in settings like ssid, pass, mqtt settings and a few other int/strings like selecting to rotate a display or not. Could live without the index page, would most likely cause blocking anyway, but the config like this example is the primary thing. Could just have new firmware being done with a batch file, but who likes to type when you can just click on things right?

        Reply
  52. I am using Example 2 by the way.

    Adding the AsyncElegantOTA wont work exactly with the example code. When accessing the /update the browser tries to download a file which then causes the ESP32 to drop off the network. Only thing to fix it is to restart. Did the following:

    #include <AsyncElegantOTA.h>

    Then under setup:
    AsyncElegantOTA.begin(&server);
    server.begin();

    Reply
  53. The libraries points to “me-no-dev” but the one that is in the Arduino IDE is “https://github.com/dvarrel/ESPAsyncWebSrv”.

    And update perhaps…

    Reply
  54. Hi,
    Thanks for this excellent article.

    I’m using Preferences instead of SPIFFS … and I’m struggling to modify the above code.

    I’ve tried searching in RNT, but seems not available. Would appreciate if RNT or someone here who had this done up in Preferences, can post their code.

    Thanks in advance.

    Reply
  55. Thanks for the excellent tutorial.
    I didn’t want to leave the page when I entered something so I changed
    request->send(200, “text/html”, “HTTP GET request sent to …”);
    to
    request->send(204, “text/html”, “”);
    and that works fine for me, I get my variable into the 8266 sketch.
    I would like to populate the input box with an initial value from the sketch before I enter a different one. How would I do that?

    Reply
  56. Hi there, many thanks for this!

    Little note:
    I was wondering why my tablet showed the full keyboard instead of the NumPad and found a trailing space in the input type definition.
    <input type=”number ” obviously defaults to “text”, but this works just fine:
    <input type=”number”

    Stefan

    Reply
  57. Dear Sara,

    this tutorial looks great. However, when ever I try to run this code, I am getting the following Error — C:\Users\anura\OneDrive\Documents\Arduino\libraries\AsyncTCP\src\AsyncTCP.cpp: In function ‘bool _start_async_task()’:
    C:\Users\anura\OneDrive\Documents\Arduino\libraries\AsyncTCP\src\AsyncTCP.cpp:221:141: error: ‘xTaskCreateUniversal’ was not declared in this scope
    xTaskCreateUniversal(_async_service_task, “async_tcp”, 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);

    request guidance on this error,

    Regards,

    Anurag

    Reply
    • Hi.
      Did you install all the required libraries?
      Which versions of the library are you running?
      What version of the ESP32 boards installation are you using? Tools > Boards > Boards Manager, search for ESP32 and check the version.
      Regards,
      Sara

      Reply
  58. c:\Users\NamPC\Documents\Arduino\libraries\AsyncTCP\src\AsyncTCP.cpp: In function ‘bool _start_async_task()’:
    c:\Users\NamPC\Documents\Arduino\libraries\AsyncTCP\src\AsyncTCP.cpp:221:141: error: ‘xTaskCreateUniversal’ was not declared in this scope
    xTaskCreateUniversal(_async_service_task, “async_tcp”, 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
    ^
    Multiple libraries were found for “WiFi.h”
    Used: C:\Users\NamPC\Documents\Arduino\hardware\espressif\esp32\libraries\WiFi
    Not used: C:\Users\NamPC\Documents\Arduino\libraries\WiFi
    exit status 1

    Compilation error: exit status 1

    AsyncTCP V1.1.4

    🙁

    Reply
  59. With a Wemos Lolin32 I had to upload txt files to spiffs to get it to work, every time I successfully change the data it tries to download a text file.

    Reply
  60. Hi Rui and everyone. I’ve been an avid follower of your excellent tutorials for the past few months. I’ve amalgamated some to make a project of my own, so thank you for that.
    I have one question – if I want to have different server operations in my sketch at the same time, for example this one above and I also want to run OTA (https://randomnerdtutorials.com/esp32-ota-over-the-air-arduino/) and say this one – https://randomnerdtutorials.com/esp32-esp-now-wi-fi-web-server/#more-96436 – how can I have many instances of ESPAsyncWebServer runnig within the same sketch? Do I need to have each one on different ports numbers? Thanks in advance for any help on this.
    Kind regards,
    Paul.

    Reply
  61. Hi all,
    thanks a lot for your inspirational tutorials. I’ve already learned a lot.
    In my current “project” my fried asked me to change the HTML buttons to choose different colors into a selection box or combo box. I can find hints how to create the selection but how do I get the selected color item to my code and how do I pre-select the current color?
    The code sample for the box looks like this:

    LED Color

    Yellow
    Green
    Red
    Blue

    I would expect to have some JavaScript code but cannot find any hint how to get the selected color to my ESP and how to set the default value depending on the ESP SW…

    Any hints are appreciated.. 😉

    Thanks a lot
    Bernhard

    Reply
  62. Hello very nice explaination, I got much running in a few hours.
    But actually I am struggeling with the processor function, which should replace the actual values on the webpage.

    I am getting an compile error:
    I have this code:

    server.on(“/Settings”,HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, “text/html”, Webpage_Settings,processor);
    });

    error: no matching function for call to ‘AsyncWebServerRequest::send(int, const char [10], char [769], String (&)(const String&))’
    166 | request->send(200, “text/html”, Webpage_Settings,processor);

    Reply
  63. Hi Sara,
    Thanks for your tutorial on ESPAsyncWebSever library. I wonder if there’s a way to hide input data/parameters in the URL instead of showing. I am trying to create a form to submit some credentials/passwords to the backend, and hope these credentials won’t be seen in the URL. Thanks.

    Reply
  64. Hi, As far as I understand that all values in the textfields are saved as “string” or “char*”
    How can I get it working by using “int”? Calculation doesn’t work in this way.

    Reply
  65. Hi Sara, Thank you for your tutorial.

    I run the code but am getting this error : “error: ‘mbedtls_md5_starts_ret’ was not declared in this scope; did you mean ‘mbedtls_md5_starts’?”

    Any hints are appreciated:)

    Thanks a lot
    Mohammad

    Reply
  66. I’ve made post version with psram:
    #include <Arduino.h>
    #include <WiFi.h>
    #include <AsyncTCP.h>
    #include <ESPAsyncWebServer.h>
    #include <ESPmDNS.h>

    AsyncWebServer server(80);

    const char* ssid = “*****”;
    const char* password = “******”;
    const char* Domain = “esp32″;/choose a domain it’s better than ip

    String value1;
    String value2;

    const char strindex[] PROGMEM = R”rawliteral(
    HTML Form to Input Data

    html {font-family: Times New Roman; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem; color: #FF0000;}

    HTML Form to Input Data

    Enter a string:
    Enter an integer:

    )rawliteral”;

    void notFound(AsyncWebServerRequest *request) {
    request->send(404, “text/plain”, “Not found”);
    }

    void setup()
    {
    value1=”val”;
    Serial.begin(115200);
    if(psramInit())
    {
    Serial.println(“La PSRAM est correctement initialisée”);
    }
    else
    {
    Serial.println(“La PSRAM ne fonctionne pas”);
    }
    char *index_html = (char *) ps_calloc(1000, sizeof(char));//choose number here 1000 octets and ajust the value in snprintf
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(“.”);
    }
    Serial.println();
    Serial.print(“IP Address: “);
    Serial.println(WiFi.localIP());
    if (MDNS.begin(Domain))
    {
    Serial.println((String)”Nom de domaine “+Domain+”.local”);
    }
    else
    {

    Serial.println("Echec du DNS");

    }

    server.on(“/”,HTTP_GET, [index_html](AsyncWebServerRequest request)
    {
    snprintf (index_html,1000,strindex,value1,value2);
    request->send_P(200, “text/html”,index_html);
    });
    server.on(“/”,HTTP_POST, [index_html](AsyncWebServerRequest *request)
    {
    const char
    para1 = “input1”;
    const char* para2 = “input2”;

    if (request->hasParam(para1,true)) {
    value1 = request->getParam(para1,true)->value();
    Serial.println(“ok”);
    }

    if (request->hasParam(para2,true)) {
    value2 = request->getParam(para2,true)->value();
    }
    //snprintf (index_html, sizeof(index_html),strindex,value1,value2);
    snprintf (index_html,1000,strindex,value1,value2);
    request->send_P(200, “text/html”,index_html);
    });

    server.onNotFound(notFound);
    server.begin();

    }

    void loop()
    {
    //code here
    }

    Reply
  67. Thank you a lot for all these wonderful tutorials, I just adapted this to one of my projects – grow tent controller so I don’t have to connect my laptop everytime to change target humidity, fan interval, time etc. One question, if we have let’s say 15 variables do we store each in it’s own file or can we pack all in one file. I don’t mind having 15 files but if my project grows in future what’s the best way to approach that? Does it hurt to have so many files? Thanks again!

    Reply
    • Hi.
      Yes, you can save all variables in the same file.
      You can save them in JSOn format, for example, or any other format that is more suitable for you.
      Regards,
      Sara

      Reply
  68. Hi there everyone. Sara and Rui, I’m so grateful for your tutorials.
    Has anyone used the SD library to store the index_html variable (the web page) as index.html and served it from the card instead?
    I’ve tried many ways to change the processor function to serve the web page from a file, but I always end up with a blank web page being served. I’ve tried loading the web page into a string and then giving the address of the string to the 3rd argument of the processor function by using myString.c_str() and myString.toCharArray(), but neither worked.
    Anyone one this great website have any ideas or success with an SD card? Perhaps someone could post the processor function or some code to show how they acheieved success?

    Thanks in advance…Bryan

    Reply
  69. Thanks so much Sara. I’ll definitely have a look at that tutorial. I was having trouble (at least I thought I was) getting the file and running the processor code to replace variables in the file. I had parameters that wouldn’t work in the server.on “/” root function. I’ll instead switch to the server.on call in the other tutorial and see how that works (thanks for your guidance and I’m sure it will work). I did solve my current issue late last night after figuring out that I had 2 bad html tags in my file on the SD card. After I corrected the tag problems I changed the 3rd parameter in server.on parameters to this:

    server.on(“/”, HTTP_GET, [](AsyncWebServerRequest* request) {
    String myString = readFile(SD,”/index.html”);
    request->send_P(200, “text/html”, (myString.c_str()) , processor); //changed local variable index_html (arg #3) to SD file (myString.c_str())

    Thanks again to you and Rui!!

    Reply
  70. THis is awesome, I love RNT content, so well explained with the way you give the full example but then go through it in steps 🙂

    Everything works fine for me, but why is there a delay of 500ms here? I would prefer to sumbit and refresh immediately but if i make that line just: “{ document.location.reload(false); }” the buttons do nothing……

    function submitMessage() {
    alert(“Saved value to ESP LittleFS”);
    setTimeout(function(){ document.location.reload(false); }, 500);
    }

    Reply
  71. Hi Sara,

    Thank you for these amazing and comprehensive tutorials; they are invaluable!

    Do you have any insights or suggestions on how to merge this tutorial ( https://randomnerdtutorials.com/esp32-esp8266-input-data-html-form/ )and this one: https://randomnerdtutorials.com/esp32-access-point-ap-web-server/

    So that one could connect to the ESP32 via phone or laptop as an Access Point and input data from an html form to be saved with littleFS?

    Effectively removing the need for a wifi network so that devices can communicate with the ESP32 directly?

    I’m happy to commission you or compensate you for any time/effort.

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.