Skip to content

Releases: awakaze/MiMonitorLightTray

v1.5.2

Choose a tag to compare

@github-actions github-actions released this 01 Sep 09:51

v1.5.2

🐛 关键修复 · 稳定性补丁

v1.5.2 是 v1.5.1 休眠恢复大改之后的稳定性修复版,集中解决了 v1.5.1 上线后发现的两个严重 Bug:并发字典迭代导致的偶发崩溃,以及冷启动时托盘图标状态不刷新的问题。同时优化了 CI Release 流程,并完成了 GitHub 用户名从 Martlnezawakaze 的迁移。

🐛 Bug 修复

1. 字典并发 re-key 崩溃(#Critical)

触发路径:冷启动 model 为空的设备在首次连接成功后,_on_model_resolved 会对 _lights 字典做原地 re-key(_lights[new_id] = _lights.pop(old_id))。此时 Flyout 的 _open / _bg_refresh_all / _any_on / _on_toggle_all 以及 App._on_state_changed 都在用 live dict view 遍历 items() / values()。CPython 迭代器在版本戳变更时抛出 RuntimeError: dictionary changed size during iteration,UI 回调未捕获,会导致弹窗渲染中断或进程退出。

修复:5 处 _lights 遍历统一改为 list(self._lights.items()) / list(self._lights.values()) 快照。

新增测试tests/test_concurrency_regressions.py(4 passed · 1 skipped),覆盖:

  • list() 快照在高并发 re-key 压力下不崩溃
  • MonitorSleepListener.stop() 必须等待旧线程完全退出
  • 异常消息泵不会导致调用者死锁
  • 包含阳性对照用例(未打补丁时 live dict view 必抛 RuntimeError)

2. MonitorSleepListener 重启后双回调 → 唤醒不复原

触发路径_restart_power_listener 会先 stop() 旧监听器再启动新的。旧实现里 stop()PostMessage(WM_CLOSE) 就返回,没有 join 旧窗口线程。新监听器立即创建后,新旧两个 HWND 会同时订阅 PBT_POWERSETTINGCHANGE,同一个显示器关闭事件会触发两次 on_monitor_sleep:第二次调用读到 state.is_on=False(灯已经关了),覆盖了 pre_sleep_state。于是 on_monitor_wake 认为睡前就是关的,直接跳过恢复供电 —— 用户表现为「显示器息屏再点亮,灯不会自动恢复」。

修复stop() 对窗口线程执行 join(timeout=3.0);异常消息泵加 3s 安全帽,超时仅记录 warning 不会死锁调用者。

3. 灯启动时托盘图标没有变亮

触发路径:程序刚启动时托盘图标默认设为「暗(关)」,之后通过状态回调翻转。但初始化路径里存在状态推送窗口过早创建 / 事件顺序错乱导致的图标不刷新问题 —— 即使灯实际已经是开的,托盘图标依旧是暗色,直到第一次手动点弹窗才刷新。

修复main.py 重构了启动时的状态推送流程,确保灯的初始状态完整传递后再刷新托盘图标聚合态。

🔧 工程与基础设施

CI Release 自动读取 Release Notes

.github/workflows/build.yml 的 Release Job 现在会自动从 release-notes/RELEASE_NOTES_<tag>.md 读取 Markdown 内容作为 GitHub Release Body,不再需要手工粘贴。tag 名与文件名严格按 v1.5.2RELEASE_NOTES_v1.5.2.md 对应。

🧭 账号迁移

  • GitHub 用户名已从 Martlnez 变更为 awakaze
  • 仓库地址:https://github.com/awakaze/MiMonitorLightTray
  • 所有源码、配置、文档、Release Notes 中的旧 URL 均已同步更新
  • GitHub Pages 站点:https://awakaze.github.io/MiMonitorLightTray/

对比

v1.5.1 → v1.5.2 完整变更

v1.5.1

Choose a tag to compare

@github-actions github-actions released this 29 Aug 08:48

v1.5.1

针对 v1.5.0 多灯架构上线后用户反馈的两类问题做了集中修复:一是弹窗(Flyout)首次打开/刷新时的延迟和状态不一致,二是**电脑从休眠/显示器息屏恢复后状态一直"离线"**的致命 Bug。

整体效果:恢复后不手动操作任何按钮,10 秒内托盘图标和弹窗会自动回落到真实的亮度/色温/开关状态。

🐛 关键修复 · 休眠恢复永不离线

电源事件监听器从不关闭(#Critical)

v1.5.0 中 MonitorSleepListener 只有在至少勾选了一项「显示器息屏关灯 / 系统休眠关灯 / 唤醒开灯」时才会启动;如果用户三个复选框都没勾(最常见),系统唤醒广播 PBT_APMRESUMEAUTOMATIC 根本不会被接收 → 恢复后 UDP 会话已过期、缓存里全是超时的"离线"、只能手动点弹窗触发 refresh → 表现为一直显示离线

v1.5.1 无论勾选与否,都始终启动并常驻监听窗口。各回调内部再根据复选框决定是否发"开关灯"指令,但 refresh() 一定会执行。

恢复后多轮补刀刷新(覆盖 WiFi/Docking 网卡延迟就绪)

系统唤醒那一刻:

  • t + 0s:立即对所有设备发 refresh(),勾选了「唤醒开灯」的设备优先 set_power(True)
  • t + 3s:第一轮补刀。WiFi 连接和扩展坞网卡平均需要 1~3 秒恢复 DHCP/链路,第一轮 refresh 通常全部超时"不可达"
  • t + 8s:第二轮补刀。覆盖极慢的企业级 Wi-Fi / 需重新认证的热点 / USB 网卡

补刀轮只做 refresh() 不重发 power-on,避免中途用户手动关灯后被程序强制开回去。

显示器点亮 → 刷新全部设备(不再跳过未托管设备)

_on_monitor_wake 之前只对勾选了「显示器息屏关灯」的设备恢复供电;如果用户没勾这一项,长达几小时息屏后 UDP 会话已经失效,直到下次手动点弹窗之前,灯的滑杆一直显示陈旧的亮度/色温。

v1.5.1:显示器从 off → on 的一次广播会对所有设备并行 refresh。未托管的设备走 refresh,托管的设备按休眠前状态还原供电。

显示器息屏时也会完整记录每台设备的 pre-sleep 状态,不再只记录勾选了 sleep-shutdown 的设备。

✨ Flyout / 托盘图标体验大幅优化

打开弹窗秒显最后已知值

以前点击托盘图标后,弹窗会启动一个串行 _bg_refresh_all 线程逐个 refresh()。某台设备离线 → 2 秒 UDP 超时 → 下一台……整个弹窗卡死几秒。

现在打开弹窗:

  1. 先同步把缓存状态全部应用到 UI — 滑块位置、开关状态、文本立刻显示上次的值
  2. 为每台设备单独起线程并行 refresh — 一台慢不阻塞其余
  3. 每台设备拿到真实状态后通过 root.after(0, …) 回写

滑块初始值使用缓存不再硬编码

之前弹窗里的亮度滑块总是从 50 开始,色温从 4000 开始。打开后即使灯是 80% 亮度,滑块先跳到 50 再跳到 80,造成肉眼可见的抖动。

现在两个滑块都以 light.state.brightness / light.state.color_temp 为初始值并裁剪到合法范围内,打开即正确。后台 refresh 只会微调偏差,不会跳变。

离线时显示"最后已知状态 + (离线)"

之前设备不可达 → 状态标签直接显示「离线 — xxx error」或「离线」,用户不知道灯到底是开还是关,也没法判断是否需要重新点开关。

现在状态文案:

  • 可达 → 已开灯 / 已关灯
  • 离线 & 有错误信息 → 已开灯 (离线) / 已关灯 (离线)
  • 离线但没加载过错误 → 仍显示 已开灯 / 已关灯(缓存值)

用户一眼看到"灯上次记录是开的,现在离线",决策清晰。

底部 ⏻ 按钮:从"只能全关"升级为"智能总开关"

  • 任何一台灯为开 → 按钮高亮为亮色,点击全部关掉
  • 所有灯为关 → 按钮为暗色,点击全部打开
  • 不再跳过 reachable=False 的设备 — 之前如果唤醒后还没刷新到设备 cached 为 unreachable,会被静默跳过导致"按了没反应"
  • 每次 apply_state 后自动重算按钮颜色,与状态同步

托盘图标启动时不误导

启动瞬间图标默认设为"暗色(关)",等第一次状态回调后再翻转成真实的亮/暗。v1.5.0 启动后会先显示 2~3 秒"亮图标"然后闪一下变暗,给用户"灯被程序开了"的错觉。

✨ 设备名显示不再乱截断

阈值从 12 字符放宽到 34 字符,取消 Label(width=13) 固定列宽限制。

Mijia Computer Monitor Light Bar 2 这种 31 字符的官方英文名现在可以完整显示。超过 34 字符才会截断为 前 32 字符 + …

✨ 启动即并行刷新全部设备

旧逻辑:启动后只对 "缺 model / device_id == 0" 的设备 refresh,其余设备的状态全是「默认离线」。即使灯一直开着,托盘图标也是暗的,直到用户手动点弹窗。

新逻辑:启动时为所有完整配置的设备并行起线程 refresh(开机自动开灯的设备在那条流程里已经 refresh 了,不重复做)。托盘图标在启动几秒后就能落到真实的"至少有一台开着 / 全部关着"聚合态。

🧹 其他

  • power-on-on-system-resume / power-off-on-monitor-sleep 等复选框切换时 _restart_power_listener 与初始化保持一致(不再按旧的 need_listener 短路)
  • 日志:Monitor wake event / System resume event / Resume refresh round: t+Xs 都有 INFO/DEBUG 输出,便于用户排查"恢复后到底有没有刷新"

⚠️ 注意事项

  • v1.5.1 的电源策略复选框仍是 v1.5.0 的语义 — 只决定"是否主动开关灯";刷新行为是常驻的、不需要配置
  • 桌面小部件仍是单设备模式(配置列表第一台),多设备场景请仍使用托盘弹窗或快捷键
  • 三轮补刀刷新期间会产生 ~3× 的 UDP 广播(python-miio discovery),对家用路由无压力,但企业网络若有严格 ACL 请留意

对比

v1.5.0 → v1.5.1 完整变更

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 25 Jul 16:52

v1.5.0

✨ 新功能

多灯连接

弹窗(Flyout)重构

每设备独立配置

外加两项显示控制:

  • 显示亮度调节 — 是否在弹窗中显示此设备的亮度滑杆
  • 显示色温调节 — 是否在弹窗中显示此设备的色温滑杆

两个显示开关都关掉的设备不会出现在弹窗里(但快捷键仍生效)—— 适合"只想用快捷键控制、不想在弹窗里看到"的辅助灯。

每设备独立快捷键

  • 每盏灯拥有自己的四个全局快捷键:亮度 +/-、色温 +/-,以及独立的调整步进值
  • 快捷键在输入框内按下即捕获(点击输入框,按下想要的组合,自动填充)
  • 右键输入框直接清空(原先的实现之前是弹菜单,现在改为一步直达)
  • 使用 Windows 系统级 RegisterHotKey API,全屏游戏 / 全屏应用中也响应
  • 支持修饰键:Ctrl / Shift / Alt / Win
  • 留空即禁用;多设备下每盏灯必须使用不同的按键组合(系统级独占)

感谢所有反馈和建议!如有问题请在 Issues 提出。

Full Changelog: Martlnez/MiMonitorLightTray@v1.4.3...v1.5.0

v1.4.3

Choose a tag to compare

@github-actions github-actions released this 07 Jul 16:42

添加灯随显示器/系统休眠开关功能
修复更新检测问题
Full Changelog: Martlnez/MiMonitorLightTray@v1.4.2...v1.4.3

v1.4.2 - 快捷键清空功能

Choose a tag to compare

@awakaze awakaze released this 03 Jul 15:22

v1.4.2

🐛 Bug 修复

  • 快捷键清空功能 - 在快捷键输入框上右键,可通过「清空快捷键」菜单禁用不需要的快捷键

感谢所有反馈和建议!如有问题请在 Issues 提出。

Full Changelog: Martlnez/MiMonitorLightTray@v1.4.1...v1.4.2

Full Changelog: Martlnez/MiMonitorLightTray@v1.4.1...v1.4.2

v1.4.1 - 全局快捷键 + 自动更新检测

Choose a tag to compare

@awakaze awakaze released this 03 Jul 14:27

v1.4.1

🎮 全局快捷键

使用系统级热键调节亮度和色温,全屏游戏中也能响应。支持长按连续调整、按键录入配置。

🔔 自动更新检测

启动时后台检查 GitHub Release,有新版本弹窗提示,可在托盘菜单手动检查或关闭。


感谢所有反馈和建议!如有问题请在 Issues 提出。

Full Changelog: Martlnez/MiMonitorLightTray@v1.4.0...v1.4.1

v1.4.0 - 云端 Token 提取 + 桌面小部件

Choose a tag to compare

@awakaze awakaze released this 29 Jun 15:40

MiMonitorLightTray v1.4.0

🎉 主要更新

✨ 新增功能

云端 Token 自动提取

  • 在设置向导中添加「自动获取」按钮,无需手动运行外部工具
  • 支持小米账号二维码登录,安全快速
  • 自动获取设备列表,2×N 网格布局的设备选择界面
  • 自动填充设备 IP 和 Token

桌面小部件

  • 全新桌面小部件,可固定在桌面任意位置
  • 深色主题设计,与托盘弹窗 UI 一致
  • 支持拖动调整位置,可锁定/解锁
  • 圆角窗口效果,视觉更现代
  • 自动记忆位置、锁定状态和可见性
  • 不在任务栏显示,保持桌面整洁

🐛 Bug 修复

  • 修复空型号时无法控制设备的问题:当用户在设置中删除型号时,程序会在启动时自动检测设备型号并选择正确的协议(Legacy 或 MIoT),避免协议不匹配导致的控制失败
  • 为所有网络请求添加 10 秒超时设置,避免长时间卡顿

📝 完整变更

  • feat: 添加云端 Token 提取功能模块(小米账号认证、设备列表获取)
  • feat: 添加云端登录窗口(二维码/密码登录)
  • feat: 添加桌面小部件功能
  • feat: 设置向导集成「自动获取」按钮
  • feat: 桌面小部件支持记忆功能(位置、锁定状态、可见性)
  • feat: 优化桌面小部件 - 圆角窗口、拖动、锁定功能
  • fix: 空 model 时自动检测设备型号,避免协议不匹配
  • fix: 为所有网络请求添加超时设置(10秒)
  • fix: 隐藏桌面小部件在任务栏的显示
  • fix: 优化桌面小部件 UI 和状态更新

🙏 致谢

特别感谢 @zengzoxiong 贡献的云端 Token 提取和桌面小部件功能(PR #1),极大提升了用户体验!

📦 下载

请在本页面下方的 Assets 区域下载 MiMonitorLightTray.exe

💡 使用说明

云端 Token 获取

  1. 打开设置向导
  2. 点击「自动获取」按钮
  3. 使用小米账号扫码登录
  4. 从设备列表中选择您的台灯
  5. IP 和 Token 会自动填充

桌面小部件

  1. 右键托盘图标
  2. 选择「桌面小部件」
  3. 拖动调整位置
  4. 右键小部件可锁定/解锁位置

完整更新日志: Martlnez/MiMonitorLightTray@v1.3.2...v1.4.0

What's Changed

New Contributors

Full Changelog: Martlnez/MiMonitorLightTray@v1.3.2...v1.4.0

v1.3.2

Choose a tag to compare

@github-actions github-actions released this 29 Jun 06:18

v1.3.1

Choose a tag to compare

@github-actions github-actions released this 28 Jun 14:42

灯随软件开关 + MIoT 协议支持 + 兼容更多设备

v1.3.0

Choose a tag to compare

@github-actions github-actions released this 28 Jun 13:13

灯随软件开关 + MIoT 协议支持 + 兼容更多设备