2019年10月17日 星期四

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

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 SPIFFS and how to access them. Here’s how this second example works.
ESP32 ESP8266 HTML Form Input Data Project Overview SPIFFS
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 SPIFFS file. This web page also contains a placeholder to show the current values.
To learn more about building a web server using SPIFFS, you can refer to the next tutorials:

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() {
 }

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 input1input2, or input3 parameters. These are saved on the PARAM_INPUT_1PARAM_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 SPIFFS

Now, let’s proceed to the second example. This example saves the data inserted on the input fields permanently on SPIFFS. 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
  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 <SPIFFS.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
  #include <Hash.h>
  #include <FS.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 SPIFFS");
      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());
  }
  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");
  }
}

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

void setup() {
  Serial.begin(115200);
  // Initialize SPIFFS
  #ifdef ESP32
    if(!SPIFFS.begin(true)){
      Serial.println("An Error has occurred while mounting SPIFFS");
      return;
    }
  #else
    if(!SPIFFS.begin()){
      Serial.println("An Error has occurred while mounting SPIFFS");
      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(SPIFFS, "/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(SPIFFS, "/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(SPIFFS, "/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(SPIFFS, "/inputString.txt");
  Serial.print("*** Your inputString: ");
  Serial.println(yourInputString);
  
  int yourInputInt = readFile(SPIFFS, "/inputInt.txt").toInt();
  Serial.print("*** Your inputInt: ");
  Serial.println(yourInputInt);
  
  float yourInputFloat = readFile(SPIFFS, "/inputFloat.txt").toFloat();
  Serial.print("*** Your inputFloat: ");
  Serial.println(yourInputFloat);
  delay(5000);
}

Important: if you’re using an ESP8266, make sure you’ve enabled SPIFFS in Tools Flash Size menu:
Select ESP8266 NodeMCU board with SPIFFS Arduino IDE

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 SPIFFS library to write to SPIFFS.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <SPIFFS.h>
If you’re using an ESP8266, you need to include the FS library to interface with SPIFFS.
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsyncTCP.h>
#include <Hash.h>
#include <FS.h>

HTML Form

In this example, when you submit the values, a window opens saying the value was saved to SPIFFS, 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 SPIFFS. After that pop up, it reloads the web page so that it displays the current values.
<script>
  function submitMessage() {
    alert("Saved value to ESP SPIFFS");
    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 SPIFFS

Then, we have some functions to read and write from SPIFFS.
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 SPIFFS.
String processor(const String& var){
  //Serial.println(var);
  if(var == "inputString"){
    return readFile(SPIFFS, "/inputString.txt");
  }
  else if(var == "inputInt"){
    return readFile(SPIFFS, "/inputInt.txt");
  }
  else if(var == "inputFloat"){
    return readFile(SPIFFS, "/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 SPIFFS.
For example, for the inputString field:
if (request->hasParam(PARAM_STRING)) {
  inputMessage = request->getParam(PARAM_STRING)->value();
  writeFile(SPIFFS, "/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 SPIFFS.
writeFile(SPIFFS, "/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 SPIFFS.
String yourInputString = readFile(SPIFFS, "/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:

沒有留言:

張貼留言

2024_09 作業3 以Node-Red 為主

 2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...