Building an ESP32 Web Server with Arduino IDE

In this project, you will create a standalone web server with the ESP32 using the Arduino IDE programming environment, which controls outputs (two LEDs).The web server is mobile responsive and can be accessed using any device as a browser on the local network.We will guide you step by step on how to create the web server and how the code works.

Project Overview

Before diving into the project, it is important to outline what our web server will do to make it easier to follow these steps later.

  • You will build a web server that controls two LEDs connected to the ESP32 on GPIO 26 and GPIO 27;

  • You can access the ESP32 web server by entering the ESP32 IP address in a browser on the local network;

  • By clicking buttons on the web server, you can immediately change the state of each LED.

This is just a simple example to illustrate how to build a web server that controls outputs, with the idea of replacing these LEDs with relays or any other electronic components you want.

Install ESP32 Board in Arduino IDE

The Arduino IDE has an add-on that allows you to program the ESP32 using the Arduino IDE and its programming language.Prepare your Arduino IDE by following one of the tutorials below:

  • Windows Instructions— Install ESP32 board in Arduino IDE

  • Mac and Linux Instructions— Install ESP32 board in Arduino IDE

Required Parts

For this tutorial, you will need the following parts:

Building an ESP32 Web Server with Arduino IDE

  • ESP32 Development BoardRead ESP32 Development Board Review and Comparison

  • 2 x 5mm LEDs

  • 2x 330 Ohm Resistors

  • Breadboard

  • Jumper Wires

You can use the links above or visit MakerAdvisor.com/tools directly to find all the parts for your project at the best prices!

Building an ESP32 Web Server with Arduino IDE

Schematic Diagram

Start by building the circuit. Connect the two LEDs to the ESP32 as shown below – one LED is connected to GPIO 26, and the other to GPIO 27.

Note: We are using the ESP32 DEVKIT DOIT board with 36 pins. Be sure to check the pinout of the board you are using before assembling the circuit.

ESP32 Web Server Code

Here we provide the code to create the ESP32 web server. Copy the following code into your Arduino IDE, but do not upload it just yet. You will need to make some changes to fit your needs.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

// Load Wi-Fi library
#include <WiFi.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output26State = "off";
String output27State = "off";

// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(output26, OUTPUT);
  pinMode(output27, OUTPUT);
  // Set outputs to LOW
  digitalWrite(output26, LOW);
  digitalWrite(output27, LOW);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

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

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
      currentTime = millis();
      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
        header += c;
        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("Connection: close");
            client.println();
            
            // turns the GPIOs on and off
            if (header.indexOf("GET /26/on") >= 0) {
              Serial.println("GPIO 26 on");
              output26State = "on";
              digitalWrite(output26, HIGH);
            } else if (header.indexOf("GET /26/off") >= 0) {
              Serial.println("GPIO 26 off");
              output26State = "off";
              digitalWrite(output26, LOW);
            } else if (header.indexOf("GET /27/on") >= 0) {
              Serial.println("GPIO 27 on");
              output27State = "on";
              digitalWrite(output27, HIGH);
            } else if (header.indexOf("GET /27/off") >= 0) {
              Serial.println("GPIO 27 off");
              output27State = "off";
              digitalWrite(output27, LOW);
            }
            
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #555555;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>ESP32 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 26  
            client.println("<p>GPIO 26 - State " + output26State + "</p>");
            // If the output26State is off, it displays the ON button       
            if (output26State=="off") {
              client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 27  
            client.println("<p>GPIO 27 - State " + output27State + "</p>");
            // If the output27State is off, it displays the ON button       
            if (output27State=="off") {
              client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            
            // 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
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

View the original code

Set Your Network Credentials

You need to modify the following lines with your network credentials: SSID and password. The code has good comments on where you should make changes.

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

Upload Code

Now, you can upload the code, and the web server will be up and running immediately. Follow these steps to upload the code to the ESP32:

1) Plug the ESP32 development board into the computer;

2) Select your board in Arduino IDE under Tools> Board (in our case, we are using the ESP32 DEVKIT DOIT board);

Building an ESP32 Web Server with Arduino IDE

3) Select the COM port in Tools> Port.

Building an ESP32 Web Server with Arduino IDE

4) Press the upload button in Arduino IDE, wait a few seconds while the code compiles and uploads to your board.

Building an ESP32 Web Server with Arduino IDE

5) Wait for the “Upload Complete” message.

Building an ESP32 Web Server with Arduino IDE

Find ESP IP Address

After uploading the code, open the Serial Monitor at a baud rate of 115200.

Building an ESP32 Web Server with Arduino IDE

Press the ESP32 EN button (reset). The ESP32 connects to Wi-Fi and outputs the ESP IP address on the Serial Monitor. Copy the IP address as you will need it to access the ESP32 web server.

Building an ESP32 Web Server with Arduino IDE

Access the Web Server

To access the web server, open a browser and paste the ESP32 IP address, and you will see the following page. In our example, it is192.168.1.135.

Building an ESP32 Web Server with Arduino IDE

If you check the Serial Monitor, you can see what is happening in the background. The ESP receives the HTTP request from a new client (in this case, your browser).

Building an ESP32 Web Server with Arduino IDE

You can also see more information about the HTTP request.

Test the Web Server

Now you can test if your web server is working properly. Click the buttons to control the LEDs.

Building an ESP32 Web Server with Arduino IDE

Meanwhile, you can check the Serial Monitor to see what is happening in the background. For example, when you click the button to turn GPIO 26 ON, the ESP32 receives a request at the /26/on URL.

Building an ESP32 Web Server with Arduino IDE

When the ESP32 receives that request, it turns ON the GPIO 26 and updates its status on the webpage.

Building an ESP32 Web Server with Arduino IDE

The button for GPIO 27 works similarly. Test it to see if it works properly.

How It Works

In this section, we will take a closer look at the code to understand how it works.

The first thing you need to do is to include the WiFi library.

#include <WiFi.h>

As mentioned earlier, you need to insert your ssid and password in the following lines inside double quotes.

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

Then, set the web server to port 80.

WiFiServer server(80);

The following line creates a variable to store the header of the HTTP request:

String header;

Next, you create auxiliary variables to store the current state of the outputs. If you want to add more outputs and keep their states, you need to create more variables.

String output26State = "off";
String output27State = "off";

You also need to assign a GPIO for each output. Here we useGPIO 26 and GPIO 27. You can use any other suitable GPIO.

const int output26 = 26;
const int output27 = 27;

Setup()

Now, let’s get into thesetup(). First, we start serial communication at a baud rate of 115200 for debugging.

Serial.begin(115200);

You also define the GPIOs as outputs and set them to low.

// Initialize the output variables as outputs
pinMode(output26, OUTPUT);
pinMode(output27, OUTPUT);

// Set outputs to LOW
digitalWrite(output26, LOW);
digitalWrite(output27, LOW);

The following lines start the Wi-Fi connectionWiFi.begin(ssid, password), wait for a successful connection, and print the ESP IP address in the Serial Monitor.

// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();

Loop()

In theloop() function, we program what happens when a new client establishes a connection with the web server.

The ESP32 always listens for incoming clients with the following line:

WiFiClient client = server.available(); // Listen for incoming clients

When a request is received from a client, we save the incoming data. The subsequent while loop runs as long as the client remains connected. We do not recommend changing this part of the code unless you know exactly what you are doing.

if (client) { // If a new client connects,
  Serial.println("New Client."); // print a message out in 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
      header += c;
      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("Connection: close");
          client.println();

The next part of the if and else statements checks which button was pressed on your webpage and controls the outputs accordingly. As we saw earlier, we send requests to different URLs based on the button pressed.

// turns the GPIOs on and off
if (header.indexOf("GET /26/on") >= 0) {
  Serial.println("GPIO 26 on");
  output26State = "on";
  digitalWrite(output26, HIGH);
} else if (header.indexOf("GET /26/off") >= 0) {
  Serial.println("GPIO 26 off");
  output26State = "off";
  digitalWrite(output26, LOW);
} else if (header.indexOf("GET /27/on") >= 0) {
  Serial.println("GPIO 27 on");
  output27State = "on";
  digitalWrite(output27, HIGH);
} else if (header.indexOf("GET /27/off") >= 0) {
  Serial.println("GPIO 27 off");
  output27State = "off";
  digitalWrite(output27, LOW);
}

For example, if you press the GPIO 26 ON button, the ESP32 receives a request about the /26/ON URL (we can see that information in the HTTP header of the Serial Monitor). Thus, we check if the header contains the expressionGET /26/on. If it does, we change the output26State variable to ON, and the ESP32 turns on the LED.

This works similarly for the other buttons. So if you want to add more outputs, you should modify this part of the code to include them.

Display HTML Webpage

The next thing you need to do is create the webpage. The ESP32 will send a response with some HTML code to your browser to build the webpage.

Use this expression to send the webpage to the clientclient.println(). You should enter the content you want to send to the client as a parameter.

The first thing we should always send is the following line, indicating that we are sending HTML

<!DOCTYPE HTML><html>

Then, the following line makes the webpage responsive in any web browser.

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");

Below is the line used to prevent requests for the icon.– You don’t need to worry about this line.

client.println("<link rel=\"icon\" href=\"data:,\">");

Webpage Styling

Next, we have some CSS text to style the buttons and the appearance of the webpage. We choose the Helvetica font, define the content to be displayed as a block, and center it.

client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");

We style the button with color #4CAF50, no border, white text, and use this padding: 16px 40px. We also set text-decoration to none, define font size, margin, and cursor as pointer.

client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

We also define the style for the second button with all the properties of the button we defined earlier but with a different color. This will be the style for the OFF button.

client.println(".button2 {background-color: #555555;}</style></head>");

Set the First Heading of the Webpage

In the next line, you can set the first heading of the webpage. Here we have “ ESP32 Web Server ”, but you can change this text to anything you like.

// Web Page Heading
client.println("<h1>ESP32 Web Server</h1>");

Display the Buttons and Their States

Then, you write a paragraph to display the current state ofGPIO 26. As you can see, we use the output26State variable to immediately update the status when that variable changes.

client.println("<p>GPIO 26 - State " + output26State + "</p>");

Then we display ON or OFF buttons based on the current state of the GPIO. If the current state of the GPIO is off, we display the ON button; otherwise, we display the OFF button.

if (output26State=="off") {
  client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
} else {
  client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
}

We use the same procedure forGPIO 27.

Close the Connection

Finally, when the response ends, we clear theheader variable and stop the connection with the clientclient.stop();.

// Clear the header variable
header = "";
// Close the connection
client.stop();

Conclusion

In this tutorial, we showed you how to build a web server with the ESP32. We have demonstrated a simple example that controls two LEDs, but the idea is to replace these LEDs with relays or any other outputs you want to control. Stay tuned for more projects with the ESP32!

Leave a Comment

Your email address will not be published. Required fields are marked *