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:
-
ESP32 Development Board — Read 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!
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);
3) Select the COM port in Tools> Port.
4) Press the upload button in Arduino IDE, wait a few seconds while the code compiles and uploads to your board.
5) Wait for the “Upload Complete” message.
Find ESP IP Address
After uploading the code, open the Serial Monitor at a baud rate of 115200.
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.
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.
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).
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.
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.
When the ESP32 receives that request, it turns ON the GPIO 26 and updates its status on the webpage.
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 *