ESP32 – Web Server – DHT22 Temperature – Humidity Monitoring

Introduction: ESP32 – Web Server – DHT22 Temperature – Humidity Monitoring

This experimentation is about creating an ESP32 (Station Mode), stand-alone HTTP web server and processing / populating DHT22 sensor temperature / humidity value at regular interval on HTTP client interface. The web page is developed by using HTML, AJAX and CSS as the subject of “Weather Monitoring”. It uses Google Gauge for indicating the status / warning to end user.

Visit the "VESZLE - The Art Of Electronics" you tube channel for further information and videos.\

ESP32 – Web Server – DHT22 Temperature – Humidity Monitoring implementation video

Step 1: Abstract

The ESP32 is constructed with Xtensa dual-core (or single-core) 32-bit RISC architecture, operating at 160MHz or 240MHz, with up to 520KiB internal SRAM, integrated with Wi-Fi (802.11 b/g/n) and Bluetooth (v4.2 BR/EDR and BLE (shares the radio with Wi-Fi). The ESP32 provides peripheral interfaces like ADC, DAC, touch sensors, SPI, I2C, I2S, UART, CAN, PWM etc. The ESP32 supports all IEEE 802.11 standard security feature (WFA, WPA/WPA2 and WAPI), and cryptographic hardware acceleration (AES, RSA, SHA-2, ECC, RNG etc). It supports wake up from GPIO / Sensor interrupts, timers and 5uA deep sleep current consumption.

ESP32 Wi-Fi interface provides

· Station Mode

· Soft Access Point Mode

· Both at the same time, (Station + Access Point)

This experimentation is about creating an ESP32 (Station Mode), stand-alone HTTP web server and processing / populating DHT22 sensor temperature / humidity value at regular interval on HTTP client interface. The web page is developed by using HTML, AJAX and CSS as the subject of “Weather Monitoring”. It uses Google Gauge for indicating the status / warning to end user.

Step 2: Reference

“ESP32 – Getting Started MicroPython -- on Board Blink LED” Instruct-able / You-tube by PugazhM

“ESP32-HTTP-Web-Server-HTML-CSS-Simple-Counter” Instruct-able / You-tube by PugazhM

“ESP32-Web-Server-HTML-AJAX-Hospital-Visitors-Counter” Instruct-able / You-tube by PugazhM

MicroPython Network TCP sockets

The “” driver library. ( LCD Assistant tool. (

“ESP32-- 128x32 OLED – SSD1306 Display Interface” Instruct-able / You-tube by PugazhM

“Raspberry Pi Pico -- DHT22 (AM2302) Temperature Sensor -- OLED Display” Instruct-able / You-tube by PugazhM

Step 3: Components

ESP32 Development Board

Micro USB Cable

128x32 OLED Display Module

DHT22 (AM2302) = 1 No

10K Resistor = 1 No

Step 4: Schematic

DHT22 temperature / humidity sensor, 128x32 OLED and ESP32 is used for hardware construction as illustrated above.

Make use of the below links for HTTP webserver implementation and DHT22 sensor description

Step 5: ESP32 Weather Server System Overview

The temperature / humidity measurement and “web-server” deployment is illustrated above

ESP32 act as “web-server” and Google Chrome running on a laptop act as a “web-client”

timer_1 is initiated and toggles the on-board LED at regular interval, via “BlinkLED()” call back function

timer_2 is initiated and updates the temperature / humidity variables at a regular interval, via “ReadUpdateSensor()” call back function. The measure temperature in Celsius is converted into Fahrenheit, Kelvin and Rankine and stored into global variable. OLED display is updated for temperature and humidity values at 5 Sec interval.

Whenever the “web-client” requests data via “HTTP Client Page Request” method, then the “web-server”, will construct the complete web page and then sends back to “web-client”.

Whenever the “web-client” requests data via “HTTP Client Data Request” method, then the “web-server”, will construct the data and then sends back to “web-client”.( Celsius, Fahrenheit, Kelvin, Rankine and Humidity values).

The “web-client” refreshes the “web page” at 1 second’s interval.

Step 6: ESP32 HTTP Web Server GUI

A weather server on a ESP32 “web-server”, with “Temperature / Humidity Monitoring” as theme is illustrated above.

The web page is constructed by using “Font Awesome” fonts and material icons. It also uses google charts.

Font Awesome icons are designed to be simple, modern, friendly, and sometimes quirky. Each icon is reduced to its minimal form, expressing essential characteristics.

The style sheet uses “”, for constructing a web page.

Google chart tools are powerful, simple to use, and free. It provides our rich gallery of interactive charts and data tools.

The “web-server” uses “google chart” Java script “”, for creating gauge tool.

The web page is divided into 5 equal vertical columns. Totally 5 boxes.

A box type drawing which uses icon, fonts and Google Gauge for formulating the “Restaurant Bin Monitoring” GUI.

Google Gauge is used for indicating the status / warning of “temperature / humidity”.

Step 7: ESP32 Web Server MicroPython Program

The timer_one is initialized and callbacks the “BlinkLED” functionality for toggling on board LED at 200mS duration. (frequency = 5)

The timer_two is initialized and callbacks the “ReadUpdateSensor” functionality for updating the temperature / humidity global variables at 5S duration. (frequency = 0.2)

The MicroPython program, first creates and configures the ESP32 as Station Mode, and then connects to the Wi-Fi router using user provided SSID and Password

§ ssid = 'WiFi Router SSID'

§ password = 'WiFi Router Password'

§ station = network.WLAN(network.STA_IF)


§ station.connect(ssid, password)

§ # Wait until the ESP32 get connected to the router

§ while station.isconnected() == False:

§ pass

The MicroPython program creates a stream TCP web-server socket and then binds it into HTTP port 80. Listens from maximum five web clients

§ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

§ s.bind(('', 80))

§ s.listen(5)

The system checks the web-client request at endless while loop.

Whenever the web-server receives the “HTTP Client page request”, then it reconstruct the web page and sends the “HTTP Server Page Response” to web-client.

Whenever the web-server receives the “HTTP Client data request”, then it reconstruct the data and sends to web-client.

 Demonstrates HTML and CSS ESP32 Web server implementation
 Simple Counter usage as "Restaurant Bin Monitoring"
 Simple counter example for counting consumption at regular interval
 ESP32 Web server detection event happens at 0.5 seconds interval,
 And validates / resets against the MIN value
 Web client request at 3 Seconds interval.
 Google Gauge for status / warnning indication
 * The ESP32 onboard LED pin connections
 * On board LED pin to GPI2
 Name:- M.Pugazhendi
 Date:-  18thOct2021
 Version:- V0.1
import machine
from machine import Pin, I2C
import dht
import time
from ssd1306 import SSD1306_I2C
import framebuf
import utime
import dht

from machine import Pin, Timer
import network
import time
import socket

import esp

import gc

ssid = 'WiFi Router SSD'
password = 'WiFi Router Password'

station = network.WLAN(network.STA_IF) # Congigure WLAN as station # Activate the Station
station.connect(ssid, password) # Connect to the router using SSID and password

# Wait until the ESP32 get connected to the router
while station.isconnected() == False:

print('Connection successful')

led = Pin(2, Pin.OUT)
timer_one = Timer(0) # Initialize timer_one. Used for toggling the on-board LED
timer_two = Timer(1) # Initialize timer_two. Used for updating sensor reading variables

toggle = 1
temp_c = 0
temp_f = 0
temp_k = 0
temp_r = 0
humidity = 0

def ReadUpdateSensor(timer_two):
    global temp_c
    global temp_f
    global temp_k
    global temp_r
    global humidity
    T = sensor.temperature()
    H = sensor.humidity()
    # Write the Temperature and Humidity ICON
    fb = framebuf.FrameBuffer(humid, 32, 32, framebuf.MONO_HLSB)
    display.blit(fb, 0, 0)
    #Write Humidity value. Convert the humidity into two decimal places.
    display.text(str('H: ' +"{:0.2f}".format(H)+ "  %",2),40,5)
    #display.text("H: " + str(H) + " %",40,5)
    #Write Temperature value. Convert the temperature into two decimal places.
    display.text(str('T: ' +"{:0.2f}".format(T)+ "  C",2),40,19)
    #display.text("T: " + str(T) + "  C",40,19)
    #Draw the degree symbol. Its 4x4 pixel squire.
    display.fill_rect(113, 18, 4,4, 1)
    #Show display
    temp_c = T
    temp_c = "{:0.2f}".format(T)
    temp_f = ( T * 1.8 ) + 32 # Fahrenheit # T(°F) = T(°C) × 9/5 + 32
    temp_f = "{:0.2f}".format(temp_f)
    temp_k = T + 273.15 # Kelvin # T(K) = T(°C) + 273.15
    temp_k = "{:0.2f}".format(temp_k)
    temp_r = (T + 273.15) * 1.8 # Rankine # T(°R) = (T(°C) + 273.15) × 9/5
    temp_r = "{:0.2f}".format(temp_r)
    humidity = "{:0.2f}".format(H)
def BlinkLED(timer_one):
    global toggle
    if toggle == 1:
        toggle = 0
        toggle = 1

def ConstructWebPage():
  html = """<html>   
    <!-- add the following google font / icon to the webpage -->  
	<link rel="stylesheet" href="" 
	 integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
	<link rel="stylesheet" href="">
	<script type="text/javascript" src=""></script>
	<meta charset="utf-8" />
    * {   
        box-sizing: border-box;   
    body {  
    /* background-color: #76ff03; */ /*Green */
	/* background-color: #76ff03; */ /* Green */
	background-color: #e91e63;
    background-size: cover;  
    .column {   
        /* box toward left of the window screen */  
        float: left;   
        /*divide each counter box in equal size*/  
        /* 4 counters of 20% of screen size*/  
        width: 20%;   
        /*spacing between each box */  
        padding: 4px;   
        padding: 3px;   
        /*background-color: #6e3dff;*/
		background-color: blue;
        color: white;
	    padding: 3px;   
        background-color: #76ff03;   
        color: black;
    .row {   
        /* Specify the margin for the row class */  
        margin: 3px;  
    /* Style the class named block*/  
    .block {   
        padding: 3px;   
        text-align: center;   
        /* background-color: #0100ca; */
		background-color: #76ff03; 		
        color: black;   
    .fa {   
        font-size: 50px;   
	.center {
		position: relative;
		left: 50%;
		top: 50%;
		transform: translate(-60%, +1%);
		var temp_c=0;
		var temp_f=0;
		var temp_k=0;
		var temp_r=0;
		var humidity=0;
       var ajaxRequest = new XMLHttpRequest();   
       function ajaxLoad(ajaxURL)  
       { 'GET',ajaxURL,true);  
        ajaxRequest.onreadystatechange = function()  
         if(ajaxRequest.readyState == 4 && ajaxRequest.status==200)  
            var ajaxResult = ajaxRequest.responseText;  
            var tmpArray = ajaxResult.split("|");
            document.getElementById('temp_c_span').innerHTML = String(tmpArray[0]) +" \xB0C";
			document.getElementById('temp_f_span').innerHTML = String(tmpArray[1]) +" \xB0F" ;			
			document.getElementById('temp_k_span').innerHTML = String(tmpArray[2]) +" K";
			document.getElementById('temp_r_span').innerHTML = String(tmpArray[3]) +" \xB0R" ;
			document.getElementById('humidity_span').innerHTML = String(tmpArray[4]) + " %";
			temp_c = tmpArray[0];
			temp_f = tmpArray[1];
			temp_k = tmpArray[2];
			temp_r = tmpArray[3];
			humidity = tmpArray[4];
      google.charts.load('current', {'packages':['gauge']});
     function drawChart() {

        var gauge1_data = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ["\xB0C", 30],
		var gauge2_data = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ["\xB0F", 800],
        var gauge3_data = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ['K', 180],
		var gauge4_data = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ["\xB0R", 150],
		var gauge5_data = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ['%', 450],
        var gauge1_options = {
          width:800, height: 240,
		  min: -10, 
		  max: +50,
		  yellowFrom:32, yellowTo: 42,
          redFrom: 42, redTo: 50,
          minorTicks: 5
        var gauge2_options = {
          width:800, height: 240,
		  min: 10, 
		  max: 130,
		  yellowFrom:90, yellowTo: 108,
          redFrom: 108, redTo: 130,         
          minorTicks: 5
        var gauge3_options = {
          width:800, height: 240,
		  min: 260, 
		  max: 330,
		  yellowFrom:305, yellowTo: 315,
          redFrom: 315, redTo: 330,
          minorTicks: 5
        var gauge4_options = {
          width:800, height: 240,
		  min: 470, 
		  max: 590,
		  yellowFrom:547, yellowTo: 567,
          redFrom: 567, redTo: 590,

          minorTicks: 5
		var gauge5_options = {
          width:800, height: 240,
		  min: 0, 
		  max: 100,
          redFrom: 50, redTo: 70,
          yellowFrom:40, yellowTo: 50,
          minorTicks: 5
        var chart1 = new google.visualization.Gauge(document.getElementById('chart_div1'));
		var chart2 = new google.visualization.Gauge(document.getElementById('chart_div2'));
		var chart3 = new google.visualization.Gauge(document.getElementById('chart_div3'));
		var chart4 = new google.visualization.Gauge(document.getElementById('chart_div4'));
		var chart5 = new google.visualization.Gauge(document.getElementById('chart_div5'));

		gauge1_data.setValue(0, 1, temp_c);
		gauge2_data.setValue(0, 1, temp_f);
		gauge3_data.setValue(0, 1, temp_k);
		gauge4_data.setValue(0, 1, temp_r);
		gauge5_data.setValue(0, 1, humidity);
        chart1.draw(gauge1_data, gauge1_options);
		chart2.draw(gauge2_data, gauge2_options);
		chart3.draw(gauge3_data, gauge3_options);
		chart4.draw(gauge4_data, gauge4_options);
		chart5.draw(gauge5_data, gauge5_options);
      function UpdateSensorMeasurment()   
      setInterval(UpdateSensorMeasurment, 1000);
	  /* setInterval(drawChart, 1000); */


    <h1 style="color:black"> ESP32 HTTP Web Server </h1>
    <h1 style="color:black"> DHT22 Temperature, Humidity Monitoring </h1>
    <h3> HTML, AJAX and CSS formulated GUI on ESP32 Web server </h3>   
     <div class="row">   
			<div class="column">   
				<div class="block" >
					<h3> Celsius </h3>
					<h3> In &#176 C </h3>
					<p><i class="fas fa-thermometer-half fa-5x" style="color:#0;"></i></p>
				<div id="count">
					<h1><span id='temp_c_span'>--</span></h1>	
				<div id="gauge_div">		
					<table class="center" id="chart_div1"></table>  
			<div class="column">   
				<div class="block"> 
				<h3> Fahrenheit </h3>
				<h3> In &#176 F </h3>
				<p><i class="fas fa-thermometer-half fa-5x" style="color:#0;"></i></p>
				<div id="count">		
					<h1><span id='temp_f_span'>--</span></h1>   
				<div id="gauge_div">		
					<table class="center" id="chart_div2"></table>  
			<div class="column">   
				<div class="block">
				<h3> Kelvin </h3>
				<h3> In K </h3>
				<p><i class="fas fa-thermometer-half fa-5x" style="color:#0;"></i></p>       
				<div id="count">		
					<h1><span id='temp_k_span'>--</span></h1>   
				<div id="gauge_div">		
					<table class="center" id="chart_div3"></table>  
			<div class="column">   
				<div class="block">
				<h3> Rankine </h3>
				<h3> In &#176 R </h3>
				<p><i class="fas fa-thermometer-half fa-5x" style="color:#0;" style="font-size:90px;"></i> </p>
				<div id="count">		
					<h1><span id='temp_r_span'>--</span></h1>   
				<div id="gauge_div">		
					<table class="center" id="chart_div4"></table>  
			<div class="column">   
				<div class="block">
				<h3> Humidity </h3>
				<h3> In % </h3>
				<p><i class="fas fa-tint fa-5x" style="color:#0;" style="font-size:90px;"></i> </p>
				<div id="count">		
					<h1><span id='humidity_span'>--</span></h1>   
				<div id="gauge_div">		
					<table class="center" id="chart_div5"></table>  
  return html

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create Stram TCP web-server socket
s.bind(('', 80)) # Assign and bind port 80 for HTTP web-server socket
s.listen(5) # Configure for listening maximum 5 web-clients

# OLED pixel definition (WxH)
WIDTH  = 128 

# I2C0 pin assignments
SCL = 22
SDA = 21
DHT_PIN = 23

# 32x32 apple icon pixel array
h = [
0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x18, 0x04, 0x20, 0x00, 0x18,
0x04, 0x38, 0x00, 0x3C, 0x04, 0x20, 0x00, 0x24, 0x04, 0x30, 0x00, 0x66, 0x04, 0x30, 0x00, 0x24,
0x04, 0x20, 0x00, 0x3C, 0x05, 0xB8, 0x00, 0x00, 0x05, 0xA0, 0x06, 0x00, 0x05, 0xA0, 0x0E, 0x00,
0x05, 0xB0, 0x0B, 0x00, 0x05, 0xA0, 0x19, 0x00, 0x05, 0xB8, 0x11, 0x80, 0x05, 0xA0, 0x11, 0x80,
0x05, 0xA0, 0x1B, 0x00, 0x0D, 0xA0, 0x0E, 0x00, 0x19, 0xB8, 0x00, 0x18, 0x31, 0x8C, 0x00, 0x18,
0x21, 0x84, 0x00, 0x24, 0x67, 0xC6, 0x00, 0x66, 0x47, 0xE2, 0x00, 0x42, 0x47, 0xE2, 0x00, 0x42,
0x47, 0xE2, 0x00, 0x42, 0x47, 0xC6, 0x00, 0x7E, 0x61, 0x84, 0x00, 0x18, 0x30, 0x0C, 0x00, 0x00,
0x18, 0x18, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

humid = bytearray(h)

# Initialize I2C0, Scan and Debug print of SSD1306 I2C device address
i2c = I2C(0, scl=Pin(SCL), sda=Pin(SDA), freq=200000)
print("Device Address      : "+hex(i2c.scan()[0]).upper())

# Initialize DHT22
sensor = dht.DHT22(Pin(DHT_PIN))

# Initialize OLED
display = SSD1306_I2C(WIDTH, HEIGHT, i2c)

# Timer one initialization for on board blinking LED at 200mS interval
timer_one.init(freq=5, mode=Timer.PERIODIC, callback=BlinkLED)

# Timer two initialization for updating the temperature and humidity variables at 5Seconds interval
timer_two.init(freq=0.2, mode=Timer.PERIODIC, callback=ReadUpdateSensor)

while True:
        if gc.mem_free() < 102000:
        conn, addr = s.accept() # Call accpept method for collecting the client address
        print('Got a connection from %s' % str(addr)) # Print the client address
        request = conn.recv(1024) # Collect client request
        request = str(request)
        print('Content = %s' % request) # Print the web-client request
        update = request.find('/getSensorValue')
        if update == 6:
            a1 = temp_c
            a2 = temp_f
            a3 = temp_k
            a4 = temp_r
            a5 = humidity
            response = str(a1) + "|"+ str(a2) + "|"+ str(a3) + "|"+ str(a4)+"|"+ str(a5)
            response = ConstructWebPage() # Construct the web page
        conn.send('HTTP/1.1 200 OK\n') # Send the web-server response to web-client
        conn.send('Content-Type: text/html\n')
        conn.send('Connection: close\n\n')
        # Clsoe connection
    except OSError as e:
        print('Connection closed')

Step 8: Conclusion

The project is successfully completed with ESP32 development board, Wi-Fi router and Tablet.

The web-server handles HTML-AJAX request / response at regular interval to web-client running on tablet, android mobile and laptop google chrome, and updates the end user GUI.

Step 9: Results and Video Links

Please Visit You Tube for the conclusion video

Visit the "VESZLE - The Art Of Electronics" you tube channel for further information and videos.

ESP32 – Web Server – DHT22 Temperature – Humidity Monitoring implementation video

Be the First to Share


    • Knitting and Crochet Speed Challenge

      Knitting and Crochet Speed Challenge
    • Photography Challenge

      Photography Challenge
    • One Board Contest

      One Board Contest