实现通过ESP32S3连接Wi-Fi并使用Web页面控制WS2812灯珠的颜色,可以使用ESP32的WebServer库来创建一个简单的Web界面。通过这个界面,可以动态地控制灯珠的显示效果。
针对 五、ESP32-S3上使用MicroPython点亮WS2812智能LED灯珠并通过web控制改变灯珠颜色代码优化说明:
- Wi-Fi连接超时处理:添加了
wifi_connect_timeout
变量,用于设置Wi-Fi连接的最大等待时间。如果超过此时间还未连接成功,会引发RuntimeError
,避免无限等待。- 输入验证:在解析颜色参数时,增加了对十六进制字符串的验证,确保输入的颜色码为有效的6位十六进制数字。如果格式不正确,会打印错误信息而不会修改颜色。
- 线程同步处理:使用
asyncio.Lock()
确保在多个请求同时进行时,对current_color
的修改是线程安全的,避免由于并发问题导致的颜色设置错误。
代码实现:
import network
import neopixel
from machine import Pin
import uasyncio as asyncio
import socket
import time
# 设置Wi-Fi连接参数
ssid = 'XTY-2'
password = 'xty202102'
wifi_connect_timeout = 10 # Wi-Fi连接超时时间(秒)
# 初始化并连接到Wi-Fi网络
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
# 等待Wi-Fi连接,添加超时处理
start_time = time.time()
while not station.isconnected():
if time.time() - start_time > wifi_connect_timeout:
raise RuntimeError('Wi-Fi连接超时,请检查网络设置')
pass
print('连接成功')
print(station.ifconfig()) # 打印Wi-Fi连接配置
# 设置GPIO 2为输出引脚,并初始化一个有7个LED的NeoPixel对象
led_pin = Pin(2, Pin.OUT)
num_leds = 7 # 固定LED数量
np = neopixel.NeoPixel(led_pin, num_leds)
# 初始化颜色,初始为红色
current_color = (255, 0, 0)
color_lock = asyncio.Lock() # 用于颜色修改的锁,防止并发修改
# 生成网页的HTML内容
def generate_web_page():
html = """<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LED控制</title>
</head>
<body>
<h1>LED 控制面板</h1>
<form action="/" method="GET">
<label for="color">灯珠颜色 (十六进制):</label>
<input type="text" id="color" name="color" value="#{0:02x}{1:02x}{2:02x}">
<br><br>
<input type="submit" value="提交">
</form>
</body>
</html>""".format(current_color[0], current_color[1], current_color[2])
return html
# 处理客户端请求的异步函数
async def handle_client(client):
try:
request = client.recv(1024) # 接收客户端请求
request = str(request)
# 解析请求并获取颜色参数
if "GET /?" in request:
try:
params = request.split("GET /?")[1].split(" HTTP/")[0]
param_dict = {}
for param in params.split('&'):
key, value = param.split('=')
param_dict[key] = value.replace("%23", "#") # 处理颜色代码中的“#”符号
print(param_dict)
global current_color
# 解析颜色参数
if 'color' in param_dict:
color_str = param_dict['color'].lstrip('#') # 去掉颜色码前的“#”
if len(color_str) == 6 and all(c in '0123456789abcdefABCDEF' for c in color_str):
try:
# 将颜色从十六进制字符串转换为RGB元组
r = int(color_str[0:2], 16)
g = int(color_str[2:4], 16)
b = int(color_str[4:6], 16)
# 使用锁来防止并发修改current_color
async with color_lock:
current_color = (r, g, b)
except ValueError as e:
print("颜色解析错误:", e) # 捕捉解析错误
current_color = (255, 0, 0) # 设置默认颜色
else:
print("无效的颜色值长度或格式:", color_str)
# 更新LED灯珠颜色
async with color_lock:
for i in range(num_leds):
np[i] = current_color
np.write() # 写入新的颜色到LED
print(f"LED颜色更新为: {current_color}")
except Exception as e:
print("参数处理错误:", e)
# 生成网页并发送响应
response = generate_web_page()
client.send('HTTP/1.1 200 OK\n')
client.send('Content-Type: text/html\n')
client.send('Connection: close\n\n')
client.sendall(response)
finally:
client.close() # 关闭客户端连接
# 查找可用端口的函数
def find_available_port(start_port=80, max_port=65535):
port = start_port
while port <= max_port:
try:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('', port))
server_socket.close() # 立即关闭以释放端口
return port
except OSError:
port += 1
raise RuntimeError('没有可用端口')
# 启动Web服务器的异步函数
async def web_server():
port = find_available_port()
print(f"Web服务器使用端口 {port}")
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('', port))
server_socket.listen(5)
print("Web服务器启动,等待连接...")
while True:
client, addr = server_socket.accept() # 接受客户端连接
print('客户端连接自', addr)
await handle_client(client) # 处理客户端请求
# 创建并运行任务
loop = asyncio.get_event_loop()
loop.create_task(web_server())
loop.run_forever()