26  ESP32 web servers

26.1 Introduction

In this tutorial, we will learn how to use the ESP32 as a simple web server.

Instead of sending data over the serial monitor, the ESP32 will create its own Wi-Fi network and host a small web page that you can open from your phone or laptop. This web page can:

  • display information (for example, temperature and humidity), and
  • receive input (for example, a button click to turn an led on or off).

We will focus on two examples:

  1. A web server that shows temperature and humidity from the SHT31 sensor.
  2. A web server that controls the built-in led.

Both examples work without any external Wi-Fi network. The ESP32 itself creates the Wi-Fi network.

26.2 SHT31 on web server

Here is the code for reading temperature and humidity values from the SHT31 sensor and displaying them on a web page.

Download code
#include <Arduino.h>
#include <Wire.h>
#include <WiFi.h>
#include <WebServer.h>
#include "Adafruit_SHT31.h"

// ── settings for students to change ───────────────────────────────
// wifi network name created by the esp32 (each student should use a different name)
const char* apSsid     = "esp32_sht31_student_1";
// device name shown on the web page
const char* deviceName = "student_1";
// ──────────────────────────────────────────────────────────────────

// sht31 sensor object
Adafruit_SHT31 sht31 = Adafruit_SHT31();

// web server on port 80
WebServer server(80);

// build and send web page
void handleRoot() {
  // read temperature and humidity
  float temperature = sht31.readTemperature();
  float humidity    = sht31.readHumidity();

  // prepare strings for display
  String tempStr = "n/a";
  String humStr  = "n/a";

  if (!isnan(temperature)) {
    tempStr = String(temperature, 1); // 1 decimal place
  }
  if (!isnan(humidity)) {
    humStr = String(humidity, 1);     // 1 decimal place
  }

  // simple html page
  String page;
  page += "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  page += "<meta http-equiv='refresh' content='1'>";  // refresh every 1 second
  page += "<title>";
  page += deviceName;
  page += " - SHT31</title>";
  page += "<style>";
  page += "body{font-family:Arial,Helvetica,sans-serif;max-width:400px;margin:20px auto;}";
  page += "</style></head><body>";

  page += "<h2>esp32 sensor: ";
  page += deviceName;
  page += "</h2>";

  page += "<p><b>temperature:</b> ";
  page += tempStr;
  page += " &deg;C</p>";

  page += "<p><b>humidity:</b> ";
  page += humStr;
  page += " %</p>";

  page += "<p style='margin-top:20px;font-size:12px;color:#555;'>";
  page += "this page refreshes once per second.";
  page += "</p>";

  page += "</body></html>";

  server.send(200, "text/html", page);
}

// handle unknown paths
void handleNotFound() {
  server.send(404, "text/plain", "not found");
}

void setup() {
  // start serial for debug
  Serial.begin(115200);
  delay(500);

  // start sht31 on i2c address 0x44
  if (!sht31.begin(0x44)) {
    Serial.println("sht31 not found");
  }

  // set wifi to access point mode
  WiFi.mode(WIFI_AP);

  // create open access point (no password)
  WiFi.softAP(apSsid);

  // print access point info
  IPAddress ip = WiFi.softAPIP();
  Serial.print("access point ssid: ");
  Serial.println(apSsid);
  Serial.print("access point ip:   ");
  Serial.println(ip);

  // define http routes
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  // start web server
  server.begin();
  Serial.println("web server started");
}

void loop() {
  // handle incoming http requests
  server.handleClient();
}

26.3 Toggle LED on web server

Here is the code for toggling the builtin LED from a web page.

Download code
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>

// ── settings for students to change ───────────────────────────────
// wifi network name created by the esp32 (each student should use a different name)
const char* apSsid = "esp32_led_student_1";
// ──────────────────────────────────────────────────────────────────

// web server on port 80
WebServer server(80);

// remember led state
bool ledState = false;

// build and send web page
void handleRoot() {
  String page;
  page += "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  page += "<title>esp32 led control</title>";
  page += "<style>";
  page += "body{font-family:Arial,Helvetica,sans-serif;max-width:400px;margin:20px auto;}";
  page += "button{font-size:16px;padding:8px 16px;}";
  page += "</style></head><body>";

  page += "<h2>esp32 led control</h2>";

  page += "<p><b>led state:</b> ";
  page += (ledState ? "ON" : "OFF");
  page += "</p>";

  page += "<form action=\"/toggle\" method=\"GET\">";
  page += "<button type=\"submit\">toggle led</button>";
  page += "</form>";

  page += "</body></html>";

  server.send(200, "text/html", page);
}

// toggle led and show main page
void handleToggle() {
  ledState = !ledState;
  digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
  handleRoot();
}

// handle unknown paths
void handleNotFound() {
  server.send(404, "text/plain", "not found");
}

void setup() {
  // start serial for debug
  Serial.begin(115200);
  delay(500);

  // set built-in led pin
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // set wifi to access point mode
  WiFi.mode(WIFI_AP);

  // create open access point (no password)
  WiFi.softAP(apSsid);

  // print access point info
  IPAddress ip = WiFi.softAPIP();
  Serial.print("access point ssid: ");
  Serial.println(apSsid);
  Serial.print("access point ip:   ");
  Serial.println(ip);

  // define http routes
  server.on("/", handleRoot);
  server.on("/toggle", handleToggle);
  server.onNotFound(handleNotFound);

  // start web server
  server.begin();
  Serial.println("web server started");
}

void loop() {
  // handle incoming http requests
  server.handleClient();
}