My ESP32 Web Server Project

How I built my first web server on a microcontroller

What I Decided to Build

So I wanted to try making a web server using an ESP32 board we from the machine making week and i will be using the same board in my final project. The goal was pretty simple - make the ESP32 connect to my WiFi and serve a basic webpage that I could access from my computer. Nothing fancy, just wanted to see if I could get it working!

for that i needed to understand the code so a used this blog to teach me how the code are BLOG LINK. Plus, I was curious about how microcontrollers handle web requests.

What I Used

ESP32 WROOM Board

Project Setup

This is the main brain - it's got WiFi built in which is perfect for web server stuff

USB Cable

Project Setup

Just needed this to program the board and power it while testing

My Home WiFi

Project Setup

The ESP32 connects to this so I can access the web server from my laptop

The "Wiring" (Spoiler: There Isn't Any)

This was probably the easiest project I've done wiring-wise - I literally just plugged the ESP32 into my computer via USB. That's it!

What How I Connected It Why
ESP32 Board USB cable to my computer Programming and power
My WiFi Network DESKTOP-52F3CL3 6029 (my laptop hostspot) So the ESP32 can get connect
My Laptop Same WiFi network To access the web server
Note to self: I hardcoded my WiFi password in the code, which isn't great for security. Should probably figure out a better way to do this for future projects!

The Code I Wrote

I kept the code pretty simple since this was my first time doing web server stuff on a microcontroller:

My ESP32 Web Server Code
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>

const char* ssid = "DESKTOP-52F3CL3 6029";
const char* password = "4,929F2w";

//Creating web server object
AsyncWebServer server(80);

void setup() {
   // Initialize Serial for debugging
  Serial.begin(115200);
  delay(1000);
 
  Serial.println("\nConnecting to WiFi...");
 
  // Connect to Wi-Fi network
  WiFi.mode(WIFI_STA); 
  WiFi.begin(ssid, password);
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  server.on("/",HTTP_GET,[](AsyncWebServerRequest *request){
    request->send(200,"text/html","Manzi Interface IP Test");
  });
  
  server.begin();
}

void loop() {
  // Empty loop - AsyncWebServer handles requests automatically
}

Breaking Down What I Did

Libraries: I needed to include WiFi and web server libraries. The AsyncWebServer one is pretty cool because it handles multiple requests at once.

WiFi Credentials: Yeah, I just put my network name and password right in the code. Not ideal but it works for testing.

Server Setup: I created the server object to listen on port 80 (standard web port).

Connection Process: The ESP32 tries to connect to WiFi and prints dots while it's trying. Once connected, it shows the IP address.

The Webpage: When someone visits the root page ("/"), it just shows "Manzi Interface IP Test". Simple but it proves everything's working!

How I Tested It

Here's exactly what I did to make sure everything was working:

  1. Uploaded the code: Used Arduino IDE to flash the program to my ESP32
  2. Project Setup
  3. Opened Serial Monitor: Set it to 115200 baud to see what was happening
  4. Watched it connect: Saw the dots appear as it tried to connect to WiFi
  5. Got the IP address: Once connected, it printed something like "192.168.1.150"
  6. Project Setup
  7. Opened Chrome: Typed the IP address in my browser
  8. Success! Saw "Manzi Interface IP Test" appear on the webpage
  9. Project Setup

What I Learned

This was actually way easier than I thought it would be! A few things that surprised me:

  • The ESP32 handles web requests really well for such a small board
  • The AsyncWebServer library does most of the heavy lifting
  • WiFi connection is pretty reliable once you get the credentials right
  • You can access the server from any device on the same network
  • The serial monitor is super helpful for debugging network issues

This project got me excited about IoT development. There's so much you can do once you have a microcontroller connected to the internet!

Next time I'm definitely going to try adding some LEDs that I can control from the webpage. That would be pretty cool!

My ESP32 LED Control Web Interface

Taking it up a notch - controlling hardware through the web!

What I Decided to Build This Time

After getting my basic web server working, I thought "okay, now let's make it actually DO something useful!" So I decided to add LED control to my ESP32 web interface. The idea was simple - create buttons on a webpage that can turn an LED on and off remotely.

I wanted to keep building on what I learned from the basic server project, but add some actual hardware interaction. Plus, being able to control things from my phone or laptop seemed like a fun next step.

What I Used This Time

ESP32 WROOM Board

ESP32 Board

Same trusty ESP32 - this time actually using one of its GPIO pins for output control

LED

LED Component

Just a basic LED

Jumper Wires

Jumper Wires

A couple of jumper wires to connect the LED to GPIO pin 19

How I Wired Everything Up

just connecting an LED to one of the ESP32's pins.

Component ESP32 Pin Notes
LED Positive (Anode) GPIO 19 Through a 220Ω resistor
LED Negative (Cathode) GND Direct connection to ground
Power USB Still powered from computer
Jumper Wires

The Code - Now With HTML Embedded!

This time my code got a lot more interesting. I embedded a full HTML page right inside the Arduino code, which was pretty neat:

ESP32 LED Control Code
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>

// Network Configuration
const char* ssid = "DESKTOP-52F3CL3 6029";
const char* password = "4,929F2w";

// Define LED pin
const int ledPin = 19;  

// Web server on port 80
AsyncWebServer server(80);

// HTML for the web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <title>MAnzi Fablab ESP32 LED Control</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 2.4rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .button {display: inline-block; background-color: #4CAF50; border: none;
      border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none;
      font-size: 30px; margin: 2px; cursor: pointer;}
    .button2 {background-color: #D11D53;}
  </style>
</head>
<body>
  <h2>Manzi LED Control</h2>
  <p>LED State: <span id="state">%STATE%</span></p>
  <p><a href="/on"><button class="button">ON</button></a></p>
  <p><a href="/off"><button class="button button2">OFF</button></a></p>
</body>
</html>
)rawliteral";

// Variable to store LED state
String ledState = "OFF";

// Function to process HTML placeholders
String processor(const String& var) {
  if(var == "STATE") {
    return ledState;
  }
  return String();
}

void setup() {
  // Initialize Serial for debugging
  Serial.begin(115200);
  delay(1000);
 
  // Initialize LED pin as output
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);  
 
  Serial.println("\nConnecting to WiFi...");
 
  // Connect to Wi-Fi network
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
 
  // Route for LED ON
  server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, HIGH);
    ledState = "ON";
    request->send_P(200, "text/html", index_html, processor);
  });
 
  // Route for LED OFF
  server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, LOW);
    ledState = "OFF";
    request->send_P(200, "text/html", index_html, processor);
  });
  
  // Start server
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // Still empty - AsyncWebServer handles everything
}

The Cool New Stuff I Added

Embedded HTML: Instead of just sending plain text, I created a full HTML page with styling! The `R"rawliteral( ... )rawliteral"` syntax lets me write multi-line HTML right in the C++ code.

LED Pin Control: Added `pinMode()` and `digitalWrite()` to actually control hardware. GPIO 19 gets set up as an output pin.

Multiple Routes: Now I have three different URLs the server responds to: "/" for the main page, "/on" to turn the LED on, and "/off" to turn it off.

Dynamic Content: The `%STATE%` placeholder gets replaced with the actual LED state using my `processor()` function.

CSS Styling: Added some basic CSS to make the buttons look decent and the page responsive on mobile.

Video Demo