ESP32 - Web Server Multiple Pages
In this tutorial, we'll find out how to turn an ESP32 into a web server that can handle multiple pages at the same time, such as index.html, temperature.html, led.html, error_404.html, and error_405.html...
By following this tutorial, you will be able to turn your ESP32 into a web server with some cool features:
Multiple web pages are active simultaneously.
The HTML content (including HTML, CSS, and Javascript) for each page is kept separately in its own file on the Arduino IDE.
The HTML content can be dynamically updated with real-time values from sensors, making the web pages dynamic and responsive.
The web server allows to control something connected to ESP32 via web.
The web server handles HTTP error codes such as 404 Not Found and 405 Method Not Allowed
It might sound complicated, but don't worry! This tutorial provides step-by-step guidance, and the code is designed to be beginner-friendly, ensuring that you can easily comprehend and create your own ESP32 web server.
Or you can buy the following sensor kits:
Disclosure: Some of the links in this section are Amazon affiliate links, meaning we may earn a commission at no additional cost to you if you make a purchase through them. Additionally, some links direct you to products from our own brand, DIYables.
If you're not familiar with ESP32 and Web Server (including pinout, how it works, and programming), you can learn about them through the following tutorials:
Below is the complete ESP32 code that creates a web server with multiple pages. To keep it simple, the HTML content for each page is very simple and embedded directly in the ESP32 code. In the another part, we will learn how to separate the HTML contents for each page into separate files, making the code more organized and manageable.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#define LED_PIN 18
const char *ssid = "YOUR_WIFI_SSID";
const char *password = "YOUR_WIFI_PASSWORD";
AsyncWebServer server(80);
int LED_state = LOW;
float getTemperature() {
float temp_x100 = random(0, 10000);
return temp_x100 / 100;
}
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("Web Server: home page");
request->send(200, "text/html", "This is the ESP32 home page");
});
server.on("/temperature.html", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("Web Server: temperature page");
float temperature = getTemperature();
request->send(200, "text/html", "Temperature: " + String(temperature));
});
server.on("/led.html", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Web Server: LED page");
if (request->hasArg("state")) {
String state = request->arg("state");
if (state == "on") {
LED_state = HIGH;
} else if (state == "off") {
LED_state = LOW;
}
digitalWrite(LED_PIN, LED_state);
Serial.print(" => turning LED to ");
Serial.print(state);
}
Serial.println();
request->send(200, "text/html", "LED state: " + String(LED_state));
});
server.onNotFound([](AsyncWebServerRequest *request) {
if (request->method() == HTTP_GET) {
Serial.println("Web Server: Not Found");
request->send(404, "text/html", "Not Found");
} else {
Serial.println("Web Server: Method Not Allowed");
request->send(405, "text/html", "Method Not Allowed");
}
});
server.begin();
Serial.println("ESP32 Web server started");
}
void loop() {
}
Do the wiring as above image.
Connect the ESP32 board to your PC via a micro USB cable
Open Arduino IDE on your PC.
Select the right ESP32 board (e.g. ESP32 Dev Module) and COM port.
Open the Library Manager by clicking on the Library Manager icon on the left navigation bar of Arduino IDE.
Search “ESPAsyncWebServer”, then find the ESPAsyncWebServer created by lacamera.
Click Install button to install ESPAsyncWebServer library.
Copy the above code and open with Arduino IDE
Change the wifi information (SSID and password) in the code to yours
Click Upload button on Arduino IDE to upload code to ESP32
Open the Serial Monitor
Check out the result on Serial Monitor.
Connecting to WiFi...
Connected to WiFi
ESP32 Web Server's IP address: 192.168.0.2
ESP32 Web server started
You will see an IP address on the Serial Monitor, for example: 192.168.0.2
Type the following list one-by-one on the address bar of a web browser on your smartphone or PC.
192.168.0.2
192.168.0.2/index.html
192.168.0.2/led.html
192.168.0.2/temperature.html
192.168.0.2/blabla.html
Please note that you need to change the 192.168.0.2 to the IP address you got on Serial Monitor.
You will see the following pages: home page, led page, temperature page, and Not Found page
You can also check the output on Serial Monitor
Connecting to WiFi...
Connected to WiFi
ESP32 Web Server's IP address: 192.168.0.2
ESP32 Web server started
Web Server: home page
Web Server: LED page
Web Server: LED page => turning LED to on
Web Server: LED page => turning LED to off
Web Server: temperature page
Web Server: Not Found
The previous code has very simple HTML content for each page. But if we want to make a fancy interface with lots of HTML, the code can get big and messy. To make it simpler, we will learn how to separate the HTML from the ESP32 code. This lets us keep the HTML in separate files, making it easier to manage and work with.
Open the Arduino IDE.
Create a new sketch and give it a name, for example, ESP32WebServer.ino.
Copy the provided code and paste it into that file.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include "index.h"
#include "temperature.h"
#include "led.h"
#include "error_404.h"
#include "error_405.h"
#define LED_PIN 18
const char *ssid = "YOUR_WIFI_SSID";
const char *password = "YOUR_WIFI_PASSWORD";
AsyncWebServer server(80);
int LED_state = LOW;
float getTemperature() {
float temp_x100 = random(0, 10000);
return temp_x100 / 100;
}
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("Web Server: home page");
String html = HTML_CONTENT_HOME;
request->send(200, "text/html", html);
});
server.on("/temperature.html", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("Web Server: temperature page");
String html = HTML_CONTENT_TEMPERATURE;
float temperature = getTemperature();
html.replace("%TEMPERATURE_VALUE%", String(temperature));
request->send(200, "text/html", html);
});
server.on("/led.html", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Web Server: LED page");
if (request->hasArg("state")) {
String state = request->arg("state");
if (state == "on") {
LED_state = HIGH;
} else if (state == "off") {
LED_state = LOW;
}
digitalWrite(LED_PIN, LED_state);
Serial.print(" => turning LED to ");
Serial.print(state);
}
Serial.println();
String html = HTML_CONTENT_LED;
html.replace("%LED_STATE%", LED_state ? "ON" : "OFF");
request->send(200, "text/html", html);
});
server.onNotFound([](AsyncWebServerRequest *request) {
if (request->method() == HTTP_GET) {
Serial.println("Web Server: Not Found");
String html = HTML_CONTENT_404;
request->send(404, "text/html", html);
} else {
Serial.println("Web Server: Method Not Allowed");
String html = HTML_CONTENT_405;
request->send(405, "text/html", html);
}
});
server.begin();
Serial.println("ESP32 Web server started");
}
void loop() {
}
Change the WiFi information (SSID and password) in the code to yours
Create the index.h file On Arduino IDE by:
const char *HTML_CONTENT_HOME = R"=====(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>Home Page</title>
</head>
<body>
<h1>Welcome to the Home Page</h1>
<ul>
<li><a href="/led.html">LED Page</a></li>
<li><a href="/temperature.html">Temperature Page</a></li>
</ul>
</body>
</html>
)=====";
const char *HTML_CONTENT_LED = R"=====(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>LED Page</title>
</head>
<body>
<h1>LED Page</h1>
<p>LED State: <span style="color: red;">%LED_STATE%</span></p>
<a href='/led.html?state=on'>Turn ON</a>
<br><br>
<a href='/led.html?state=off'>Turn OFF</a>
</body>
</html>
)=====";
const char *HTML_CONTENT_TEMPERATURE = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 - Web Temperature</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<link rel="icon" href="https://diyables.io/images/page/diyables.svg">
<style>
body { font-family: "Georgia"; text-align: center; font-size: width/2pt;}
h1 { font-weight: bold; font-size: width/2pt;}
h2 { font-weight: bold; font-size: width/2pt;}
button { font-weight: bold; font-size: width/2pt;}
</style>
<script>
var cvs_width = 200, cvs_height = 450;
function init() {
var canvas = document.getElementById("cvs");
canvas.width = cvs_width;
canvas.height = cvs_height + 50;
var ctx = canvas.getContext("2d");
ctx.translate(cvs_width/2, cvs_height - 80);
update_view(%TEMPERATURE_VALUE%);
}
function update_view(temp) {
var canvas = document.getElementById("cvs");
var ctx = canvas.getContext("2d");
var radius = 70;
var offset = 5;
var width = 45;
var height = 330;
ctx.clearRect(-cvs_width/2, -350, cvs_width, cvs_height);
ctx.strokeStyle="blue";
ctx.fillStyle="blue";
var x = -width/2;
ctx.lineWidth=2;
for (var i = 0; i <= 100; i+=5) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 20, y);
ctx.stroke();
}
ctx.lineWidth=5;
for (var i = 0; i <= 100; i+=20) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 25, y);
ctx.stroke();
ctx.font="20px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="right";
ctx.fillText(i.toString(), x - 35, y);
}
ctx.lineWidth=16;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.stroke();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle="#e6e6ff";
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.fill();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle="#ff1a1a";
ctx.beginPath();
ctx.arc(0, 0, radius - offset, 0, 2 * Math.PI);
ctx.fill();
temp = Math.round(temp * 100) / 100;
var y = (height - radius)*temp/100.0 + radius + 5;
ctx.beginPath();
ctx.rect(-width/2 + offset, -y, width - 2*offset, y);
ctx.fill();
ctx.fillStyle="red";
ctx.font="bold 34px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="center";
ctx.fillText(temp.toString() + "°C", 0, 100);
}
window.onload = init;
</script>
</head>
<body>
<h1>ESP32 - Web Temperature</h1>
<canvas id="cvs"></canvas>
</body>
</html>
)=====";
const char *HTML_CONTENT_404 = R"=====(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>404 - Page Not Found</title>
<style>
h1 {color: #ff4040;}
</style>
</head>
<body>
<h1>404</h1>
<p>Oops! The page you are looking for could not be found on Esp32 Web Server.</p>
<p>Please check the URL or go back to the <a href="/">homepage</a>.</p>
<p>Or check <a href="https://esp32io.com/tutorials/esp32-web-server-multiple-pages"> Esp32 Web Server</a> tutorial.</p>
</body>
</html>
)=====";
const char *HTML_CONTENT_405 = R"=====(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>405 - Method Not Allowed</title>
<style>
h1 {color: #ff4040;}
</style>
</head>
<body>
<h1>405 - Method Not Allowed</h1>
<p>Oops! The requested method is not allowed for this resource.</p>
<p>Please check your request or go back to the <a href="/">homepage</a>.</p>
<p>Or check <a href="https://esp32io.com/tutorials/esp32-web-server-multiple-pages"> Esp32 Web Server</a> tutorial.</p>
</body>
</html>
)=====";