Arduino Nano ESP32 - Web Server Multiple Pages

In this tutorial, we'll find out how to turn an Arduino Nano 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...

Arduino Nano ESP32 web browser

By following this tutorial, you will be able to turn your Arduino Nano ESP32 into a web server with some cool features:

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 Arduino Nano ESP32 web server.

Hardware Preparation

1×Arduino Nano ESP32
1×USB Cable Type-C
1×(Recommended) Screw Terminal Adapter for Arduino Nano

Or you can buy the following sensor kit:

1×DIYables Sensor Kit 30 types, 69 units
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you. We appreciate your support.

Overview of Arduino Nano ESP32 and Web Server

If you're not familiar with Arduino Nano ESP32 and Web Server (including pinout, how it works, and programming), you can learn about them through the following tutorials:

Arduino Nano ESP32 Code - Multiple-page Web server

Below is the complete Arduino Nano 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 Arduino Nano 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.

/* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ #include <WiFi.h> #include <ESPAsyncWebServer.h> #define LED_PIN D5 // The Arduino Nano ESP32 pin connected to LED const char *ssid = "YOUR_WIFI_SSID"; // CHANGE IT const char *password = "YOUR_WIFI_PASSWORD"; // CHANGE IT AsyncWebServer server(80); int LED_state = LOW; float getTemperature() { // YOUR SENSOR IMPLEMENTATION HERE // simulate the temperature value float temp_x100 = random(0, 10000); // a ramdom value from 0 to 10000 return temp_x100 / 100; // return the simulated temperature value from 0 to 100 in float } void setup() { Serial.begin(9600); pinMode(LED_PIN, OUTPUT); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); // Print the ESP32's IP address Serial.print("Arduino Nano ESP32 Web Server's IP address: "); Serial.println(WiFi.localIP()); // Serve the specified HTML pages 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"); // Check for the 'state' parameter in the query string if (request->hasArg("state")) { String state = request->arg("state"); if (state == "on") { LED_state = HIGH; } else if (state == "off") { LED_state = LOW; } // control LED here 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)); }); // 404 and 405 error handler server.onNotFound([](AsyncWebServerRequest *request) { if (request->method() == HTTP_GET) { // Handle 404 Not Found error Serial.println("Web Server: Not Found"); request->send(404, "text/html", "Not Found"); } else { // Handle 405 Method Not Allowed error Serial.println("Web Server: Method Not Allowed"); request->send(405, "text/html", "Method Not Allowed"); } }); server.begin(); Serial.println("Arduino Nano ESP32 Web server started"); } void loop() { // Your code can go here or be empty; the server is handled asynchronously }

Detailed Instructions

To get started with Arduino Nano ESP32, follow these steps:

  • If you are new to Arduino Nano ESP32, refer to the tutorial on how to set up the environment for Arduino Nano ESP32 in the Arduino IDE.
  • Connect the Arduino Nano ESP32 board to your computer using a USB cable.
  • Launch the Arduino IDE on your computer.
  • Select the Arduino Nano ESP32) board and its corresponding 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.
  • Click Install button to install ESPAsyncWebServer library by lacamera.
Arduino Nano ESP32 ESPAsyncWebServer library
  • You will be asked to install the dependency. Click Install All button.
Arduino Nano ESP32 ESPAsyncWebServer dependencies 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 Arduino Nano ESP32
  • Open the Serial Monitor
  • Check out the result on Serial Monitor.
COM6
Send
Connecting to WiFi... Connected to WiFi Arduino Nano ESP32 Web Server's IP address: 192.168.0.2 Arduino Nano ESP32 Web server started
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • 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
COM6
Send
Connecting to WiFi... Connected to WiFi Arduino Nano ESP32 Web Server's IP address: 192.168.0.2 Arduino Nano 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
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

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 Arduino Nano ESP32 code. This lets us keep the HTML in separate files, making it easier to manage and work with.

Arduino Nano ESP32 Code - Complete multiple-page Web server

  • 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.
/* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ #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 D5 // The Arduino Nano ESP32 pin connected to LED const char *ssid = "YOUR_WIFI_SSID"; // CHANGE IT const char *password = "YOUR_WIFI_PASSWORD"; // CHANGE IT AsyncWebServer server(80); int LED_state = LOW; float getTemperature() { // YOUR SENSOR IMPLEMENTATION HERE // simulate the temperature value float temp_x100 = random(0, 10000); // a ramdom value from 0 to 10000 return temp_x100 / 100; // return the simulated temperature value from 0 to 100 in float } void setup() { Serial.begin(9600); pinMode(LED_PIN, OUTPUT); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); // Print the ESP32's IP address Serial.print("Arduino Nano ESP32 Web Server's IP address: "); Serial.println(WiFi.localIP()); // Serve the specified HTML pages server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { Serial.println("Web Server: home page"); String html = HTML_CONTENT_HOME; // Use the HTML content from the index.h file 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; // Use the HTML content from the temperature.h file float temperature = getTemperature(); html.replace("%TEMPERATURE_VALUE%", String(temperature)); // update the temperature value request->send(200, "text/html", html); }); server.on("/led.html", HTTP_GET, [](AsyncWebServerRequest *request) { Serial.print("Web Server: LED page"); // Check for the 'state' parameter in the query string if (request->hasArg("state")) { String state = request->arg("state"); if (state == "on") { LED_state = HIGH; } else if (state == "off") { LED_state = LOW; } // control LED here digitalWrite(LED_PIN, LED_state); Serial.print(" => turning LED to "); Serial.print(state); } Serial.println(); String html = HTML_CONTENT_LED; // Use the HTML content from the led.h file html.replace("%LED_STATE%", LED_state ? "ON" : "OFF"); // update the LED state request->send(200, "text/html", html); }); // 404 and 405 error handler server.onNotFound([](AsyncWebServerRequest *request) { if (request->method() == HTTP_GET) { // Handle 404 Not Found error Serial.println("Web Server: Not Found"); String html = HTML_CONTENT_404; // Use the HTML content from the error_404.h file request->send(404, "text/html", html); } else { // Handle 405 Method Not Allowed error Serial.println("Web Server: Method Not Allowed"); String html = HTML_CONTENT_405; // Use the HTML content from the error_405.h file request->send(405, "text/html", html); } }); server.begin(); Serial.println("Arduino Nano ESP32 Web server started"); } void loop() { // Your code can go here or be empty; the server is handled asynchronously }
  • Change the WiFi information (SSID and password) in the code to yours
  • Create the index.h file On Arduino IDE by:
    • Either click on the button just below the serial monitor icon and choose New Tab, or use Ctrl+Shift+N keys.
    Arduino IDE 2 adds file
    • Give file's name index.h and click OK button
    Arduino IDE 2 adds file index.h
    • Copy the below code and paste it to the index.h file.
    /* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ 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> )=====";
    • Similarly, Create the led.h file On Arduino IDE with the following content.
    /* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ 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> )=====";
    • Similarly, Create the temperature.h file On Arduino IDE with the following content.
    /* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ const char *HTML_CONTENT_TEMPERATURE = R"=====( <!DOCTYPE html> <html> <head> <title>Arduino Nano 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"; //5-step Degree 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(); } //20-step Degree 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); } // shape 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>Arduino Nano ESP32 - Web Temperature</h1> <canvas id="cvs"></canvas> </body> </html> )=====";
    • Similarly, Create the error_404.h file On Arduino IDE with the following content.
    /* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ 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> )=====";
    • Similarly, Create the error_405.h file On Arduino IDE with the following content.
    /* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-server-multiple-pages */ 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> )=====";
    • Now you have multiple files on Arduino IDE like below:
    Arduino IDE 2 multiple files
    • Click Upload button on Arduino IDE to upload code to Arduino Nano ESP32
    • Access the web pages of Arduino Nano ESP32 board via web browser one by one as before. You will see all web page as below:
    Arduino Nano ESP32 multiple web page