Skip to main content

Web Server

The ESP32 has built-in Wi-Fi capabilities that can serve other devices in the network as a web server. By running a web server on ESP32, a browser-based user interface can be created for monitoring sensor data or controlling device status, which is one of the fundamental features for implementing IoT applications.

1. Web Server in MicroPython

In MicroPython, the built-in socket module is typically used to create a Web server. While there are third-party libraries like Microdot that provide a higher-level wrapper, using socket offers a deeper understanding of the basic principles of the HTTP protocol and network communication. It requires no additional libraries to install, making it ideal for beginners.

The basic workflow of a Web server is as follows:

  1. Create a Socket: Establish an endpoint for network communication.
  2. Bind: Bind the socket to a specific IP address and port (typically port 80 for HTTP).
  3. Listen: Start listening for connection requests from clients (e.g., web browsers).
  4. Accept Connection: When a client connects, establish a connection channel.
  5. Receive Request: Read the HTTP request message sent by the client.
  6. Send Response: Send an HTTP response message (containing HTML pages, etc.) based on the request content.
  7. Close Connection: Disconnect from the client.

2. Example 1: Basic Web Services (STA Mode)

Create a basic web server in STA mode to display a static page containing "Hello World!".

2.1 Code

import time
import network
import socket
from machine import Pin

# Wi-Fi Configuration
SSID = "Maker" # Replace with your Wi-Fi name
PASSWORD = "12345678" # Replace with your Wi-Fi password

def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('Connecting to network...')
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
time.sleep(0.5)
print('.', end='')
print('\nNetwork connected')
print('IP address:', wlan.ifconfig()[0])
return wlan

def web_page():
html = """<!DOCTYPE html> <html>
<head><meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1">
<title>ESP32 MicroPython Web Server</title>
</head><body>
<h1>Hello World!</h1>
<p>Hello from ESP32 MicroPython</p>
</body></html>
"""
return html

# Connect to Wi-Fi
connect_wifi()

# Create a Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind to port 80
s.bind(('', 80))
# Start listening
s.listen(5)

print("Web server is running...")

while True:
try:
# Accept a client connection
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))

# Receive the request
request = conn.recv(1024)
# print('Content = %s' % str(request)) # For debugging, prints the full request header

# Send the response
response = web_page()

# Send HTTP response headers
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')

# Send HTML content
conn.sendall(response)

# Close the connection
conn.close()

except OSError as e:
conn.close()
print('Connection closed')

2.2 Code Analysis

  • socket.socket(socket.AF_INET, socket.SOCK_STREAM): Creates a new socket object. AF_INET specifies the use of the IPv4 address family, and SOCK_STREAM specifies the use of the TCP protocol.
  • s.bind(('', 80)): Binds the socket to the specified IP address and port. '' means binding to all available network interfaces, and 80 is the standard HTTP service port.
  • s.listen(5): Starts listening for connection requests. The parameter 5 specifies the maximum number of queued unprocessed connections allowed before rejecting new ones.
  • s.accept(): Blocks program execution until a new client connection request arrives. Once a connection is made, it returns a new socket object conn (for communicating with that specific client) and the client's address information addr.
  • conn.recv(1024): Receives data from the client. 1024 specifies the maximum number of bytes to receive at once. The received data is of type bytes.
  • HTTP Response Headers: Before sending HTML content, HTTP-compliant response headers must be sent first. HTTP/1.1 200 OK indicates the request was successful, and Content-Type: text/html informs the browser that HTML content follows.

2.3 Expected Output

After modifying the Wi-Fi name and password, run the code. Check the ESP32's IP address in the Shell window of Thonny. Enter this IP address in a web browser to see the "Hello World!" page.

Thonny Shell displays IP address

Browser displays Hello World page

3. Example 2: Controlling an LED via Web Page (STA Mode)

In STA mode, control an LED on/off via web page buttons by parsing the path (URL) in the HTTP request.

3.1 Circuit Assembly

Components required:

  • LED * 1
  • 330Ω resistor * 1
  • Breadboard * 1
  • Wire
  • ESP32 development board

Connect the circuit according to the wiring diagram below:

ESP32-S3-Zero Pinout Diagram

ESP32-S3-Zero-Pinout

Wiring diagram

3.2 Code

import time
import network
import socket
from machine import Pin

# LED Configuration
led = Pin(7, Pin.OUT)
led.value(0) # Initially off

# Wi-Fi Configuration
SSID = "Maker" # Replace with your Wi-Fi name (SSID)
PASSWORD = "12345678" # Replace with your Wi-Fi password

def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('Connecting to network...')
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
time.sleep(0.5)
print('.', end='')
print('\nNetwork connected')
print('IP address:', wlan.ifconfig()[0])
return wlan

def web_page():
if led.value() == 1:
gpio_state = "ON"
button_html = '<a href="/ledoff">Turn off the LED</a>'
else:
gpio_state = "OFF"
button_html = '<a href="/ledon">Turn on the LED</a>'

html = """<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP32S3 Test</title>
</head>
<body><h1>ESP32 Web Server</h1>
<p>GPIO state: <strong>""" + gpio_state + """</strong></p>
""" + button_html + """
</body></html>"""
return html

# Connect to Wi-Fi
connect_wifi()

# Create a Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

print("Web server is running...")

while True:
try:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))

request = conn.recv(1024)
request = str(request)
# Check the network request
# print(request)

if 'GET /ledon' in request:
print('LED ON')
led.value(1)
elif 'GET /ledoff' in request:
print('LED OFF')
led.value(0)

# Prepare and send the web page response
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()

except OSError as e:
conn.close()
print('Connection closed')

3.3 Code Analysis

  • Request Parsing:
    • request = str(request): The data received by conn.recv() is in bytes. It's converted to a string for easier processing.
    • if 'GET /ledon' in request: Checks if the request content contains GET /ledon. When a user clicks the "Turn ON" link on the web page, the browser sends a GET request containing this path to the server.
    • The program executes the corresponding LED control logic by determining whether the URL path is /ledon or /ledoff.
  • Dynamic HTML Generation:
    • The web_page() function dynamically generates HTML code containing different text and links based on the LED's current state (led.value()).
    • If the LED is on, the generated page shows a "Turn off" link; if the LED is off, it shows a "Turn on" link.

3.4 Expected Output

Access the ESP32's IP address. The page will display a large button. Clicking the button controls the LED on/off, and the page refreshes to show the latest LED state.

Thonny Shell displays IP address

Web Control Page

4. Example 3: Controlling an LED via Web Page (AP Mode)

In AP (Access Point) mode, the ESP32 creates its own Wi-Fi hotspot. Phones or computers can connect to this hotspot to access the web server without relying on an external router.

4.1 Circuit Assembly

The circuit connection is the same as in Example 2.

4.2 Code

import time
import network
import socket
from machine import Pin

# LED Configuration
led = Pin(7, Pin.OUT)
led.value(0) # Initially off

# Wi-Fi Configuration
SSID = "ESP32-S3-TEST" # Set the hotspot name
PASSWORD = "12345678" # Set the hotspot password (at least 8 characters)

def start_ap():
ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=SSID, password=PASSWORD, authmode=network.AUTH_WPA_WPA2_PSK)

while not ap.active():
pass

print('AP started')
print('IP address:', ap.ifconfig()[0])

def web_page():
if led.value() == 1:
gpio_state = "ON"
button_html = '<a href="/ledoff">Turn off the LED</a>'
else:
gpio_state = "OFF"
button_html = '<a href="/ledon">Turn on the LED</a>'

html = """<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP32S3 Test</title>
</head>
<body><h1>ESP32 Web Server</h1>
<p>GPIO state: <strong>""" + gpio_state + """</strong></p>
""" + button_html + """
</body></html>"""
return html

start_ap()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

print("Web server is running...")

while True:
try:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))

request = conn.recv(1024)
request = str(request)
# Check the network request
# print(request)

if 'GET /ledon' in request:
print('LED ON')
led.value(1)
elif 'GET /ledoff' in request:
print('LED OFF')
led.value(0)

# Prepare and send the web page response
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()

except OSError as e:
conn.close()
print('Connection closed')

4.3 Code Analysis

  • network.WLAN(network.AP_IF): Creates a WLAN object, specifying the use of the AP (Access Point, hotspot) mode interface.
  • ap.active(True): Activates the AP interface, starting the wireless hotspot functionality.
  • ap.config(...): Configures hotspot parameters.
    • essid: Sets the hotspot name (SSID).
    • password: Sets the hotspot password.
    • authmode: Sets the authentication mode; here, WPA/WPA2 PSK security mode is used.
  • IP Address: In AP mode, the ESP32's default IP address is typically 192.168.4.1.

4.4 Expected Output

  1. Upload the code.
  2. Use a phone or computer to search for and connect to the Wi-Fi named "ESP32-AP-Test" (password: 12345678).
  3. Enter 192.168.4.1.
  4. You will see the control page and can control the LED.

Thonny Shell displays IP address

Web Control Page