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

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

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颜色选择器的部分:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值