跳到主要内容

网页服务器

ESP32 内置了 Wi-Fi 功能,能够作为网页服务器(Web Server)向网络中的其他设备提供服务。通过在 ESP32 上运行网页服务器,可以创建基于浏览器的用户界面,用于监控传感器数据或控制设备状态,是实现物联网(IoT)应用的基础功能之一。

1. MicroPython 中的 Web Server

在 MicroPython 中,通常使用内置的 socket 模块来创建 Web 服务器。虽然也有像 Microdot 这样的第三方库提供了更高级的封装,但使用 socket 可以更深入地理解 HTTP 协议和网络通信的基本原理,且无需安装额外的库,非常适合入门学习。

Web 服务器的基本工作流程如下:

  1. 创建套接字 (Socket):建立网络通信的端点。
  2. 绑定 (Bind):将套接字绑定到特定的 IP 地址和端口(通常是 HTTP 的 80 端口)。
  3. 监听 (Listen):开始监听来自客户端(如浏览器)的连接请求。
  4. 接受连接 (Accept):当有客户端连接时,建立连接通道。
  5. 接收请求 (Receive):读取客户端发送的 HTTP 请求报文。
  6. 发送响应 (Send):根据请求内容,发送 HTTP 响应报文(包含 HTML 页面等)。
  7. 关闭连接 (Close):断开与客户端的连接。

2. 示例 1:基础网页服务 (STA 模式)

在 STA 模式下创建一个基础的网页服务器,用于显示一个包含 "Hello World!" 的静态页面。

2.1 代码

import time
import network
import socket
from machine import Pin

# Wi-Fi 配置
SSID = "Maker" # 替换为你的 Wi-Fi 名称
PASSWORD = "12345678" # 替换为你的 Wi-Fi 密码

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

# 连接 Wi-Fi
connect_wifi()

# 创建 Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口 80
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)
# print('Content = %s' % str(request)) # 调试用,打印完整的请求头

# 发送响应
response = web_page()

# 发送 HTTP 响应头
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')

# 发送 HTML 内容
conn.sendall(response)

# 关闭连接
conn.close()

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

2.2 代码解释

  • socket.socket(socket.AF_INET, socket.SOCK_STREAM): 创建一个新的套接字对象。AF_INET 指定使用 IPv4 地址族,SOCK_STREAM 指定使用 TCP 协议。
  • s.bind(('', 80)): 将套接字绑定到指定的 IP 地址和端口。'' 表示绑定到所有可用的网络接口,80 是标准的 HTTP 服务端口。
  • s.listen(5): 开始监听连接请求。参数 5 指定了在拒绝新连接之前允许排队的最大未处理连接数。
  • s.accept(): 阻塞程序执行,直到有新的客户端连接请求。一旦有连接,它返回一个新的套接字对象 conn(用于与该特定客户端通信)和客户端的地址信息 addr
  • conn.recv(1024): 从客户端接收数据。1024 指定了一次接收的最大字节数。接收到的数据是字节(bytes)类型。
  • HTTP 响应头: 在发送 HTML 内容之前,必须先发送符合 HTTP 协议的响应头。HTTP/1.1 200 OK 表示请求成功,Content-Type: text/html 告知浏览器后续发送的是 HTML 内容。

2.3 运行结果

修改 Wi-Fi 名称和密码后运行代码。在 Thonny 的 Shell 窗口中查看 ESP32 的 IP 地址。在浏览器中输入该 IP 地址,即可看到 "Hello World!" 页面。

Thonny Shell 显示 IP 地址

浏览器显示 Hello World 页面

3. 示例 2:通过网页控制 LED (STA 模式)

在 STA 模式下,通过解析 HTTP 请求中的路径(URL),实现通过网页按钮控制 LED 的亮灭。

3.1 搭建电路

需要使用的器件有:

  • LED * 1
  • 330Ω 电阻 * 1
  • 面包板 * 1
  • 导线
  • ESP32 开发板

按照下面接线图连接电路:

ESP32-S3-Zero 引脚图

ESP32-S3-Zero-Pinout

接线图

3.2 代码

import time
import network
import socket
from machine import Pin

# LED 配置
led = Pin(7, Pin.OUT)
led.value(0) # 初始关闭

# Wi-Fi 配置
SSID = "Maker" # 替换为 Wi-Fi 名称
PASSWORD = "12345678" # 替换为 Wi-Fi 密码

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

# 连接 Wi-Fi
connect_wifi()

# 创建 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)
# 查看网络请求
# print(request)

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

# 准备并发送网页响应
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 代码解析

  • 请求解析:
    • request = str(request): conn.recv() 接收到的是字节数据,将其转换为字符串以便于处理。
    • if 'GET /ledon' in request: 检查请求内容中是否包含 GET /ledon。当用户点击网页上的 "Turn ON" 链接时,浏览器会向服务器发送包含此路径的 GET 请求。
    • 程序通过判断 URL 路径是 /ledon 还是 /ledoff 来执行相应的 LED 控制逻辑。
  • 动态 HTML 生成:
    • web_page() 函数根据 LED 当前的电平状态(led.value()),动态生成包含不同文本和链接的 HTML 代码。
    • 如果 LED 开启,生成的网页显示 "Turn off" 链接;如果 LED 关闭,则显示 "Turn on" 链接。

3.4 运行结果

访问 ESP32 的 IP 地址,页面将显示一个大按钮。点击按钮可以控制 LED 的开关,同时页面会刷新显示最新的 LED 状态。

Thonny Shell 显示 IP 地址

网页控制页面

4. 示例 3:通过网页控制 LED (AP 模式)

在 AP (Access Point) 模式下,ESP32 自己建立一个 Wi-Fi 热点,手机或电脑连接该热点后即可访问网页服务器,无需依赖外部路由器。

4.1 搭建电路

电路连接与示例 2 相同。

4.2 代码

import time
import network
import socket
from machine import Pin

# LED 配置
led = Pin(7, Pin.OUT)
led.value(0) # 初始关闭

# Wi-Fi 配置
SSID = "ESP32-S3-TEST" # 设置热点名称
PASSWORD = "12345678" # 设置热点密码(至少 8 位)

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)
# 查看网络请求
# print(request)

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

# 准备并发送网页响应
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 代码解析

  • network.WLAN(network.AP_IF): 创建一个 WLAN 对象,并指定使用 AP(Access Point,热点)模式接口。
  • ap.active(True): 激活 AP 接口,启动无线热点功能。
  • ap.config(...): 配置热点参数。
    • essid: 设置热点的名称(SSID)。
    • password: 设置热点的密码。
    • authmode: 设置认证模式,这里使用 WPA/WPA2 PSK 安全模式。
  • IP 地址: 在 AP 模式下,ESP32 默认的 IP 地址通常为 192.168.4.1

4.4 运行结果

  1. 上传代码。
  2. 使用手机或电脑搜索名为 "ESP32-AP-Test" 的 Wi-Fi 并连接(密码 12345678)。
  3. 在浏览器中输入 192.168.4.1
  4. 即可看到控制页面并控制 LED。

Thonny Shell 显示 IP 地址

网页控制页面

5. 相关链接