Embedded System Project 8: ESP32 Web Server

Michelle Lim
8 min readApr 2, 2023

--

Hi, I’m Michelle and today I’ll be continuing my blog series of the embedded systems project! ✨🤩 (You can read the previous blog here 🤗)

The eighth project I’ll be doing is about ESP32 Web Server. A fun fact to start with, web servers are actually buildable with an ESP32 microcontroller, it doesn't need a set of computers with large powers placed in a server room. The web server experimented in this project will be connected to a WiFi network thus is accessible by devices or other computers from far locations via browser. In this project, we’ll be specifically building a room monitoring and controlling system, with these criterias:

  1. The ESP32 is equipped with a temperature sensor placed in a room, connected to WiFi. In this project, I’ll be using the BME280 sensor.
  2. The ESP32 is connected to a drive fan motor. In this project, the fans are modeled using LEDs.
  3. Information regarding temperature is accessible from a distance via browser on PC or mobile phones.
  4. User can turn on and off the fan from afar using browser.

Hence by using the system, the user can control the fan according to the room monitoring result. For instance, the user monitors the room condition before entering the room. If it is too hot, the user can then turn on the fan before entering the room. 😄

I’ll be referring from two of the tutorials provided from randomnerdtutorials.com regarding ESP32 Web Server and ESP32 Web Server with BME280 — Advanced Weather Station. You may check it out to understand more about the modules. 😉

Project: Introduction

As explained earlier, we’ll be building a room monitoring and controlling system in this project.

The components we’ll be using are listed below.

  1. ESP32 Development Board
  2. BME280 Sensor
  3. Micro-USB Cable
  4. Breadboard
  5. 2 5mm LEDs of preferably different colors
  6. 2 330Ω resistors
  7. A device with browser (you can use the same laptop that is used for the Arduino IDE)
  8. Male-to-Male jumper wires
  9. Laptop/PC with Arduino IDE installed and set

Project: Schematics

The schematics we’ll be using in this project is as shown on the picture below.

Schematic for this project

Pinout:

  • ESP32 3V3 pin — positive row of the breadboard (grey wire)
  • ESP32 GND pin — negative row of the breadboard (yellow wire)
  • LED1 positive pole — ESP32 GPIO4 (purple wire)
  • LED1 negative pole — 330Ω Resistor1
  • 330Ω Resistor1 — negative row of the breadboard
  • LED2 positive pole — ESP32 GPIO5 (orange wire)
  • LED2 negative pole — 330Ω Resistor2
  • 330Ω Resistor2 — negative row of the breadboard
  • BME280 VIN pin — positive row of the breadboard (brown wire)
  • BME280 GND pin — negative row of the breadboard (green wire)
  • BME280 SDA pin — ESP32 GPIO21 (red wire)
  • BME280 SCL pin — ESP32 GPIO22 (blue wire)

You should have the arrangement like shown below.

My arrangements for reference

Project: Code

I combined the two codes from both tutorials, resulting to the code shown below. You can just copy, compile, and upload the code. 😉👍

Note: Don’t forget to replace the values for the network credentials (WiFi SSID and password) ☑️

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

//uncomment the following lines if you're using SPI
/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// Replace with your network credentials
const char* ssid = "change_to_your_wifi_ssid";
const char* password = "change_to_your_wifi_password";

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

// Variable to store the HTTP request
String header;

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

// Auxiliar variables to store the current output state
String outputLED1State = "off";
String outputLED2State = "off";

// Assign output variables to GPIO pins
const int LED1 = 4;
const int LED2 = 5;

void setup() {
Serial.begin(115200);
bool status;

// Initialize the output variables as outputs
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
// Set outputs to LOW
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);

// default settings
// (you can also pass in a Wire library object like &Wire2)
//status = bme.begin();
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}

// 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 /4/on") >= 0) {
Serial.println("GPIO 4 on");
outputLED1State = "on";
digitalWrite(LED1, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
Serial.println("GPIO 4 off");
outputLED1State = "off";
digitalWrite(LED1, LOW);
} else if (header.indexOf("GET /5/on") >= 0) {
Serial.println("GPIO 5 on");
outputLED2State = "on";
digitalWrite(LED2, HIGH);
} else if (header.indexOf("GET /5/off") >= 0) {
Serial.println("GPIO 5 off");
outputLED2State = "off";
digitalWrite(LED2, 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>");

// Display current state, and ON/OFF buttons for GPIO 4
client.println("<p>LED1 - State " + outputLED1State + "</p>");
// If the outputLED1State is off, it displays the ON button
if (outputLED1State=="off") {
client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
}

// Display current state, and ON/OFF buttons for GPIO 5
client.println("<p>LED2 - State " + outputLED2State + "</p>");
// If the outputLED2State is off, it displays the ON button
if (outputLED2State=="off") {
client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
}
client.println("</body></html>");
// CSS to style the table
client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}");
client.println("table { border-collapse: collapse; width:35%; margin-left:auto; margin-right:auto; }");
client.println("th { padding: 12px; background-color: #0043af; color: white; }");
client.println("tr { border: 1px solid #ddd; padding: 12px; }");
client.println("tr:hover { background-color: #bcbcbc; }");
client.println("td { border: none; padding: 12px; }");
client.println(".sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px; }");


// Web Page Heading
client.println("</style></head><body><h1>ESP32 with BME280</h1>");
client.println("<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>");
client.println("<tr><td>Temp. Celsius</td><td><span class=\"sensor\">");
client.println(bme.readTemperature());
client.println(" *C</span></td></tr>");
client.println("<tr><td>Temp. Fahrenheit</td><td><span class=\"sensor\">");
client.println(1.8 * bme.readTemperature() + 32);
client.println(" *F</span></td></tr>");
client.println("<tr><td>Pressure</td><td><span class=\"sensor\">");
client.println(bme.readPressure() / 100.0F);
client.println(" hPa</span></td></tr>");
client.println("<tr><td>Approx. Altitude</td><td><span class=\"sensor\">");
client.println(bme.readAltitude(SEALEVELPRESSURE_HPA));
client.println(" m</span></td></tr>");
client.println("<tr><td>Humidity</td><td><span class=\"sensor\">");
client.println(bme.readHumidity());
client.println(" %</span></td></tr>");
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("");
}
}

The code explanation is written on the //comment section on the code block above. However, if you wish to understand the code deeper, you can read the tutorials from randomnerdtutorials.com as mentioned before. 😉

After uploading the code, open the serial monitor at a baud rate of 115200. You should then get the host IP address, as shown in the picture below.

After getting the IP address, copy it and open it on your browser. You should then see the web server we’ve just built displayed on your browser, as shown on the picture below. 😆

Display of room monitoring and controlling system on browser

As seen above, there are buttons for turning on and off the LEDs (the modeled fans) and a table showing measurement and value read from the BME280 sensor. 😲😆

I then tried to click on the buttons to control the LEDs and here’s the result attached in the gif below.

Result of monitoring and controlling of LED via browser

So yea, that’s the end of our eighth Embedded System Project: ESP32 Web Server. (yeah!! 🥳) Stay tune for the next projects and stay safe and healthy 🥰

--

--