Utility Bar

ESP32 DHT11/DHT22 Web Server With Temperature & Humidity

ESP32 DHT11/DHT22 Web Server Tutorial

Ethan Zaitchik |

Table of Contents

    The ESP32 is a powerful microcontroller with built-in Wi-Fi, making it ideal for real-world IoT monitoring systems. In this guide, we expand on the basic web server concept by adding a temperature and humidity sensor, then displaying live environmental data directly in a browser.

    You’ll also learn how to trigger an external LED when certain environmental conditions are met, forming the foundation of climate alerts, greenhouse automation, and smart monitoring systems. If you're looking for a guide that covers only blinking a LED, check our our ESP32 LED Blink tutorial.

    New to ESP32? Start with our ESP32 Beginner Tutorials or follow our guide on Installing and Configuring Arduino IDE for ESP32 before continuing.
    What you’ll build:
    An ESP32 that:
    • Connects to your Wi-Fi network (Station Mode)
    • Reads live temperature and humidity data from a DHT sensor
    • Displays that data on a browser-based dashboard
    • Automatically turns on an LED when temperature exceeds a defined threshold

    How This Project Works

    This project builds directly on the ESP32 web server foundation that we covered in our previous guide.

    Instead of just displaying static text, the ESP32 will:

    • Read temperature and humidity from a DHT sensor
    • Evaluate environmental conditions using simple logic
    • Control an external LED based on a threshold
    • Generate a dynamic HTML page showing live data

    Communication Flow:

    Computer → Router → ESP32 → Sensor → ESP32 → Browser

    ESP32 Temperature Humidity Web Server Data Flow
    All devices must be connected to the same Wi-Fi network. If the ESP32 connects to a different subnet or guest network, your browser will not be able to access it.

    This is how real IoT systems operate. Sensors collect data, microcontrollers process it, and web interfaces provide human-readable monitoring dashboards.

    Understanding the DHT Temperature & Humidity Sensor

    To measure environmental data, we will use a digital temperature and humidity sensor from the DHT family. We'll be using the DHT22, but the DHT11 can also work by changing the defined sensor type in the code.

    Inside the module are two separate sensing elements. A thermistor is used to measure temperature, and a capacitive humidity sensor is used to measure moisture in the air. The humidity sensor works by detecting changes in capacitance as water vapour in the air alters the electrical properties of a tiny polymer layer. The temperature reading is measured electronically and converted into a digital signal by a small internal microcontroller. This means the ESP32 does not measure voltage directly. Instead, it receives already processed digital data over a single data pin. 

    One important limitation to be aware of is the 1sampling rate. The DHT sensors update relatively slowly and should only be read about once every 2 seconds. Reading it too quickly can cause invalid or repeated values.

    If you're building a monitoring system that needs better accuracy or wider environmental range, choose the DHT22. For basic experimentation, the DHT11 works perfectly.

    Hardware Required

    Get All the Parts You Need

    This tutorial is part of our comprehensive ESP32 learning series. Instead of buying components individually, save time and money with our ESP32 Basic Starter Kit. It includes everything you need for this lesson and 20+ other projects.

    What's Included: ESP32 board, OLED display, sensors (DHT11, PIR, LDR), relay module, buzzers, LEDs, buttons, breadboard, resistors, and all cables, plus access to our complete lesson plans.

    View ESP32 Starter Kit →

    Wiring the Circuit

    The DHT sensor uses a single digital data line to communicate with the ESP32.

    DHT Sensor Connections

    • VCC → 3.3V
    • GND → GND
    • DATA → GPIO 5

    LED Connections

    • Anode (long leg) → GPIO 4 through 220Ω resistor
    • Cathode → GND
    The 220Ω resistor protects the LED from excessive current.
    ESP32 DHT22 LED Wiring Diagram Web Server

    Installing Required Libraries

    Before uploading the sketch, install the required libraries in the Arduino IDE.

    1. Within the Arduino IDE, click Sketch
    2. Click Include Library
    3. Click Manage Libraries
    4. In the Library Manager search box, search DHT sensor library
    5. Under DHT sensor library by Adafruit click Install
    DHT Sensor Library Install Adafruit Arduino IDE
    The WiFi and WebServer libraries are already included with the ESP32 board package.

    Create & Upload the Complete Sketch

    This sketch connects to Wi-Fi, reads the DHT sensor, controls an LED when temperature exceeds a defined threshold, and serves a live dashboard page.

    #include <WiFi.h>
    #include <WebServer.h>
    #include "DHT.h"
    
    // ===== WiFi Credentials =====
    const char* ssid = "YOUR_WIFI_NAME"; // Replace these
    const char* password = "YOUR_WIFI_PASSWORD"; // Replace these
    
    // ===== DHT Setup =====
    #define DHTPIN 5
    #define DHTTYPE DHT22   // Change to DHT11 if using DHT11
    DHT dht(DHTPIN, DHTTYPE);
    
    // ===== LED Setup =====
    #define LED_PIN 4
    float temperatureThreshold = 30.0; // Celsius
    
    WebServer server(80);
    
    void handleRoot() {
    
      float humidity = dht.readHumidity();
      float temperature = dht.readTemperature();
    
      if (temperature > temperatureThreshold) {
        digitalWrite(LED_PIN, HIGH);
      } else {
        digitalWrite(LED_PIN, LOW);
      }
    
      String html = "<!DOCTYPE html><html>";
      html += "<head><meta http-equiv='refresh' content='5'/>";
      html += "<title>ESP32 Climate Monitor</title></head>";
      html += "<body style='font-family: Arial; text-align:center;'>";
      html += "<h1>ESP32 Temperature & Humidity Monitor</h1>";
      html += "<p>Temperature: " + String(temperature) + " °C</p>";
      html += "<p>Humidity: " + String(humidity) + " %</p>";
      html += "</body></html>";
    
      server.send(200, "text/html", html);
    }
    
    void setup() {
    
      Serial.begin(115200);
      dht.begin();
    
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, LOW);
    
      WiFi.begin(ssid, password);
      Serial.print("Connecting to WiFi");
    
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
    
      Serial.println("");
      Serial.println("Connected!");
      Serial.print("IP Address: ");
      Serial.println(WiFi.localIP());
    
      server.on("/", handleRoot);
      server.begin();
    }
    
    void loop() {
      server.handleClient();
    }

    Testing the System

    1. Open Serial Monitor.
    2. Confirm Wi-Fi connection.
    3. Copy the printed IP address.
    4. Open a browser on the same network.
    5. Enter the IP address.
    ESP32 Web Server Serial Monitor IP Address
    ESP32 DHT22 Web Server Temperature & Humidity Readings

    You should now see live temperature and humidity readings updating automatically.

    Try warming the sensor gently with your hand. When temperature crosses 30°C, the LED should illuminate.

    Below Threshold

    ESP32 DHT22 Web Server LED Off

    Above Threshold

    ESP32 DHT22 Web Server LED On

    Understanding the Code

    WiFi Credentials

    Your network name and password are stored at the top of the sketch:

    const char* ssid = "YOUR_WIFI_NAME";
    const char* password = "YOUR_WIFI_PASSWORD";

    These values allow the ESP32 to connect to your local wireless network. Replace them with your actual router credentials before uploading the sketch.

    Including Required Libraries

    #include <WiFi.h>
    #include <WebServer.h>
    #include "DHT.h"

    Three libraries power this project:

    • WiFi.h handles wireless connectivity.
    • WebServer.h creates a lightweight HTTP server on the ESP32.
    • DHT.h allows communication with the DHT temperature and humidity sensor.

    DHT22 Sensor Configuration

    #define DHTPIN 5
    #define DHTTYPE DHT22

    This section defines which GPIO pin the sensor is connected to and specifies the sensor model. If you are using a DHT11 instead of a DHT22, simply change the sensor type definition.

    The line below creates the sensor object used throughout the program:

    DHT dht(DHTPIN, DHTTYPE);

    LED Setup and Threshold

    #define LED_PIN 4
    float temperatureThreshold = 30.0;

    The temperatureThreshold variable defines the trigger point in degrees Celsius. When the measured temperature exceeds 30°C, the LED turns on. Otherwise, it remains off.

    Using a variable instead of a hardcoded value makes it easy to adjust the trigger point later.

    Creating the Web Server

    WebServer server(80);

    This initializes a web server that listens on port 80, which is the standard HTTP port used by web browsers.

    Reading Sensor Data

    Inside the handleRoot() function, the ESP32 reads live data from the sensor:

    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();

    Each time a browser loads the page, these two lines request fresh temperature and humidity values from the DHT sensor. The readings are stored in variables so they can be displayed and used for decision making.

    Temperature-Based LED Logic

    if (temperature > temperatureThreshold) {
    digitalWrite(LED_PIN, HIGH);
    } else {
    digitalWrite(LED_PIN, LOW);
    }

    This conditional statement checks if the temperature exceeds the defined threshold. If it does, the LED turns ON. If not, it remains OFF.

    You can modify this conditional statement to trigger when humidity exceeds a certain threshold. Replace temperature with humidity in the comparison, and change temperatureThreshold to a new variable such as humidityThreshold to reflect the new trigger condition.

    Building the Dynamic HTML Page

    Instead of storing a static webpage, the ESP32 builds the entire HTML document dynamically using string concatenation.

    String html = "";
    html += "<!DOCTYPE html><html>";

    Each line adds more content to the page before it is sent to the browser.

    Meta Tags and Auto Refresh

    html += "<head>";
    html += "<meta charset-\"UTF-8\">";
    html += "<meta name
    =\"viewport\" content=\"width=device-width, initial-scale=1.0\">";
    html += "<meta http-equiv=\"refresh\" content=\"5\">";

    These lines include UTF-8 character encoding for proper symbol display (°C), viewport settings for mobile responsiveness and forces the browser to refresh every 5 seconds. The refresh triggers a new sensor reading, keeping the displayed values up to date automatically.

    Modern CSS Styling

    Your updated version includes embedded CSS to create a clean card-style layout:

    body{ margin:0; font-family:Arial,sans-serif; background:linear-gradient(135deg,#eef2f3,#dfe9f3); text-align:center; }

    This styling:

    • Adds a soft gradient background
    • Centers all content
    • Uses a responsive card layout with rounded corners and shadow

    The result is a professional-looking interface rather than plain text output.

    Dynamic Temperature Colour

    One of the most important upgrades in your new code is dynamic colour logic:

    html += ".temp{color:" + String(temperature > temperatureThreshold ? "#e53935" : "#ff7043") + ";}";

    This uses a conditional (ternary) operator inside the HTML builder.

    • If the temperature exceeds the threshold → the value appears red.
    • If not → it appears orange.

    This visual feedback mirrors the LED behaviour, giving both physical and on-screen alerts.

    SVG Icons for Visual Feedback

    Your updated layout includes inline SVG icons for both temperature and humidity:

    <svg class='icon temp' viewBox='0 0 24 24' fill='currentColor'> <path d='M14 14.76V5a2 2 0 10-4 0v9.76A4 4 0 1014 14.76zM12 20a2 2 0 110-4 2 2 0 010 4z'/> </svg>

    Instead of using image files, SVG graphics are embedded directly into the HTML. This has several advantages:

    • No external image loading required
    • Icons scale cleanly on all screen sizes
    • Colours can be controlled using CSS

    The fill="currentColor" property allows the icon colour to automatically match the CSS text colour. That means when the temperature turns red, the thermometer icon turns red as well.

    Sending the Response

    server.send(200, "text/html", charset=UTF-8", html); 

    This line sends an HTTP response back to the browser:

    • 200 means the request was successful.
    • text/html tells the browser the content is a web page.
    • charset=UTF-8 ensures special characters like ° render correctly.
    • html contains the dynamically generated page.

    Setup Function

    The setup() function runs once when the ESP32 powers on.

    Serial.begin(115200);
    dht.begin();

    Serial communication is started for debugging, and the DHT sensor is initialized.

    Configuring the LED

    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);

    The LED pin is configured as an output and set to OFF at startup.

    Connecting to WiFi

    WiFi.begin(ssid, password); 
    Serial.print("Connecting to WiFi");

    This starts the connection process using your router credentials.

    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }

    This loop keeps checking the connection status until the ESP32 successfully joins the network. While waiting, it prints dots to the Serial Monitor.

    Serial.println("Connected!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

    Once connected, the assigned local IP address is displayed. You enter this IP address into your browser to view the climate monitor page.

    Starting the Server

    server.on("/", handleRoot);
    server.begin();

    This tells the ESP32 what to do when someone visits the root URL.

    • "/" represents the homepage.
    • handleRoot is the function that builds and sends the webpage.

    server.begin() starts the web server so it can begin listening for incoming HTTP requests.

    Main Loop

    void loop() {
    server.handleClient();
    }

    The loop continuously checks for incoming browser requests. When a request is detected, it runs handleRoot(), reads the sensor, applies the LED logic, generates the HTML page, and sends it back to the client.

    What Happens Behind the Scenes

    • The ESP32 powers on.
    • The DHT22 sensor and LED are initialized.
    • The ESP32 connects to your WiFi network.
    • The web server starts listening on port 80.
    • A browser sends an HTTP request to the ESP32 IP address.
    • The sensor is read in real time.
    • The temperature is compared against the threshold.
    • The LED is updated accordingly.
    • A fully styled HTML page is generated dynamically.
    • The page is sent back to the browser.
    • The browser refreshes every 5 seconds and repeats the cycle.

    Even though this system runs on a small embedded device, it follows the same architecture as professional web applications: server-side processing and client-side rendering.

    Why this matters
    This project combines environmental sensing, conditional logic, wireless networking, and live browser monitoring into a single embedded system. Mastering this structure forms the foundation of most ESP32 IoT applications.

    Expanding the Project

    This simple LED can be replaced with more advanced outputs:

    • Relay module to control fans or heaters
    • Buzzer for audible alerts
    • Transistor-driven high-power loads
    • Data logging to SD card
    • Cloud-based logging platforms

    You can also improve the dashboard interface by:

    • Adding colour indicators (red when above threshold)
    • Displaying LED status
    • Adding buttons for manual override
    • Styling the page with CSS
    At this stage, you’ve built the core of an IoT environmental monitoring system.

    Adding Simple Data Logging (Serial Monitor)

    To log readings for debugging or testing, add this inside handleRoot():

    Serial.print("Temp: ");
    Serial.print(temperature);
    Serial.print(" C | Humidity: ");
    Serial.print(humidity);
    Serial.println(" %");
    

    Now every browser refresh also logs the values in the Serial Monitor.

    Common Issues & Troubleshooting

    1. ESP32 Not Connecting to Wi-Fi

    • Double-check SSID and password.
    • Ensure 2.4GHz network is enabled (ESP32 does not support 5GHz).
    • Make sure firewall settings aren’t blocking local devices.

    2. Sensor Returning “NaN”

    • Check wiring.
    • Confirm correct sensor type (DHT11 vs DHT22).
    • Ensure 10kΩ pull-up resistor is installed.

    3. Web Page Not Loading

    • Confirm devices are on the same Wi-Fi network.
    • Re-check the printed IP address.
    • Disable mobile data if accessing from a phone.

    Project Summary

    In this guide, you built an ESP32-based environmental monitoring system that:

    • Connects to Wi-Fi
    • Hosts a local web server
    • Reads temperature and humidity
    • Displays live data in a browser
    • Uses conditional logic to control an LED

    You now understand:

    • How embedded web servers operate
    • How sensors integrate with networked systems
    • How to apply threshold-based automation
    • How AND/OR logic affects control behaviour
    This structure: Sensor → Logic → Output → Web Interface, is the foundation of nearly every IoT system.

    From here, you can expand into:

    • Cloud-connected monitoring
    • Remote alerts
    • Home automation systems
    • Industrial environment tracking

    You’ve now moved beyond basic web serving and into true environmental IoT system design.

    ESP32 IoT Systems Pathway

    Leave a comment