七、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的颜色。

相关推荐
田三番1 天前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
T0uken2 天前
【ESP32+MicroPython】网络编程基础
网络·python·esp32
e调布鲁斯5 天前
esp32cam+Arduino IDE在编译时提示找不到 esp_camera.h 的解决办法
esp32·arduino
启明云端wireless-tag5 天前
ESP-IDF HTTP POST请求发送音频-启明云端乐鑫代理商
http·音视频·esp32·物联网开发
乐鑫科技 Espressif6 天前
ESP-HaloPanel:用 ESP32-C2 打造超低成本智能家居面板
esp32·智能家居·wi-fi
WKJay_8 天前
【ESP32S3】VSCode 开发环境搭建
wifi·esp32·ble
zhangrelay15 天前
Arduino-ESP32机器人控制器设计练习题汇总
机器人·esp32
柔贝特三哥15 天前
ESP32 S3 语音识别 语音唤醒程序流程
人工智能·esp32·语音识别·esp-idf·ai对话·语音唤醒·语音命令
Mr_Chenph19 天前
MicroPython rp2-LVGL 固件编译记录
lvgl·micropython·pico·固件
宁子希25 天前
封装 ESP-IDF 组件并上传到 ESP 组件注册表
单片机·嵌入式硬件·esp32