七、ESP32-S3上使用MicroPython点亮WS2812智能LED灯珠并通过web控制和JS颜色选择器改变灯珠颜色

本地代码集成离线iro.js库来添加一个颜色选择器控件,在无网络环境可以通过JavaScript将选中的颜色发送到服务器以改变LED颜色。以下是将iro.js集成到网页后的颜色图片。

bash 复制代码
color:change
# 每当所选颜色发生变化时触发 - 无论是当用户与颜色选择器交互时,还是当颜色由您自己的代码更新时。此事件的回调函数将接收两个值:
 - color:当前选定的颜色
 - changes:显示自上次触发事件以来哪些 HSV 通道发生了变化的对象

colorPicker.on('color:change', function(color) {
    // don't let the color saturation fall below 50!
    if (color.saturation < 50) {
      color.saturation = 50;
    }
});

input:change
与 类似color:change,不同之处在于仅当颜色随着用户的鼠标或触摸输入而改变时才会触发此事件。

此事件的回调接收与相同的值,并且在此事件的回调中color:change修改对象也是安全的。color

input:start
每当用户开始与颜色选择器控件交互时触发。当前选定的颜色将传递到此事件的回调函数。

input:move
当用户在开始交互后移动指针/鼠标时触发。当前选定的颜色将传递到此事件的回调函数。

input:end (建议使用)
每当用户停止与颜色选择器控件交互时触发。当前选定的颜色将传递到此事件的回调函数。

color:init
添加颜色时触发。此事件的回调将接收新添加的颜色对象。

color:remove
当颜色从颜色选择器中移除时触发。此事件的回调将接收已移除的颜色对象。

color:setActive
每当切换"活动"颜色时触发。此事件的回调将接收活动颜色对象。

mount
当 colorPicker 的 UI 已安装到 DOM 并准备好进行用户交互时触发。colorPicker 对象将传递给此事件的回调函数。

代码路径示意图

完整代码

完整代码包括所有优化和集成iro.js颜色选择器的部分:

python 复制代码
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()  # 用于颜色修改的锁,防止并发修改

def generate_web_page():
    global current_color  # 确保current_color可以被访问
    html = """<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>LED控制</title>
        <script src="/iro.js"></script> <!-- 引入iro.js库 -->
    </head>
    <body>
        <h1>LED 控制面板效果1</h1>
        <div id="color-picker-container1"></div>
        <h1>LED 控制面板效果2</h1>
        <div id="color-picker-container2"></div>
        <h1>LED 控制面板效果3</h1>
        <div id="color-picker-container3"></div>
        <h1>LED 控制面板效果4</h1>
        <div id="color-picker-container4"></div>
        <h1>LED 控制面板效果5</h1>
        <div id="color-picker-container5"></div>
        <script>
            // 初始化iro.js颜色选择器
            var colorPicker1 = new iro.ColorPicker("#color-picker-container1", {
                width: 300
            });
            
            var colorPicker2 = new iro.ColorPicker("#color-picker-container2", {
                width: 300,
                layout: [
                    { 
                      component: iro.ui.Wheel,
                      options: {}
                    },
                ]
            });
            
            var colorPicker3 = new iro.ColorPicker("#color-picker-container3", {
                width: 300,
                layout: [
                    { 
                      component: iro.ui.Box,
                      options: {}
                    },
                ]
            });
            
            var colorPicker4 = new iro.ColorPicker("#color-picker-container4", {
                width: 300,
                layout: [
                    { 
                      component: iro.ui.Slider,
                      options: {}
                    },
                ]
            });
            
            var colorPicker5 = new iro.ColorPicker("#color-picker-container5", {
                width: 300,
                layout: [
                    { 
                      component: iro.ui.Slider,
                      options: {
                          sliderType: 'hue'
                      }
                    },
                ]
            });

            // 当颜色改变时,发送请求到服务器
            colorPicker1.on('input:end', function(color) {
                var hexColor = color.hexString;
                var xhr = new XMLHttpRequest();
                xhr.open("GET", "/?color=" + encodeURIComponent(hexColor.substring(1)), true);  // 发送颜色值(去掉#号)
                xhr.send();
            });
        </script>
    </body>
    </html>"""
    return html

# 处理客户端请求的异步函数
async def handle_client(client):
    try:
        request = client.recv(1024)  # 接收客户端请求
        request = str(request)

        # 提供iro.js文件
        if "GET /iro.js" in request:
            with open('iro.js', 'r') as file:
                js_content = file.read()
            client.send('HTTP/1.1 200 OK\n')
            client.send('Content-Type: application/javascript\n')
            client.send('Connection: close\n\n')
            client.sendall(js_content)
            return
        
        # 解析请求并获取颜色参数
        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()

这样,网页中将包含一个颜色选择器控件,用户可以通过选择颜色来动态改变LED的颜色。

相关推荐
lingzhilab6 小时前
零知派ESP32——基于INA238高精度功率监测芯片的18650锂电池充电状态可视化与数据导出
单片机·esp32·ina238
阿昊真人8 小时前
AIR780E MINI开发日志
esp32
一个平凡而乐于分享的小比特1 天前
还在手动挡写单片机?MicroPython 一脚油门踩进 Python 硬件世界
单片机·嵌入式硬件·micropython
温中志2 天前
esp_event_loop_create_default详细解释
esp32·freertos
似是燕归来2 天前
WiFi 模块自动联网自带MQTT协议栈和云服务器串口透传免AT开发
服务器·esp32·wifi模块·mqtt协议
NQBJT7 天前
双轮足机器人 5 连杆逆运动学:从几何模型到嵌入式实现
esp32·逆运动学·轮足机器人
qdprobot7 天前
ESP32S3 AiTall V3 Mixly 图形化编程开发AI小智 MCP AIOT大模型对话开发视频教程Micropython小智AI系统
人工智能·micropython·esp32s3·图形化编程·mcp·mixly小智ai·大模型对话
wanghanjiett8 天前
笔记:ESP32驱动SimpleFOC成功(基于Espressif-IDE)
笔记·esp32·foc
NQBJT9 天前
双轮足导盲机器人:多传感融合与全局-局部分层导航系统设计
c++·esp32·openmv·避障·导盲·轮足
net3m3310 天前
mic声音怎么才不容易卡顿 : 环形队列缓存要足够大
esp32·i2s