English version: README_EN.md · 在线文档:awakaze.github.io/MiMonitorLightTray
一款 Windows 系统托盘小工具,用类似 Twinkle Tray 的弹出式滑杆,控制小米 / Yeelight 显示器挂灯及各类米家灯具的开关、亮度与色温。基于 python-miio 与设备本地局域网通信,不经过云端。
支持多灯同时控制 — 可在同一实例中管理任意数量的设备,每盏灯拥有独立的显示、快捷键、休眠 / 唤醒策略。基本兼容所有可以连接米家的灯具。
本程序按设备 model 自动选择 legacy 或 MIoT 协议。除少数手工 curated 的机型外,~2100 个 MIoT 灯具的协议映射与色温范围已从 home.miot-spec.com 抓取并嵌入 (mi_monitor_light_tray/_miot_data.py),覆盖 yeelink、xiaomi、mijia 以及大量第三方品牌。
路由决策(按 model 在以下集合的成员关系自动推导):
- curated
_MIOT_MAPPINGS(miio_client.py 顶部,含 lamp22)→ MIoT - python-miio
YeelightSpecHelper(specs.yaml 已知的 legacy 设备,41 个)→ legacy - 本项目 curated
MODEL_CT_RANGES(手工验证过 legacy 的设备,如 lamp2)→ legacy - bulk
_miot_data(前 3 个都没听说过的 MIoT-only 设备,~2100 个)→ MIoT - 完全未知 → legacy(兜底,配合「启用 MIoT 实验性」开关可改走 MIoT)
色温范围解析(同样优先级):curated 覆盖表 > YeelightSpecHelper > bulk → 默认 2700–6500K。bulk 数据有合理性过滤(min ≥ 1000K、max ∈ [2000, 15000]K、span ≥ 500K),拒绝 spec 里把色温单位错标成 percentage 的伪 Kelvin 条目(~7% 的源数据是这样)。
下表只列重点机型,其它任何在嵌入数据库里的设备都会自动拿到正确协议与色温区间:
| 型号 ID | 设备 | 协议 | 色温范围 | 数据来源 |
|---|---|---|---|---|
yeelink.light.lamp22 |
米家智能显示器挂灯 1S(默认型号) | MIoT | 2700–6500 K | curated |
yeelink.light.lamp1 |
米家台灯 | legacy | 2700–5000 K | YeelightSpecHelper |
yeelink.light.lamp2 |
米家台灯 Pro | legacy | 2500–4800 K | 项目覆盖表 |
yeelink.light.lamp4 |
米家台灯 1S | legacy | 2600–5000 K | YeelightSpecHelper |
yeelink.light.ceiling* 系列 |
米家智能吸顶灯 | legacy | 2700–6500 K | YeelightSpecHelper |
yeelink.light.bslamp* |
米家床头灯 | legacy | 1700–6500 K | YeelightSpecHelper |
| 其它 ~2100 个 MIoT-only 机型 | 各品牌新型智能灯 | MIoT | 按 spec | _miot_data.py(bulk) |
如果你的机型不在任何来源里 → 程序按 legacy 处理。MIoT-only 但未被收录的新机型可在设备编辑器里勾选 启用 MIoT(实验性) 强制走 MIoT 通用 Light service spec 试探。
反馈兼容性问题时请带上
model字段(例如yeelink.light.lamp22)。可在配置文件%APPDATA%\MiMonitorLightTray\config.json的devices[].model看到,或者用miiocli device --ip <IP> --token <token> info查。
- 多灯并行管理 — 一个实例控制任意多盏米家 / Yeelight 灯,每灯独立配置
- 类 Twinkle Tray 弹出窗 — 每盏灯一节滑杆与开关按钮,窗口高度按内容自适应
- "关闭所有灯"一键操作 — 弹窗底部按钮,一次关掉所有在线设备
- 设备列表管理 — 图形化增删设备,拖拽排序,编辑 IP / Token / 型号
- 云端一键导入 — 扫码登录小米账号后多选设备,一次性批量添加
- 每设备独立快捷键 — 每盏灯有自己的亮度 / 色温加减快捷键,互不干扰;使用 Windows RegisterHotKey API,全屏游戏中也响应
- 每设备独立电源策略 — 逐灯配置软件启动 / 关闭、显示器休眠 / 唤醒、系统休眠 / 唤醒的自动开关
- 每设备可见性控制 — 单独隐藏某盏灯的亮度或色温滑杆,只保留常用控件
- 桌面小部件 — 可固定在桌面任意位置的控制面板,深色主题 + 圆角窗口,支持拖动 / 锁定,记忆位置与可见性
- 自动更新检测 — 启动时自动检查 GitHub Release 新版本,托盘菜单直接跳转下载
- 亮度 / 色温滑杆 — 亮度 1–100,色温由设备实际支持范围决定(自动读取)
- 滑杆防抖 — 拖动时合并请求,约 120 / 180 ms 才发一次 miio 调用,避免网络拥塞(每设备独立防抖器)
- 单例锁 — Windows 命名互斥锁防止重复启动,重复运行时弹窗提示
- IP 变化自动发现 — DHCP 续约导致 IP 变化时,自动通过 device ID 在局域网内重新定位设备并更新配置
- 空 model 自动识别 — 配置里没填型号时,启动时通过
info()探测真实型号并选择正确协议,避免协议错配 - Fluent Design 风格 — DWM 原生圆角窗口、半透明、Win11 配色
- 极简托盘图标 — 矢量绘制,高 DPI 清晰;开 / 关有不同视觉
- 持久化配置 — 保存到
%APPDATA%\MiMonitorLightTray\config.json,原子写入 - 单设备配置自动迁移 — 从 v1.4.x 升级时旧的
device单对象自动转为devices数组,无需手工处理 - 免安装 — 提供单文件 EXE,无需 Python 环境
- 拖滑杆自动开灯 — 灯处于关闭状态时拖动亮度 / 色温,会先开灯再生效,避免"白拖一通"
- MIoT 实验开关 — 对未被白名单收录的新型 Yeelight 设备,可在设备编辑器里手动启用 MIoT 协议尝试
从 Releases 下载 MiMonitorLightTray.exe,双击运行即可。每次 push 到 main 与每个 tag 都会自动构建(见 build.yml)。
git clone https://github.com/awakaze/MiMonitorLightTray.git
cd MiMonitorLightTray
python -m venv .venv
.venv\Scripts\activate
pip install -e .
mi-monitor-light-tray要求 Python 3.9+。
首次运行会自动打开设备列表向导。推荐流程(多设备一键导入):
- 点击 云端导入
- 用小米账号 / 米家 App 扫描弹出的二维码登录
- 在设备列表中勾选一个或多个灯具,点击 确认导入
所有勾选的设备会带着 IP / Token / 型号自动进入设备列表。Token 仅写入本地 %APPDATA%\MiMonitorLightTray\config.json,不上传第三方服务器。
也可以点击 + 添加设备 逐个填写:
- 设备 IP:米家 App → 设备页面 → ⋮ → 更多设置 → 网络信息;或在路由器 DHCP 列表里找名称含
yeelight/monitor的设备 - miio Token:32 位十六进制串,可用 Xiaomi-cloud-tokens-extractor 或
miiocli cloud提取 - 显示名称:随意,会显示在弹窗上方
- 型号:留空即可,连接后自动识别
点击 测试连接 验证连通性,保存 后设备加入列表。可以对已添加的设备执行 编辑 / 删除,或按住行首 ⋮⋮ 图标 拖拽 调整显示顺序 —— 顺序决定弹窗中每个设备的显示位置。
- 左键单击托盘图标 → 在光标附近弹出控制窗
- 弹窗按设备列表顺序为每盏灯渲染一节:设备名 + 状态 + 独立 ⏻ 开关按钮,下方是亮度 / 色温滑杆
- 窗口高度按内容自适应:一盏灯与旧版差不多,两盏灯约翻倍高
- 底部按钮从右到左:⚙ 打开设置、⏻ 关闭所有在线灯
- 点击窗口外或按
Esc关闭弹窗 - 设备名过长时自动截断为
xxxx...,按钮位置保持固定,不会被挤出可视区
- 调整亮度 — 打开控制窗
- 桌面小部件 — 切换桌面小部件显示(当前小部件绑定第一盏灯)
- 设置 — 打开设备列表管理器
- 开机自启动 — 开关开机自启动
- 灯跟随软件启动 — 若任一设备启用,视为开
- 灯跟随软件关闭 — 若任一设备启用,视为开
- 灯随显示器休眠开关 — 若任一设备启用,视为开
- 系统休眠时关灯 — 若任一设备启用,视为开
- 系统唤醒时开灯 — 若任一设备启用,视为开
- 检查更新 — 手动检查 GitHub Release 新版本
- 启动时自动检查更新 — 开关自动更新检测
- 访问 GitHub 主页 — 在浏览器中打开项目主页
- 退出 — 关闭程序
托盘菜单里那几个"聚合视图"的开关只显示第一台设备的取反效果 — 想逐灯精确设置,请到 设置 → 编辑设备 里对每盏灯单独勾选。有新版本时托盘菜单会显示 🔔 提示并提供下载链接。
在 设置 → 编辑设备 底部的"快捷键设置"里,为每盏灯单独绑定:
- 点击快捷键输入框
- 按下想要的按键组合(如
Ctrl+Alt+Up) - 输入框自动填充,可再次修改
- 右键输入框直接清空
- 设置调整步进(默认 5,亮度按 1–100 直加减,色温按范围百分比换算)
- 保存
可用修饰键:Ctrl、Shift、Alt、Win
推荐组合示例:
- 亮度增加:
Ctrl+Alt+Up - 亮度降低:
Ctrl+Alt+Down - 色温增加:
Ctrl+Alt+Right(偏冷白) - 色温降低:
Ctrl+Alt+Left(偏暖白)
留空则禁用该功能。多设备场景下每盏灯必须使用不同的按键组合 — 系统级 RegisterHotKey 是独占的,重复绑定会失败。快捷键在设置保存后立即生效。
在 设置 界面的设备卡片上可以直接勾选 / 取消:
- 显示亮度调节 — 是否在弹窗中显示此设备的亮度滑杆
- 显示色温调节 — 是否在弹窗中显示此设备的色温滑杆
两个开关都关掉时,该设备不会出现在弹窗里(快捷键仍生效)—— 适合"只想快捷键控制、不想在弹窗里看到"的辅助灯。
右键托盘菜单点击 桌面小部件 即可在桌面显示一个常驻控制面板:
- 拖动标题区域移动位置
- 右键小部件可 锁定/解锁 位置(锁定后无法拖动,防止误碰)
- 位置、锁定状态、可见性自动持久化到
config.json的widget段
注意:桌面小部件当前只显示配置里第一盏灯(老单设备实现,多设备扩展在计划中)。要控制其它灯请用托盘弹窗或快捷键。
在托盘右键菜单或设备列表底部勾选"开机自启动"。本质是向 HKCU\Software\Microsoft\Windows\CurrentVersion\Run 写一条 MiMonitorLightTray,不需要管理员权限,只对当前用户生效。
每盏灯在设备编辑器里都有独立的五个开关:
- 灯跟随软件启动 — 程序启动时自动开这盏灯
- 灯跟随软件关闭 — 程序退出(含托盘"退出"、
Ctrl+C、任务栏关闭、Windows 关机)时自动关这盏灯 - 灯随显示器休眠开关 — 显示器休眠时关灯,唤醒时恢复休眠前状态
- 系统休眠时关灯 — 系统进入睡眠 / 休眠时关灯
- 系统唤醒时开灯 — 系统从睡眠 / 休眠恢复时开灯
每盏灯互不干扰:可以让台灯跟随软件启停、显示器挂灯跟随显示器休眠、床头灯只用系统休眠 / 唤醒 —— 组合自由。
底层实现:
- 显示器休眠通过
RegisterPowerSettingNotification订阅GUID_CONSOLE_DISPLAY_STATE,跟随 Windows 自身的显示器电源广播,不做独立空闲计时(看视频、听音乐时不会误关) - 系统休眠 / 唤醒监听
WM_POWERBROADCAST的PBT_APMSUSPEND/PBT_APMRESUMESUSPEND - 程序退出关灯走
atexit钩子 + 顶级窗口的WM_QUERYENDSESSION双保险,覆盖 Windows 强制关机场景
当灯处于关闭状态时拖动亮度或色温滑杆,程序会先发送开灯指令,再设置目标值。默认行为、无需开关 —— 避免"拖了半天没反应"(legacy Yeelight 由固件决定是否自动开,MIoT 协议则完全不会自动开)。
设备编辑器里的开关。适合以下情况:手上是新型 Yeelight / MIoT 设备、不在 _MIOT_MAPPINGS 白名单里、又怀疑它实际走 MIoT 协议。勾选后程序会用 lamp22 的通用 Light service spec((siid=2, piid=1/2/3) = power/brightness/color-temperature)尝试通信。设备不兼容时会持续报错;关掉即可回到 legacy 路径。
MiMonitorLightTray.exe --setup # 强制打开设备列表向导
MiMonitorLightTray.exe --debug # 开启调试日志pip install -e ".[build]"
python scripts/build_exe.py输出到 dist\MiMonitorLightTray.exe。脚本会用 PyInstaller 的 --onefile --noconsole,并通过 --collect-data miio 把 python-miio 的 YAML / JSON 规格文件一起打包(否则会在运行时崩溃)。构建脚本开头会自动执行 pip install -e . --no-deps --quiet 同步 dist-info,确保 EXE 报告的版本号与 pyproject.toml 一致。
pip install -e ".[dev]"
pytest -q测试覆盖配置序列化(tests/test_config.py)、托盘图标渲染(tests/test_icon.py)、miio 包装层与防抖器(tests/test_miio_client.py)。UI 与真实网络路径需要手动验证。
docs/ 目录是一个纯静态站点(无 Jekyll,靠 .nojekyll 跳过默认处理),包含:
- docs/index.html — 项目主页(特性介绍、UI 预览、下载按钮)
- docs/guide.html — 完整使用文档
- docs/releases.html — 版本发布说明
- docs/assets/ — CSS / JS / 图标
首次启用:Repo → Settings → Pages → Source 选 Deploy from a branch,Branch 选 main / /docs,保存后几十秒内 https://awakaze.github.io/MiMonitorLightTray/ 就能访问。
页面顶部下载按钮和版本号会通过 GitHub Releases API 自动填入最新版本,push 后不用手工同步版本号。
mi_monitor_light_tray/
__main__.py 入口:单例锁 → 加载配置 → 启动托盘、弹窗、快捷键
config.py AppConfig / DeviceConfig / WidgetConfig / HotkeyConfig
持久化(原子写入),含 v1.4→v1.5 单设备自动迁移
miio_client.py legacy Yeelight + MIoT 协议分发,线程安全 + 每设备 Debouncer
flyout.py 无边框弹窗,每设备一节,高度自适应,含"关闭所有灯"按钮
desktop_widget.py 桌面小部件(当前绑定第一盏灯)
device_list_wizard.py 设备列表管理器(增删 / 拖拽排序 / 云端导入 / 全局设置)
device_editor.py 单设备编辑对话框(IP / Token / 型号 / 电源策略 / 快捷键)
cloud_login_window.py 云端登录窗口(二维码 + 多选设备)
token_extractor/ 小米云 API 客户端:authentication + device list 拉取
hotkey_manager.py 全局快捷键管理(Windows RegisterHotKey,每设备独立 ID)
version_checker.py GitHub Release 版本检查(importlib.metadata 读版本)
icon.py Pillow 程序化绘制托盘图标(无二进制资源)
setup_wizard.py 首次运行时的空态引导,跳到 device_list_wizard
tray.py pystray 系统托盘控制器
shutdown_listener.py Windows WM_QUERYENDSESSION 监听,关机时关灯
monitor_sleep_listener.py Windows WM_POWERBROADCAST + GUID_CONSOLE_DISPLAY_STATE
single_instance.py Windows 命名互斥锁(单例保护)
discovery.py UDP 广播设备发现,按 device_id 重定位
scripts/
build_exe.py PyInstaller 打包脚本,构建前自动同步 dist-info
run_app.py PyInstaller 入口(避免相对导入问题)
tests/ pytest 单元测试套件
位置:%APPDATA%\MiMonitorLightTray\config.json
{
"devices": [
{
"id": "1a2b3c4d",
"ip": "192.168.1.100",
"token": "...32 位十六进制...",
"name": "显示器挂灯",
"model": "yeelink.light.lamp22",
"device_id": 12345678,
"enable_miot_for_unknown": false,
"power_on_at_startup": false,
"power_off_at_exit": false,
"power_off_on_monitor_sleep": false,
"power_off_on_system_suspend": false,
"power_on_on_system_resume": false,
"brightness_up": "Ctrl+Alt+Up",
"brightness_down": "Ctrl+Alt+Down",
"color_temp_up": "Ctrl+Alt+Right",
"color_temp_down": "Ctrl+Alt+Left",
"hotkey_step": 5,
"show_brightness": true,
"show_color_temp": true
}
],
"active_device_id": "ALL",
"widget": {
"visible": false,
"x": 100,
"y": 100,
"locked": true
},
"hotkey": {
"brightness_up": "",
"brightness_down": "",
"color_temp_up": "",
"color_temp_down": "",
"step": 5
},
"auto_check_update": true
}字段说明:
devices[]:所有设备的数组。可以是空数组(此时启动会进设备列表向导)devices[].id:稳定标识符,新设备是temp_xxxxxxxx,首次成功连接后自动升级为<device_id 的 8 位十六进制>devices[].device_id:首次连接时从 miioinfo()捕获,用于 IP 变化后的自动发现devices[].model:留空时启动时通过info()自动探测并回填devices[].enable_miot_for_unknown:未在_MIOT_MAPPINGS白名单的 Yeelight 设备强制走 MIoTdevices[].power_on_at_startup/power_off_at_exit/power_off_on_monitor_sleep/power_off_on_system_suspend/power_on_on_system_resume:五个独立电源策略开关devices[].brightness_up/brightness_down/color_temp_up/color_temp_down:本设备的四个全局快捷键devices[].hotkey_step:快捷键调整步进(亮度:加减 N,色温:按范围 N% 换算)devices[].show_brightness/show_color_temp:弹窗内此设备是否显示对应滑杆active_device_id:"ALL"保留字段(历史遗留,当前未使用)widget:桌面小部件位置 / 可见性 / 锁定状态hotkey:已废弃的旧全局快捷键段,仅为向后兼容保留,v1.5+ 使用每设备快捷键auto_check_update:启动时是否自动检查 GitHub Release
v1.4 → v1.5 迁移:程序首次读取旧配置时会自动把顶层 device 单对象转成 devices: [...] 数组并生成 id,用户无需手工处理。
Q:从 v1.4.x 升级后设备没了 / 报错
A:程序会自动把旧的 device 字段迁移为 devices 数组。如果没有生效,检查 %APPDATA%\MiMonitorLightTray\config.json 是否可读;实在不行删掉重新走一遍设备列表向导。
Q:多盏灯的快捷键冲突
A:系统级 RegisterHotKey 每个组合只能被注册一次,所以每盏灯必须用不同的快捷键。冲突时后注册的会失败并写入日志(--debug 可看到)。
Q:提示"已在运行"
A:程序已启动,检查系统托盘溢出区(右下角向上箭头)是否有图标。
Q:状态显示"离线 — Unable to discover the device"
A:
- 确认挂灯通电且与电脑在同一局域网
- 确认 IP 正确(用米家 App 或路由器复查)
- miio 走 UDP 54321,部分企业网络 / 防火墙会拦截,可临时关闭防火墙测试
- 程序会在后台自动尝试发现新 IP(如果
device_id已知)
Q:提示"miio error: Invalid token"
A:Token 在设备重新配对到米家时会刷新,需用 cloud-tokens-extractor 重新提取,或者用云端导入功能重新拉一次。
Q:托盘图标不显示
A:Windows 资源管理器可能把它收进了溢出区,点击托盘左侧的向上箭头查看。
Q:拖滑杆时灯有约 0.1 秒延迟
A:这是有意的防抖(120ms 亮度 / 180ms 色温),用来合并请求避免设备被刷爆,松开手后会立即生效。每盏灯有独立防抖器,多设备不会互相拖累。
Q:桌面小部件只显示一盏灯
A:小部件目前是旧的单设备实现,多设备场景请用托盘弹窗或快捷键。
- @zengzoxiong — 云端 Token 提取与桌面小部件功能(PR #1)
- python-miio — miio 协议库
- pystray — Python 系统托盘
- Pillow — 图标生成
- Twinkle Tray — UI 灵感