点了个“更新”,全屋三台家电全变砖?Home Assistant 升级 Midea AC LAN 的6分钟卡死惊魂与底层 Deps 离线自愈实录
智能家居最让人心惊肉跳的瞬间,不是买来的新硬件配不上网,而是一个已经稳定运行了大半年的核心插件,在 HACS 里弹出了一个鲜红的更新提示。你顺手点了一下「更新」,重启系统后,不仅设备全部失联,连整个智能家居中枢都在启动过程中僵死在半路上。
2026 年 10 月 26 日,我针对家里 Home Assistant 系统中的 Midea AC LAN 集成(负责接管全屋的美的滚筒洗衣机、洗碗机与燃气热水器)做了一次日常版本升级升级评估与实操。从 v2026.9.1 升级到 v2026.10.0,看似只是一个小版本迭代,背后却险象环生:启动流程足足卡死超过 6 分钟、三台核心大件全部显示「无法加载」、控制实体属性大面积变动,以及境内弱网环境下 Python 包管理器的致命缺陷。
这篇文章将完整复盘这场历时近两小时的排障与架构深潜:不仅有详尽的现象分析、源码考古与生活化比方,更有经过生产环境真实验证的零侵入离线自愈方案,以及支持 Windows 11、Ubuntu 26.04 和 macOS 27 的一键自动化脚本。

图 1:本文原创题图。展示了本次升级涉及的三台核心大家电、启动阶段的 Stage 2 阻塞超时,以及最终通过规范目录实现的零侵入离线挂载。
一、问题背景:承载全家生活的局域网中枢
在智能家居架构中,白电(大家电)的接入地位极为特殊。温湿度计或人体传感器偶尔掉线,顶多是灯光联动稍慢一秒;但洗衣机、洗碗机和热水器,是直接与水路、强电和燃气打交道的重型设备。
我的 Home Assistant 部署在局域网专用的独立服务器上(运行最新的 Home Assistant OS,Core 版本为 2026.10.4,底层 Python 运行时为 3.14)。为了彻底摆脱厂商云端断网、服务器维护或延迟过高的限制,家里的美的设备全部通过经典的开源第三方集成 midea_ac_lan 走局域网纯本地协议交互:
| 设备名称 | 硬件型号 / 协议识别码 | 协议版本 | 接管控制与传感器职能 |
|---|---|---|---|
| 美的滚筒洗衣机 | 38111463 / Type 0xDB | V2 局域网协议 | 运行进度、洗涤程序、水温档位、脱水转速、剩余时间 |
| 美的智能洗碗机 H5 | 000000H5 / Type 0xE1 | V3 局域网协议 | 门状态、漂洗剂与软水盐告警、洗涤模式、童锁、电源 |
| 美的燃气热水器 | 5110188E / Type 0xE3 | V3 局域网协议 | 出水水温、燃烧状态火焰感应、零冷水循环、运行保护 |
这三台设备总共衍生出 34 个实体,长期嵌入在 Lovelace 首页和自动化大屏中。
当天下午,HACS(Home Assistant Community Store)弹出了 Midea AC LAN 的新版本提醒:从本地运行的 v2026.9.1 推送至 v2026.10.0。作者在 Release 说明中提到了多项稳定性增强、对新设备类型的支持以及优雅停机时的连接断开修复。
从表面上看,这是一个非常常规的小版本更新。然而,当升级指令下发后,平静的家庭局域网瞬间被打破。
图 2:真实系统截图。Home Assistant 集成管理看板中正常工作的 Midea AC LAN 模块。它同时管理着滚筒洗衣机、洗碗机和燃气热水器。
二、问题表现:漫长的 6 分钟卡死与全线瘫痪
按照通常习惯,如果在 HACS 界面直接点击「更新」并重启,接下来会遭遇令人绝望的连锁灾难。
在测试环境中,我们先通过隔离工具将新版集成文件写入 custom_components/midea_ac_lan/,然后下发了重启命令。通常情况下,这台高性能主机的 Home Assistant Core 重启只需要 15 到 20 秒。但这一次,倒计时在浏览器界面上转了一圈又一圈,整整 5 分钟过去了,Web 控制台依然毫无响应。
通过底层宿主机抓取实时日志,我们看到了令人震惊的场景:
- 启动流程被硬生生阻断:系统卡在 Stage 2 初始化阶段,日志中反复刷出
[homeassistant.bootstrap] Waiting on tasks: {<Task pending name=‘setup component midea_ac_lan’…>}。 - 触发超时强行跳过:足足等待了 360 秒(6 分钟)后,Home Assistant Core 的看门狗计时器终于忍无可忍,抛出警告:
Something is blocking Home Assistant from wrapping up the start up phase. We’re going to continue anyway.。 - 全线加载失败:虽然整个中枢终于勉强挤进了运行态,但打开「设置 → 设备与集成」,Midea AC LAN 旗下的三个条目(洗衣机、洗碗机、热水器)全部呈现暗红色的
not_loaded(未加载)状态! - 核心功能暴毙:在设备调试面板中,新版代码抛出了致命异常:
TypeError: device_selector() got an unexpected keyword argument ‘sn8’。
为什么更新一个家电集成,不仅让设备全废,还会导致整个 Home Assistant 启动过程像被水泥浇筑了一样卡死 6 分钟?
三、生动比方:开学典礼上的慢速快递员
为了让即使没有软件工程背景的读者、甚至家里上小学的小朋友也能秒懂这里面的玄机,我们可以把 Home Assistant 的启动过程比作一场「全校开学典礼」。

图 3:本文原创示意图。用生活中的开学典礼、校门口安检与课桌专用书袋,通俗比拟依赖拉取卡死、假离线挂载与真实解决路径。
1. 现象:开学典礼被迫暂停 6 分钟
想象一下,开学第一天早上,全校师生(灯光、网关、传感器、面板)都站在操场上,校长准备宣布典礼开始(系统进入 RUNNING 状态)。
这时负责考勤的主任(Core 启动器)拿起一张装备清单(插件的 manifest.json),走到「小美同学」(Midea 集成)面前,发现清单上写着:「今天上课必须携带 2026 最新版的美的说明书(midea-lan==2026.10.0)」。
主任一看小美书包里没有这本书,便立即派出一个快递员去外省总仓库(PyPI 镜像源 files.pythonhosted.org)去取。
偏偏那天高速公路上大堵车,网络信号极其恶劣,快递员骑着一辆破旧的自行车,一秒钟只能往前挪几厘米(下载速度只有可怜的 10 KB/s)。更要命的是,学校规定:开学典礼必须所有人装备齐全才能宣布开始!
于是,全操场几千名师生在凄风冷雨中足足干等了 6 分钟!直到校长实在冻得受不了了,才吹哨强行宣布开幕,但由于小美同学终究没拿到书,被当场罚站(集成标记为 not_loaded),今天的所有课都无法上了。
2. 误区一:把书扔在校门口地上(/config 假离线)
有人可能会问:我提前把这本说明书从别的地方下载好,扔在学校大门口的过道上(即把 midealan 放在 /config/ 根目录),不就不用派快递员了吗?
这就引出了后面我们要深剖的代码假象:学校的保洁门卫大爷只有在引导客人进校门的一瞬间(import custom_components)会低头看一下大门口;等真正上课检查装备时,大爷根本不看门口地上堆的杂物!所以你扔在门外的书,老师根本不知道,依然会派快递员去外省跑腿。
3. 误区二:带了一张光盘,安检员非要打电话国际长途(file:// 轮子陷阱)
又有人想:那我给老师带一张存了说明书的光盘(本地 file://…whl)行不行?
不行!因为学校的装备安检员有个不可理喻的强迫症规定(执行 uv pip install 时被强制追加了 –upgrade 升级参数)。安检员拿到你的光盘后,非要拿起长途电话,向跨国出版总部重新核对一遍:这本书里提到的标点符号有没有更新的版本?结果电话线又被卡死在越洋慢速线路上了。
4. 黄金正解:课桌里预留的专用暗格(/config/deps 目录)
那怎样才能既不打电话、又不派快递员呢?
深入翻阅学校的百年规章(Home Assistant Core 官方启动代码)后,我们发现:校长早在每个学生的课桌最深处,设计了一个专用的「免检暗格」(路径为 /config/deps/lib/python3.14/site-packages/)。
只要你提前把印有官方防伪钢印(.dist-info)的正版说明书整整齐齐放进这个暗格里,老师一进门伸手一摸,发现书已经在暗格中躺得好好的,便当场打勾放行!开学典礼 1 秒钟顺利举行,全校皆大欢喜。
四、问题深度分析:双重陷阱与代码考古
回到严肃的技术细节。导致这次升级灾难的,实际上是两记环环相扣的暗箭:
图 4:真实运行环境日志快照。清清楚楚记录了 homeassistant.bootstrap 在 Stage 2 中因等待 setup component midea_ac_lan 耗尽 360 秒超时的全过程。
1. 第一重陷阱:版本参数断崖式不兼容
Midea AC LAN 本身只是一个对接 Home Assistant 的外壳界面,真正解析美的电器的网络二进制报文、加解密通信密钥(Token/Key)以及匹配设备型号协议的核心,是一个名为 midea-lan 的独立 Python 伴生库。
在旧版本 v2026.9.1 中,集成依赖的是 midea-lan 2026.9.1;而在新版 v2026.10.0 中,集成代码重构了设备选择器,调用方式变为:
device_selector(
device_type,
device_id,
ip_address,
port,
token,
key,
protocol,
model,
sn8, # 新增参数
manufacturer_code, # 新增参数
cloud_name # 新增参数
)
然而,旧版的 midea-lan 2026.9.1 函数定义里根本没有这三个新参数!
如果系统在升级集成时,未能同步将底层的 midea-lan 库替换为 2026.10.0,那么任何一台美的设备在执行 async_setup_entry 时,都会瞬间抛出 TypeError 异常,直接崩溃。
2. 第二重陷阱:假离线挂载与 sys.path 的障眼法
你可能会好奇,既然依赖库这么重要,之前系统难道一直是在线联网下载的吗?
这里就隐藏着许多智能家居老玩家和维护脚本都会踩中的「认知误区」。在之前的运维记录中,曾有人将 midea-lan 2026.9.1 手动解压放到了配置根目录 /config/midealan/ 下,误以为这样就能实现「离线 Vendoring」。
但通过分析 Home Assistant 2026.10 的核心加载源码 homeassistant/loader.py(第 1709 至 1713 行),真相水落石出:
# homeassistant/loader.py 片段
try:
sys.path.insert(0, config_dir)
# 仅在此处动态 import custom_components
integration = importlib.import_module(f"{CUSTOM_COMPONENTS}.{domain}")
finally:
# 扫描与初次引入完成后,立刻将 config_dir 从 sys.path 彻底剔除!
sys.path.remove(config_dir)
原来,Home Assistant 只在最开始探测自定义集成模块的瞬间,极其短暂地将 /config 目录推入内存中的 sys.path;随后立刻将其移出!
在后续的常规运行期、以及核心类库判断依赖是否满足的 is_installed() 阶段,/config 根本不在 Python 的模块搜索路径里。之前之所以能跑,完全是因为当时碰巧在容器或虚拟环境的系统全局 site-packages 里安装成功过;放在 /config 根目录下的文件,从始至终都是摆设!

图 5:本文原创架构图。深度剖析了 loader.py 的临时挂载、package.py 的强制 upgrade 网络重试,以及 bootstrap.py 中永久注入的 user-site 机制。
3. 第三重陷阱:uv pip –upgrade 的网络黑洞
Home Assistant 从 2024 年底开始,全面引入了极速的 Python 包管理工具 uv 代替传统的 pip。这本来是一项提升性能的壮举,但在国内弱网环境下,却演化成了一个噩梦。
当集成在 manifest.json 中声明了:
{
"domain": "midea_ac_lan",
"requirements": ["midea-lan==2026.10.0"]
}
Core 在启动时会通过 homeassistant.util.package.is_installed() 进行校验。由于上面提到的假离线失效,Core 认为这个包没有安装,于是调用:
uv pip install --upgrade midea-lan==2026.10.0
在用户的家庭网络环境下,访问海外的 files.pythonhosted.org 速度经常跌落至 10 KB/s 以下。一个 330 KB 的 Wheel 包,下载需要数分钟甚至更久,期间一旦触发 TLS 握手重试或数据包中断,uv 就会挂起重试。
更有甚者,有人尝试把 manifest 改成指向本地文件:
{
"requirements": ["file:///config/wheels/midea_lan-2026.10.0-py3-none-any.whl"]
}
这依然会卡死!因为 Core 调用安装命令时,写死了 –upgrade 标志。根据 PEP 规范与 uv 的解析逻辑,带有 –upgrade 时,包解析器会强行连网查询该包的所有间接依赖是否在 PyPI 上有更新版本。只要宿主机无法顺畅连接外网,这个网络重试黑洞就会直接将 Home Assistant 拖入长达 6 分钟的 Stage 2 启动死锁中!
五、问题根因与破局点:寻找官方认可的生路
既然改 manifest.json 会破坏版本定义且触发联网检查,放 /config 根目录又无效,官方到底留没留下纯离线、零侵入的解决方案?
答案就藏在 Home Assistant 启动引导器 homeassistant/bootstrap.py 中。
通过查阅 2026.10.4 的源码,我们锁定了函数 async_mount_local_lib_path:
async def async_mount_local_lib_path(config_dir: str) -> str:
"""Add local library to Python Path.
This function is a coroutine.
"""
deps_dir = os.path.join(config_dir, "deps")
if (lib_dir := await async_get_user_site(deps_dir)) not in sys.path:
sys.path.insert(0, lib_dir)
return deps_dir
这里的逻辑非常清晰而优雅:
- 官方保留的专用目录:在配置目录下,有一个专为本地依赖预留的
deps/体系。 - 永久置顶 sys.path[0]:系统在 Stage 0 引导的最开始,就会通过
async_get_user_site找到对应的 Python 版本目录(例如/config/deps/lib/python3.14/site-packages),并将其直接插入到 Python 搜索路径的最顶端(sys.path[0])! - 完美阻断联网安装:在后续检查依赖时,
importlib.metadata会首先扫描sys.path[0]。如果我们在该目录下同时放置了解压后的代码包(midealan/)和元数据分发信息包(midea_lan-2026.10.0.dist-info/),is_installed(“midea-lan==2026.10.0”)将当场返回True! - 保持集成发布包的绝对纯净:官方
manifest.json不需要做任何篡改,完全维持midea-lan==2026.10.0的官方声明。以后即使官方发布热修复或通过 Git 同步,都不会发生配置冲突。
图 6:现场环境的目录结构快照。确认 midealan 代码目录与 .dist-info 规范放置在 Python 3.14 的 site-packages 路径下。
六、如何解决问题:从离线注入到闭环验收
理清了底层原理,解决方案的实施路径就变得清晰而极其稳健。整个实施过程严格遵循生产级变更标准,分为五个关键阶段:
阶段一:宿主机离线拉取与双重哈希校验
我们在外围工作机(能够稳定访问海外源的 Mac 电脑)上,通过高带宽通道直接下载对应的发布制品,并在本地完成 SHA256 完整性核对:
- 集成源码包:GitHub Tag 源码 ZIP(sha256 校验值为
56fe36ef…9591,确认与官方 Release 逐字节吻合)。 - 依赖类库:PyPI 官方发布的纯 Python Wheel 轮子
midea_lan-2026.10.0-py3-none-any.whl(sha256 校验值为1aef9186…e56d,确认无损坏)。
阶段二:生产环境旧资产全量备份
在进行任何写入之前,通过自动化运维探针对 Home Assistant 上的原有资产执行严格备份:
- 备份
custom_components/midea_ac_lan/目录下的所有文件; - 备份旧版
/config/midealan和历史遗留的midea_lan-2026.9.1.dist-info; - 累计归档 123 个历史资产文件,确保任何异常均可一键回滚。
阶段三:规范化 Deps 注入与旧文件清理
- 目录创建:在 Home Assistant 端建立严格匹配当前 Python 运行时版本的依赖目录:
/config/deps/lib/python3.14/site-packages/。 - 解包注入:将 Wheel 包解压,把其中的
midealan/代码包和midea_lan-2026.10.0.dist-info/元数据包同步推送到上述目录中,并逐文件校验大小。 - 写入集成:将
custom_components/midea_ac_lan/的 32 个新版文件全量写入,并维持未经修改的官方manifest.json。 - 卫生清理:彻底删除过去留在
/config根目录下的废弃midealan目录及临时目录,消除一切路径干扰。
阶段四:配置校验与安全重启
在下发重启指令前,调用 Home Assistant 官方的 check_config 服务:
- 确认 YAML 配置校验结果为
valid,无任何报错或警告; - 触发优雅重启;
- 这一次,没有了 10 KB/s 的网络死锁,Home Assistant 在 18 秒内秒级完成冷启动!
- 核心状态立刻跃升为
RUNNING,Stage 2 耗时缩短至毫秒级。
阶段五:设备状态机核对与实体分流治理
重启完成后,我们通过 WebSocket 接口抓取三台核心电器的加载状态:
- 美的滚筒洗衣机:
loaded; - 美的智能洗碗机:
loaded; - 美的燃气热水器:
loaded。
原有的 34 个基础实体全部完好保留,历史曲线平滑延续。
图 7:洗碗机设备详情页面。展示了新版规范命名并默认禁用的 11 个控制实体,以及正常工作的状态汇报。
图 8:美的滚筒洗衣机设备页面。水温、脱水速度、剩余时间和运行阶段传感器数据均精准保持。
图 9:燃气热水器详情页面。清晰展示了当前水温、燃烧状态传感器与零冷水开关联动。
此时,还有两处细微但至关重要的「新版行为变动」需要人工接管处理:
- 洗碗机新增 11 个实验性实体:新版集成对洗碗机默认开启了「开始、预约开始、暂停、恢复、取消」等 5 个动作按钮,以及程序选择、预约时长、自动开门等开关。由于 H5 这款硬件是否完全支持远程通过网络触发启动尚存不确定性,为了防止误触引发漏水或干烧风险,我们将这些新增实体统一重命名为
.mei_de_xi_wan_ji_规范格式,并在实体注册表中将其标记为disabled_by: user(安全禁用)。后续有实际需要时,可在 UI 中单独开启。 - 状态值格式变更为纯小写:新版代码将洗碗机和洗衣机的原始枚举值,由以前的首字母大写改为了小写 Key(例如
Running→running,ECO Wash→eco_wash,Idle→idle,Power Off→power_off)。由于上游集成的简体中文语言包尚未补充这些状态的翻译映射,Lovelace 面板上会直接显示英文原值。如果你有基于状态文字匹配的自动化脚本,需要同步核对是否受到影响。
图 10:HACS 集成管理卡片。已成功与上游 v2026.10.0 版本对齐,移除了更新角标。
七、全平台一键离线升级工具与脚本
为了让遇到同样弱网超时困扰、或者希望在未来的版本更新中一劳永逸避坑的玩家能够轻松落地,我们开发了配套的自动化离线注入工具集。
该工具完全基于 Python 3 标准库构建,零第三方 pip 依赖,支持本地离线校验、自动探测 Python 运行时版本、自动构建 deps 目录并安全重启验证。

图 11:本文原创流程图。涵盖了三端自动化脚本从环境探针、离线哈希防篡改、隔离解包到闭环验证的完整流水线。
代码已开源并提供打包下载:
- 工具包完整下载:midea-deps-toolkit.zip
- 核心实现源码:midea_deps_toolkit.py
方法 A:人工自动执行(三端一键命令行)
在本地电脑上下载解压工具包后,打开对应系统的终端,运行单条指令即可。程序会自动检查环境并在隐藏密码提示下交互式读取 Token,杜绝凭据泄漏风险:
1. Windows 11(PowerShell 7 / Windows PowerShell)
powershell -NoProfile -ExecutionPolicy Bypass -File .\run-windows11.ps1 -Apply
说明:这里的执行策略覆盖仅作用于当前的 PowerShell 单次会话,不会修改全局系统安全策略。
2. Ubuntu 26.04 LTS(Bash)
bash ./run-ubuntu2604.sh --apply
3. macOS 27(Zsh)
zsh ./run-macos27.zsh --apply
若不带 –apply 参数,工具默认只执行「只读探测」,会输出当前 Home Assistant 版本、Python 目录规范以及 Midea 实体的在线情况,绝不会擅自修改服务端的任何文件。
方法 B:Agent 自动化配置方案
如果你日常使用具备命令行调用能力的 AI Agent(如 Claude Code、OpenCode 或专用运维智能体),可以将工具包解压到工作区,并将下述任务提示词直接托付给 Agent:
请使用当前目录中的 midea_deps_toolkit.py 对我的 Home Assistant 进行 Midea AC LAN 离线依赖升级与加固。
从环境变量 HA_URL 读取中枢地址,从 HA_TOKEN 读取长期访问令牌,严禁在控制台打印令牌或完整 IP 地址。
第一步:先执行只读评估:
python3 midea_deps_toolkit.py --non-interactive
第二步:核对探测到的 Python 版本后,执行安全离线依赖解包与升级:
python3 midea_deps_toolkit.py --non-interactive --apply
任务要求:
1. 下载 Release ZIP 与 midea-lan 2026.10.0 wheel 并执行 SHA256 完整性核对;
2. 在服务端严格注入至 /config/deps/lib/python3.14/site-packages/,禁止修改 manifest.json 原文;
3. 清理 /config 根目录下的历史游离 midealan 目录;
4. 调用 check_config 服务并在合法的前提下重启 Home Assistant;
5. 重启完成后通过 API 验证洗衣机、洗碗机、热水器三个条目状态均为 loaded;
6. 检查洗碗机新增的实体,将其统一重命名并安全禁用。
图 12:整理完成后正常运转的「我的家」大屏控制台。美的洗衣机、洗碗机和热水器在概览页上稳定更新。
八、常见问题 Q&A
Q1:为什么我直接在 HACS 点更新后,每次重启都要卡很久?
这是典型的 uv pip install –upgrade 弱网超时。集成在 manifest 里写了依赖要求,系统发现本地没有装,便在每次启动时尝试联网拉取。由于国内访问国外下载源极慢,看门狗计时器每次都会硬等数分钟直到超时。按照本文方法把依赖放进 /config/deps/lib/pythonX.Y/site-packages/ 后,系统直接判定依赖已满足,启动立刻恢复秒级。
Q2:未来 Home Assistant 升级大版本(比如从 Python 3.14 升到 Python 3.15)该怎么办?
deps/lib/ 下的目录名称是严格绑定 Python 大小版本的。当未来 Home Assistant Core 升级其底层的 Python 运行时小版本时,你需要把旧版本目录下的 site-packages 内容复制或迁移到对应的新版本目录(例如 deps/lib/python3.15/site-packages)中即可。本文提供的工具支持 –python-ver 参数,可以秒级完成新目录的构建。
Q3:为什么不建议把 manifest.json 改成 file:// 本地 wheel?
首先,改动第三方集成的 manifest 会导致它失去官方源码的完整性,以后 HACS 检测或者更新时会经常提示文件冲突;其次,更关键的是 Home Assistant 调用底层 uv 时附带了 –upgrade 标志,即便你指向了本地 wheel 文件,uv 依然会发起网络请求重新验证依赖树,弱网环境下依然会发生超时卡死。
Q4:面板上的洗碗机状态显示为「power_off」或「idle」,能改成中文吗?
可以。新版上游代码只翻译了实体名称,未提供状态值的多语言映射。你可以通过在 configuration.yaml 中建立简单的模板传感器(Template Sensor),使用映射字典将 power_off 转换为「已关机」、running 转换为「运行中」、eco_wash 转换为「节能洗」,并在前端 Lovelace 卡片上引用该模板传感器,即可恢复原汁原味的优雅中文显示。
Q5:这套方案需要公网连接或第三方中转服务吗?
完全不需要。本文的所有工具、脚本和流程均完全运行在内网本地环境中,下载依赖是在你的外围电脑上完成并验证 SHA256,所有向 Home Assistant 的推送与调用全部基于局域网官方 REST API。既不依赖任何第三方平台,也不泄露任何家庭网络隐私。
参考资料与文献
- Home Assistant 官方开发者文档:集成架构与清单规范 (Manifest Specification)
- Home Assistant 官方文档:异步启动引导机制 (Bootstrap Implementation)
- PEP 370:Per user site-packages Directory 规范
- Midea AC LAN 开源仓库与发布说明
- Python 官方 importlib.metadata 运行时元数据查找规范
- Home Assistant REST & WebSocket 官方交互协议指南
文中的 Home Assistant 品牌标志来自官方开源资产,原理图与流程图均为本文原创绘制。界面截图均源自本次真实运行环境,所有网络 IP、机器标识、个人账户及敏感用能数值已做不透明脱敏遮蔽。







