跳转至

HAOS 升级与回滚实战:6 步安全升级 + 3 个失败事故复盘

HA 跑稳之后,最让人紧张的操作不是装第一个 addon,是升级。装完 HA 第一个月你会觉得一切尽在掌握,第二个月开始写第一个自动化,第三个月家里加了 5 个智能设备、10 条自动化、2 个摄像头——这时候某次 OTA 卡 99%、或者升级后 MQTT 断连、或者addon 集体崩溃,就是从"玩玩具"到"真运维"的分水岭。

我在 J4125 上跑 HAOS 快两年了,累计升级 12 次以上,其中 3 次翻车,最严重的一次直接让我凌晨爬起来刷 NVMe。这篇文章就是把这 3 次事故踩出来的东西系统总结:6 步升级前检查 + 3 个真实事故复盘 + 回滚决策树。

顺带说一下 HAOS vs HA Container 的升级差异:HAOS 是整台机器升级(系统 + Supervisor + HA Core 一起动),失败就整台重来;Container 只升级 HA Core 那个容器,数据卷不动,回退成本低。这不是说 Container 更安全,而是失败模式不同——Container 挂了你大概率不用刷盘,HAOS 挂了你基本要进 Recovery 模式。

一、为什么要专门讲升级

HAOS 的升级模型跟 Android OTA 很像:下载固件 → 校验 → 写到 A/B 分区之一 → 下次启动走新分区。听起来很安全,实际有几个坑:

  1. A/B 分区写入会耗光 SD 卡写寿命——树莓派用户 6 个月就 SD 变砖的概率不低
  2. Recovery 模式是唯一救火入口——一旦当前分区损坏,进不了 HA 就要进 Recovery 刷机
  3. 升级过程 HA 完全不可用——所有自动化、传感器、MQTT 断连,家庭场景下门锁和摄像头也会一起断
  4. HAOS 不支持"回退到上一个版本"——只有"重新刷",没有"回滚"

Container 部署就没这些限制:docker pull 换镜像、docker run 起来、不行删掉重来,数据卷 /config 一直挂载不动。代价是你要自己管 Supervisor、管 addon、管 HAOS 层面的东西(比如 NTP、防火墙)。

所以选完部署模式,升级流程是不一样的。下面所有流程默认 HAOS,最后单独讲 Container。

二、升级前 6 步检查清单

这是我最重要的一张 checklist,每次升级我会截图保存到运维笔记本。跳过任何一步都是赌博。

Step 1: 全量备份

不是"点一下 Supervisor 备份"就完事,要三层:

1. Supervisor UI 备份(Settings → System → Backups)
   - 勾选 Database + 所有 addon + 配置
   - 加密,密钥抄在纸上放抽屉
   - 下载到本机一份

2. 数据库单独备份 addon(Database Backup)
   - 单独生成 state.json 压缩包
   - 用 rsync 或 sftp 拉到 NAS

3. /data 目录手工备份(SSH 进去)
   ssh [email protected]
   tar -czf /data/ha-full-$(date +%Y%m%d).tar.gz \
     --exclude='/data/rfstack' \
     /usr /etc /root /home

第一层是官方机制,第二层是"以防万一",第三层是"以防万一的以防万一"。J4125 有 256GB NVMe,备份随便打;树莓派 32GB 卡就要精打细算。

Step 2: 分区空间检查

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/disk/by-label/ROOT   22G  14G  6.2G  69% /
/dev/disk/by-label/HOMASS 918M  342M  575M  38% /homeassistant
/dev/disk/by-label/DATA   22G  8.4G  12G  42% /data

门槛:根分区剩余 < 20% 就别升级。OTA 下载固件本身就 200-300MB,写入 A/B 分区时还要预留临时空间。低于 20% 会直接触发事故 3(下面会讲)。

清理策略: - /data/rfstack 可以清空(Zigbee 会重扫) - docker system prune -af 清 addon 缓存(先停 addon) - /data/log 下的旧日志删掉

Step 3: Addon 版本兼容性检查

进 Settings → Add-ons,把每个 addon 的 Changelog 翻一遍。特别关注:

  • 官方 addon(HA Supervisor、Database Backup、Network Utility、Studio Code Server)——一般 48h 内跟进
  • 社区 addon(Mosquitto、Mosquitto Logger、File Editor、Nginx Proxy Manager、Node-RED、ESPHome)——跟 HA 版本发布节奏对齐
  • AppDaemon / HACS / MaterialUI——最容易落后

一个 addon 版本落后,HA 启动时不会崩,但升级后可能因为 Python 库版本问题起不来。升级前把 addon 全部升到最新,比升级后挨个救简单得多。

Step 4: DNS 与 NTP 检查

# 检查 DNS
nslookup cloud.homeassistant.io
# 应该返回真实 IP,不是 0.0.0.0 或超时

# 检查 NTP
timedatectl
                Local time: Mon 2026-10-26 03:12:44 CST
Universal time: Sun 2026-10-25 19:12:44 UTC
              Time zone: Asia/Shanghai (CST, +0800)
NTP service: active

DNS 不对会导致 OTA 下载失败,NTP 不对会导致证书校验失败。家庭路由器里如果启用了 DNS 广告过滤(如 Pi-hole),记得把 *.homeassistant.io 加白名单。

Step 5: 网络可达性检查

在升级前用 SSH 或 Network Utility addon 测一下这几个端点:

# HA Cloud
curl -I https://cloud.homeassistant.io

# GitHub(HACS、addon 更新都会用)
curl -I https://github.com

# MQTT Broker(如果自建)
mosquitto_sub -h mqtt.local -p 1883 -t '#' -C 1 -v

# Zigbee 协调器
ping -c 3 zigbee.local

任何一个不通,先修网络再升级。升级过程中 HA 会主动拉新固件,网络抖动 = 卡 99%。

Step 6: 记录当前版本与依赖状态

版本快照(升级前):
- HAOS: 12.4
- HA Core: 2024.11.2
- Supervisor: 2024.11.1
- Hostname: ha.local
- 硬件: J4125 + NVMe 256GB
- 依赖服务:
  * MQTT: broker 在 192.168.1.50,正常运行
  * Zigbee: ZHA + ConBee II,22 个设备
  * 摄像头: 4 台 ONVIF,走本地 NAS 存储
  * 自动化: 47 条,其中 3 条依赖 Zigbee
  * 定时任务: 4 个(备份、镜像、日志清理)

这份记录的作用是——升级失败时,你能精确对比"升级前 OK 的项目"和"升级后异常的项目"。

三、OTA 升级流程深度

方式一:Web UI(推荐家用)

  1. Settings → System → 右上角菜单 → Check for updates
  2. 如果有更新,显示 New version available: 2025.1.0
  3. 点 Restart and install → HA 关闭 → 下载固件 → 写分区 → 重启
  4. 全程不需要人工干预,UI 变灰,浏览器页面会挂

方式二:REST API(推荐给团队批量部署)

TOKEN=eyJhbGciOiJIUzI1NiIs...   # 从配置 → 安全 → 长期访问令牌生成

# 触发升级
curl -X POST https://ha.local:8123/api/supervisor/core/update \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json"

# 查询状态
curl https://ha.local:8123/api/supervisor/core/info \
  -H "Authorization: Bearer $TOKEN" | jq

方式三:SSH + 命令(推荐给远程运维)

ssh [email protected]

# 触发下载
sudo systemctl stop homeassistant
supervisor-core update

# 或者直接调 Supervisor API
curl -X POST http://localhost:8080/supervisor/core/update

四、HAOS vs Container 升级对比

维度 HAOS Container
升级粒度 HAOS + Supervisor + HA Core 一起 只升 HA Core
升级方式 Web UI / OTA docker pull + docker run
时长 5-15 分钟 1-3 分钟
失败模式 可能 A/B 分区损坏,进 Recovery 容器起不来,删掉重来
回滚 只能重新刷固件 改 tag 重启容器
数据保存 /data 目录不动 /config 挂载不动
升级期间 HA 可用 否 可以停容器期间短断
适用场景 家庭用户、单机部署 有 Docker 经验的用户、服务器部署

五、Addon 升级顺序

升级 HA Core 之后,addon 要按依赖顺序逐个升:

  1. 基础设施 addon(先升)
  2. Docker Compose Manager、Network Utility、SSH
  3. 这些是"工具型",升完不影响业务

  4. 中间件 addon(次之)

  5. Mosquitto Broker(MQTT)
  6. Mosquitto Explorer
  7. NGINX Proxy Manager
  8. 这些是通信层,升级时 MQTT 会短暂断连

  9. 协议集成 addon(最后)

  10. ZHA / Zigbee2MQTT
  11. ESPHome
  12. Tasmota
  13. 这些依赖 MQTT,MQTT 先稳了再动它们

  14. 应用层 addon(最后)

  15. AppDaemon
  16. Node-RED
  17. Home Assistant Companion 后端
  18. HACS

踩坑:如果我反过来先升 AppDaemon,Python 版本升级会让 AppDaemon 找不到老版本的第三方库,得重装。

六、事故 1:OTA 卡在 99%

现象

2024 年 8 月某日凌晨,我按流程升级 HAOS 12.1 → 12.2。UI 显示:

Updating Home Assistant OS...
Downloading firmware... 99%

卡了 20 分钟。J4125 主板的指示灯还在闪,说明机器没死,HA 进程已经没了。

定位

用另一台设备 SSH 进来:

ssh [email protected]
$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
nvme0n1      0 255.9G  0 disk
├─nvme0n1p1 0   128M  0 part
├─nvme0n1p2 0    22G  0 part
├─nvme0n1p3 0    22G  0 part
└─nvme0n1p4 0  211.4G  0 part /data

nvme0n1p2 是旧分区,nvme0n1p3 是新分区,写入过程中磁盘 IO 完全卡死。dmesg 里有:

nvme nvme0: I/O 1024 QID 0 timeout
nvme nvme0: I/O 1024 QID 0 timeout, aborting
nvme nvme0: I/O 1024 QID 0 completed, result: 0x401

典型的 NVMe 控制器挂死。原因:J4125 主板用的是板载 NVMe 走 PCIe 通道,某些固件版本写入分区时 DMA 会跟系统其它进程打架。

恢复

  1. 直接断电(拔电 5 秒)
  2. 短接 Recovery 引脚(J4125 主板有 RECOVERY 针脚,短接后接电源)
  3. 电脑 USB 识别到 RECOVERY 分区
  4. 挂载 Recovery 分区,删掉损坏的 A/B 分区标志
  5. 用 Home Assistant OS image + Rufus 重刷 NVMe
  6. 启动 → 恢复备份

全程 40 分钟。因为备份在 NAS 上,恢复自动化和集成一次搞定。

教训:J4125 用户如果遇到卡 99%,先查 NVMe 型号(三星 970/980 有已知 bug),换三星 970 Pro 或西数 SN750 稳定。

七、事故 2:addon 不兼容崩溃

现象

2025 年 2 月升级到 HA 2025.2.0 后,Zigbee2MQTT addon 起不来。日志:

[19:24:13] INFO: [main] Starting Zigbee2MQTT version 1.34.0
[19:24:15] ERROR: [main] Failed to start Zigbee2MQTT
[19:24:15] ERROR: [main] TypeError: Cannot read properties of undefined (reading 'permit_join')
[19:24:15] ERROR: [main]     at Coordinator.start (/app/index.js:142:34)

定位

在 HA UI 打开 Zigbee2MQTT addon,右下角 Configuration 面板显示红字:

⚠ This add-on is not compatible with HA Core version 2025.2.0

翻 Changelog:

v5.1.0 (2025.1.2)  ← 我装的
  - Fixed coordinator discovery
v5.2.0 (2025.2.1)  ← 应该升到这里
  - Fixed compatibility with HA Core 2025.2

恢复

单独升级 Zigbee2MQTT addon 到 v5.2.0,重启,OK。

通用排查步骤:

# 看 supervisor 日志
journalctl -u supervisor -n 100

# 看具体 addon 日志
docker logs addon_config_zigbee2mqtt --tail 200

# 看 HA Core 日志
journalctl -u homeassistant -n 100 | grep -i error

90% 的 addon 报错都是addon 版本落后于 HA Core,跟 HA 本身无关。剩下 10% 是 addon 作者 bug,只能等新版。

八、事故 3:分区空间不足

现象

2024 年 11 月升级 HAOS 12.3 → 12.4,UI 直接报红:

Unable to update Home Assistant OS
There is not enough space on the device

定位

df -h
/dev/disk/by-label/ROOT   22G  20.5G  940M  96% /

96% 使用率,直接卡死升级入口。

排查

升级前的分区分布:

du -sh /data/* | sort -h
4.2G  /data/media              # 音乐/视频缓存
3.8G  /data/docker             # addon 镜像层
1.6G  /data/log                # 日志
1.2G  /data/supervisor         # HA 数据
800M  /data/rfstack            # Zigbee 缓存
500M  /data/media              # 其他

清理策略

按风险从低到高:

# 1. 清理 addon 镜像层(先停所有 addon)
ha supervisor addons list > /tmp/addons.txt
for a in $(cat /tmp/addons.txt | awk '{print $1}'); do
  ha supervisor addons stop $a
done
docker system prune -af --volumes

# 2. 清理旧日志
find /data/log -name "*.log" -mtime +30 -delete

# 3. 清理 rfstack(会重扫 Zigbee 设备)
rm -rf /data/rfstack/*

# 4. 清理 media 缓存(如果没本地媒体需求)
rm -rf /data/media/cache/*

清理后:

df -h
/dev/disk/by-label/ROOT   22G  14.2G  5.8G  71% /

从 96% 降到 71%,可以升级。

长期方案

  • 定期清理:cron 每周日 3 点执行 docker system prune
  • 备份策略:保留 7 天历史备份,超过 7 天的移到 NAS
  • 大文件别放 /data/media——那分区跟系统共享,一满全灭

九、回滚决策树

升级翻车了怎么办?按顺序问自己 4 个问题:

问题 1: HA 还能进 Web UI 吗?
├─ 能 → 问题 2
└─ 不能 → 进 Recovery 模式刷盘

问题 2: HA Core 版本是否可降级?
├─ Container 部署 → 直接改 docker tag 重来
└─ HAOS 部署 → 问题 3

问题 3: 是 addon 崩溃还是 HA Core 崩溃?
├─ addon 崩溃 → 单独重装 addon,不用回滚 HA
└─ HA Core 崩溃 → 问题 4

问题 4: 分区完整吗?
├─ df -h 正常 → 用旧版本固件重新刷
└─ 分区损坏 → Recovery 模式 + Factory reset

HAOS 回滚流程

  1. 从 home-assistant.io/download 下载旧版本镜像
  2. Rufus 写镜像到 SD 卡或 NVMe 启动盘
  3. 短接 Recovery 引脚启动
  4. 挂载旧系统,/data 分区保留(自动化和配置还在)
  5. 从 Recovery UI 里选 "Install latest version" 走新固件,或手动挂载旧分区

关键点:/data 分区不动,重装系统不会丢配置。

Container 回滚流程

# 拉取旧版本
docker pull homeassistant/home-assistant:2025.1.2

# 停止当前容器
docker stop homeassistant

# 删除当前容器(不删数据卷)
docker rm homeassistant

# 用旧镜像重新创建
docker run -d --name homeassistant \
  -e TZ=Asia/Shanghai \
  -v /mnt/user/backup/ha-config:/config \
  --restart unless-stopped \
  homeassistant/home-assistant:2025.1.2

10 秒钟完成,数据全在。这就是 Container 部署的杀手锏。

十、升级后冒烟测试

升级完别急着关掉浏览器,5 项必测:

1. 登录测试

用管理员账号登录,看能否正常进入 Dashboard。登不上说明 Supervisor 或 HA Core 都没起来,直接进 recovery。

2. API 测试

curl https://ha.local:8123/api/ -H "Authorization: Bearer $TOKEN"
# 应该返回 {"message": "API running."}

返回 401 是 token 问题,返回 502 是 Supervisor 挂了。

3. 自动化测试

挑 3 条关键自动化:

  • 一条基于时日的(比如"早上 7 点开灯")——触发时间检查
  • 一条基于状态变化的(比如"门窗打开触发")——事件总线检查
  • 一条基于 MQTT 的(比如"设备离线告警")——MQTT 检查

用 Developer Tools → Automations 手动触发,看执行日志。

4. MQTT 测试

# 订阅所有消息
mosquitto_sub -h mqtt.local -p 1883 -t '#' -v

# 发布测试消息
mosquitto_pub -h mqtt.local -p 1883 -t 'test/ping' -m 'hello'

发布后订阅端能收到 test/ping hello,MQTT 链路正常。

5. 传感器测试

在 Developer Tools → States 里随便挑 3 个传感器:

  • 温湿度传感器(本地协议)
  • 智能插座(MQTT 上报)
  • Zigbee 设备(ZHA/Z2M 上报)

每个都能显示数值、更新时间在 5 分钟内,OK。

5 项全过才敢关掉浏览器。任何一项挂了就按上面的排查流程走。

十一、FAQ

Q1: HAOS 升级卡 99% 不动了怎么办?

99% 是 OTA 下载完后正在写分区。这时候千万别急着重启——重启可能让新分区写到一半,进 Recovery 也救不回。

正确姿势: 1. 等 5 分钟,看进度条有没有动 2. 不动就断电(拔电 5 秒),然后重新插电 3. 短接 Recovery 引脚,进 Recovery UI 4. 选 "Factory reset and install latest version" 5. Recovery 完事,登录 HA,从 NAS 备份恢复配置

不会变砖,只是回到出厂状态。因为备份完整,恢复 20 分钟能搞定。

Q2: 升级后 addon 报错怎么办?

先别慌,看报错原文:

  • incompatible with HA version → addon 版本落后,单独升 addon
  • TypeError: Cannot read properties of undefined → addon 代码 bug,等新版
  • ModuleNotFoundError: No module named 'xxx' → Python 库升级,pip install 补一下
  • Failed to bind to port 1883 → 端口冲突,改端口或停冲突服务

90% 的报错是 addon 版本落后,先单 addon 升级重试。如果 addon 本身有 bug(比如 Changelog 明写 "not tested with 2025.2"),回退 HA 版本。

Q3: HAOS 能回滚到上一个版本吗?

不能直接回滚。HAOS 每次升级都会格式化一个分区,另一个分区保留旧版,但系统只认当前分区。想回退,只能重新刷回旧版本固件:

  1. 下载旧版本镜像(比如 12.3)
  2. Rufus + dd 刷到 SD 卡或 NVMe
  3. Recovery 模式启动
  4. Factory reset + Install

所以升级前必须做全量备份。这也是为什么 Container 部署更适合爱折腾的用户——回退 10 秒钟。

Q4: HA Container 怎么升级?

# 1. 拉新镜像
docker pull homeassistant/home-assistant:latest

# 2. 停止当前容器
docker stop homeassistant

# 3. 删除当前容器(不删数据卷)
docker rm homeassistant

# 4. 用新镜像重新创建
docker run -d \
  --name homeassistant \
  --net host \
  -e TZ=Asia/Shanghai \
  -e NODE_TLS_REJECT_UNAUTHORIZED=0 \
  -v /mnt/user/backup/ha-config:/config \
  -v /etc/localtime:/etc/localtime:ro \
  --privileged \
  --restart unless-stopped \
  homeassistant/home-assistant:latest

数据卷挂载 /mnt/user/backup/ha-config 不会丢。整个过程 HA 只断 30 秒左右。

Container 有个额外好处:可以同时跑两个版本。比如:

docker run -d --name ha-test \
  -v /mnt/user/backup/ha-config:/config:ro \
  -p 8124:8123 \
  homeassistant/home-assistant:latest

新版本跑在 8124 端口,先在测试账号下验证,稳定了再切主容器。

Q5: 升级要多久?

取决于网络速度与硬件:

硬件 网络 时长
J4125 + NVMe 有线千兆 3-5 分钟
J4125 + SATA SSD 有线千兆 4-6 分钟
树莓派 4 + SD 卡 WiFi 8-15 分钟
树莓派 4 + NVMe HAT WiFi 5-8 分钟
树莓派 5 + NVMe WiFi 4-7 分钟

升级期间 HA 完全不可用——所有自动化、传感器、门锁、摄像头会一起断。建议:

  • 凌晨 2-5 点执行(家里没人、自动化不会触发)
  • 提前通知智能家居设备用户(如果团队多人)
  • 保留 SSH 通道,UI 挂了还能进来排查

我在 J4125 上跑 HAOS 两年多的经验总结:升级不是玄学,是有 checklist 的运维操作。照着 6 步走 + 5 项冒烟测试,翻车概率能从 30% 降到 5% 以下。剩下的 5% 就是硬件故障,备份救你。