Skip to content

Repository files navigation

MLight 工作灯驱动与控制程序

针对淘宝 1003 MLight 单灯珠版 USB 状态灯编写的驱动。
本工程实现了字节级串口协议,从零实现驱动。

MLight 工作灯商品宣传图
对应硬件商品宣传图

目录结构

驱动程序工程/
├── mlight/                  # 驱动包(Python,纯脚本,无需编译)
│   ├── protocol.py          # 协议层:命令表、校验、组帧
│   ├── portfinder.py        # 串口端口发现(WMI / VID_2E8A / 环境变量)
│   ├── driver.py            # 驱动核心:连接、发送、超时、断线重连、自检、软件呼吸
│   ├── cli.py               # 命令行入口
│   └── server.py            # 本地 HTTP 服务(供 Agent Skill 调用)
├── skill/                   # 控制程序(Agent Skill 形式)
│   ├── SKILL.md
│   └── scripts/light.py
├── tests/                   # 单元测试(可离线运行,不依赖硬件)
├── images/                  # README 配图
├── 启动服务.bat             # 一键启动服务(前台窗口)
├── 启动服务-隐藏.ps1        # 隐藏启动(开机自启用)
├── 注册开机自启.bat         # 注册到 HKCU Run(当前用户,无需管理员)
├── 取消开机自启.bat         # 取消开机自启
├── 使用说明书.md            # 日常使用说明(面向非开发者)
└── README.md

串口协议

  • 物理层:USB 串口(CDC),115200 波特,8N1,读写超时 500ms
  • 帧格式:ASCII 命令文本 + \n(0x0A),无帧头/校验/应答 (卖家代码:SerialPort.WriteLine(command)NewLine = "\n"
  • 命令表(13 个基础命令 + 亮度):
命令 效果
GREEN_ON / GREEN_OFF / GREEN_BLINK / GREEN_BREATH 绿灯 常亮/熄灭/闪烁/呼吸
YELLOW_ON / YELLOW_OFF / YELLOW_BLINK / YELLOW_BREATH 黄灯 常亮/熄灭/闪烁/呼吸
RED_ON / RED_OFF / RED_BLINK / RED_BREATH 红灯 常亮/熄灭/闪烁/呼吸
OFF 全部熄灭
BRIGHTNESS_0 ~ BRIGHTNESS_100 亮度 0-100%
  • 设备为单灯珠(1003 单灯珠版),同一时刻只显示一种主色
  • 设备芯片方案:Raspberry Pi Pico(USB VID 2E8A),端口发现时优先匹配

运行环境

项目 要求
操作系统 Windows 10/11(开发与实测环境)
Python 3.7+(推荐 3.10+,实测 Windows 11 + Python 3.14)
第三方依赖 pyserial
硬件 1003 MLight 单灯珠版 USB 状态灯(USB CDC,即插即用,自动识别为 COM 口)

驱动为纯 Python 脚本:无需编译、无需 .NET 或其它运行时;代码未使用平台专属 API,理论上 Linux/macOS 亦可运行(pyserial 跨平台),但仅在 Windows 上验证过。

安装依赖

python -m pip install pyserial

快速开始(CLI)

# 绿灯常亮(驱动默认行为,表示在线)
python -m mlight.cli on green on

# 黄灯呼吸 60 秒后自动熄灭
python -m mlight.cli on yellow breath 60

# 软件呼吸(推荐):三角波+gamma 感知校正,匀速渐变、峰值瞬间折返
python -m mlight.cli on green breath --soft --period 4.0 --gamma 2.2 --curve triangle

# 红灯闪烁 30 秒后恢复绿灯
python -m mlight.cli on red blink 30 --restore GREEN_ON

# 熄灭
python -m mlight.cli off

# 亮度 50%
python -m mlight.cli brightness 50

# 自检(红→绿→黄各 1 秒)
python -m mlight.cli selftest

# 查看状态 / 端口
python -m mlight.cli status
python -m mlight.cli port
python -m mlight.cli ports

指定端口(默认自动发现):python -m mlight.cli --port COM12 on green on 或设置环境变量 MLIGHT_SERIAL_PORT=COM12

常驻 HTTP 服务(供 Agent 调用)

python -m mlight.server --port 6802
  • GET /api/health — 健康检查
  • GET /api/status — 驱动状态(端口、当前命令、是否在线)
  • POST /api/command — 控制灯光,三种请求体任选:
{"command": "YELLOW_BREATH"}
{"color": "yellow", "mode": "breath", "timeout": 60, "restore": "OFF"}
{"color": "green", "mode": "breath", "soft": true, "period": 4.0, "gamma": 2.2, "curve": "triangle"}
{"brightness": 50}
{"action": "selftest"}
  • POST /api/off — 熄灭

驱动特性

  • 超时控制:任何命令可带超时,到期自动熄灭或恢复指定状态
  • 软件呼吸:固件自带呼吸动画在亮度降到低端时会突然熄灭(渐变末端骤断, 属固件行为无法修改)。驱动可用 BRIGHTNESS_0..100 命令做平滑渐变 (on <color> breath --soft):20ms 步进(50fps)+ gamma 感知编码 (人眼感知 ≈ 光强^0.45,编码 PWM = s^γ,γ≈2.2 时感知线性)+ 三角波曲线 (感知亮度匀速升降、峰值瞬间折返,不会像正弦那样"粘"在最亮状态 被误看成常亮;--curve sine 可换回正弦),节拍误差 <1ms (实测 20.0±0.5ms),视觉接近固件连续 PWM 的丝滑效果。帧值不变时 跳过写入(暗端多帧同值零 I/O),实测呼吸态 CPU ~1% 单核、串口带宽 ~4%。 参数:--period(默认 4 秒)、--gamma(默认 2.2,1.0=线性)、 --curve(默认 triangle);HTTP 服务用 {"soft": true, "period": 4.0, "gamma": 2.2, "curve": "triangle"}
  • 动画维持:实测设备固件的闪烁/呼吸动画仅持续约 1-2 秒即自动熄灭, 驱动内置维持线程每 2 秒重申动画命令(卖家 sidecar 同样每 10 秒重申)
  • 端口自动发现:pyserial 枚举 → 排除蓝牙(BTHENUM)→ 优先 VID_2E8A(Pico) → 环境变量 MLIGHT_SERIAL_PORT / 参数指定
  • 断线自动重连:发送失败自动重试,重连成功后重放当前灯光状态 (重连直接复用上次成功的端口名,不重复枚举)
  • 启动自检:打开串口后默认点亮绿灯常亮(驱动在线指示),可用 selftest 命令做三色测试
  • 无需 exe:纯 Python 脚本,符合"驱动程序无需以 exe 形式产出"的要求

性能测试

目标:驱动作为常驻后台的提示灯服务,必须长时间运行且低开销。 以下是真机实测成果(服务常驻运行时的真实资源占用)。

测试环境与方法

项目 说明
硬件 1003 MLight 单灯珠版(COM12,USB CDC)
系统 Windows 11 + Python 3.14(pyserial 3.5)
服务形态 python -m mlight.server --port 6802 常驻
测量方法 PowerShell Get-Process 采样进程累计 CPU 时间与工作集,10 秒窗口做差分;线程数取 Threads.Count
测量点 空闲(常亮/熄灭)、软件呼吸(4s 周期、50fps)各测 10s+,30s 持续观察泄漏

结果

状态 CPU(单核) 内存 线程 串口带宽
空闲(常亮/熄灭) 0.000% ~29 MB 1 0
软件呼吸(4s 周期,50fps) ~1.0% ~29 MB 2 ~4%
固件动画(闪烁/呼吸 + 2s 重申) ~0.05%(每 2s 一帧) ~29 MB 2 极低
  • 空闲态调度线程自动退出(无事可做即退出,绝不空转),常驻后台 CPU 为 0
  • 30 秒持续观察:线程数与内存无增长(无泄漏、无僵尸线程)
  • 呼吸节拍精度:20.0 ± 0.5ms(50fps 无抖动,人眼不可感知的恒定节拍)

呼吸态 ~1% 单核的开销构成

50 帧/秒节拍 × 平均写入 36 帧/秒(4s 周期 200 个 tick 中实际写入约 145 帧,帧值不变即跳过),每帧约 0.25ms:

组成 耗时/帧 说明
串口写(WriteFile) ~0.1 ms 15 字节 @ 115200,纯系统调用
精确睡眠(time.sleep) ~0.03 ms 10ms 切片 1-2 次,本机精度 <1ms
亮度计算(曲线 + pow) ~1 μs 纯 Python 计算
锁 / 循环 / 时间戳 ~5 μs RLock 短临界区

关键设计把开销压到平台下限:

  • 帧值不变跳过写入:暗端 gamma 编码下多帧同值(如 0%),直接跳过, 不产生任何 I/O(模拟验证:4s 周期 200 帧中 55 帧零写入,占 28%)
  • BRIGHTNESS 命令幂等:重复设置相同亮度零 I/O
  • 调度线程按需存活:无超时/无动画/无呼吸时线程退出,连线程调度 开销都省掉
  • 睡眠不进锁:状态变化最多延迟一个切片(10ms),无感知影响

结论

  • 空闲态:0% CPU + 单线程,适合开机自启长期常驻
  • 呼吸态:~1% 单核 ≈ 8 核机器总 CPU 的 0.12%,属 Windows 系统调用开销下限,Python 层无进一步压缩空间
  • 无内存/线程泄漏,可 7×24 小时运行

测试

cd 驱动程序工程
python -m unittest discover -s tests -v

全部测试可离线运行(不依赖硬件),覆盖:协议命令校验/组帧、端口发现 评分、软件呼吸曲线(三角波/正弦形状、gamma 编码方向、峰值停留对比)、 步进节拍、亮度幂等、超时恢复、停止行为。

Skill(Agent 控制程序)

详见 skill/SKILL.md。Agent 通过 skill/scripts/light.py (内部调用 HTTP 服务或直接驱动)把自身状态映射为灯光:

Agent 状态 灯光
空闲 / 已连接 绿灯常亮
正在执行任务 黄灯呼吸
等待用户确认 / 需要授权 红灯闪烁
任务结束 熄灭或恢复绿灯

已知限制

  • 串口被其它程序占用时无法打开(Windows 串口独占,需先退出占用程序)。
  • 单灯珠只能同时显示一种颜色,复合命令(如 GREEN_ON+RED_BLINK)仅适用于三灯珠版。
  • 设备无应答协议(纯下行命令),驱动无法读取灯珠当前状态,只能记录本地状态。
  • 设备固件的闪烁/呼吸动画约 1-2 秒后自动熄灭,须周期性重申(驱动已内置,见"驱动特性"); 常亮与熄灭无此限制。

About

MLight 状态灯驱动与控制程序。AI工作状态灯驱动。

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages