Home Assistant 数据迁移实战:三层迁移 + SQLite→MariaDB + 5 个真实事故
去年秋天,我把跑了三年的 HA 从一张快满的 32GB 树莓派 SD 卡搬到 J4125 小主机上,顺便把 18GB 的 SQLite 历史库切成 MariaDB。原本以为一下午搞定,结果前后折腾了三天,中间翻车五次,最狠的一次让我误以为全家自动化要重写。
这篇文章就是那三天换来的教训。我把它拆成三层迁移(配置 / 历史数据 / 自定义组件),每一层独立讲、独立排坑,最后把 SQLite→MariaDB 的完整命令流程和 5 个真实事故复盘出来。希望你读完之后,能比我当年少踩一半坑。
先说一个核心判断:HA 迁移失败,九成不是因为拷错了文件,而是因为"以为拷够了"。configuration.yaml 拷过去、HA 能启动、界面能打开,就以为完事了。结果自动化全挂、历史全断、能量统计归零。这就是本文要救你的事。
1. 什么时候需要迁移
不是所有迁移都是"换机器"。我总结下来,触发迁移的场景就四类,前两类是主动的,后两类是被迫的。
1.1 四类触发场景
换硬件。最典型的是树莓派换机、SD 卡换 NVMe、老 NUC 换新主机。这类迁移最像"搬家",重点是配置和历史都要带走,别重头再来。
换部署形态。HA OS 整机镜像换到 HA Container(Docker)、虚拟机、或者反过来。形态不同,迁移路径完全不同,后面第 7 章专门讲。
历史库过大拖垮系统。这是最容易忽视的。SQLite 是 HA 的默认数据库,单文件、单连接写入,历史库一旦上 10GB,你会遇到:历史面板打开要转十几秒、recorder 组件 CPU 占用飙到 100%、HA 启动变慢、甚至自动化触发延迟。这时候迁移的"目标"根本不是新硬件,而是把数据库从 SQLite 切成 MariaDB。
数据盘迁移。HA OS 默认把数据放系统盘,你给它加了一块 NVMe 做数据盘,用 ha os datadisk move 把数据挪过去。这个操作本身不复杂,但坑很多,第 8 章那个"双数据盘冲突"事故就是这里来的。
1.2 怎么判断"该迁了"
我给自己的判断标准很简单,满足任意两条就启动迁移:
| 信号 | 表现 |
|---|---|
| 硬件告警 | 树莓派 SD 卡读写错误、dmesg 出现 mmc0 报错 |
| 数据库膨胀 | home-assistant_v2.db 超过 5GB,且持续增长 |
| 性能劣化 | 历史面板加载 > 10s,recorder 常驻 CPU > 30% |
| 容量告急 | 根分区 / 数据盘使用率 > 80% |
| 形态变更 | 想从 HA OS 换 Docker,或反向 |
这里给个提醒:别把"换形态"和"换数据库"混在一次做。我见过有人一次迁移同时换机器 + 换 Container + 切 MariaDB,三层都动,出问题完全没法定位。一次只动一层,这是迁移的铁律。
1.3 迁移决策树
把上面四类场景整理成一棵决策树,你照着走就不会漏层:
迁移原因?
├─ 历史库太大 / 性能劣化 → 只迁数据库:SQLite → MariaDB(第 5 章)
│ 无需动配置,只需改 recorder.db_url
├─ 换硬件(同形态)→ 三层全迁:配置 + 历史 + custom_components(第 3/4/6 章)
│ 树莓派换机 → 可整卡镜像,最省事(第 7.2 章)
├─ 换形态(OS→Container/VM)→ 三层全迁 + 改路径引用(第 7.1 章)
│ 重点:.storage 认证、http 配置、挂载目录
└─ 数据盘迁移 → 只动 datadisk,不动配置历史(第 8 章)
重点:先 list 确认单盘,再 move
注意最上面那条:如果只是数据库切 MariaDB,配置和 custom_components 都不用动,只改 recorder.db_url。很多人一听到"迁移"就把三层全做一遍,结果把好好的配置也搬出问题了。迁移的范围要和原因匹配,别做多余的动作。
2. 迁移前:备份 + 系统信息评估
迁移前的准备比迁移本身重要。很多人跳过这步直接拷文件,出了事才发现源机已经关机、原始数据没了。
2.1 全量备份
无论 HA OS 还是 Container,先做一次完整备份。备份有两个目的:一是出事能回滚,二是"迁移前基线"——迁移后对比用的。
HA OS 用 Supervisor 备份,可以直接在 UI 里做,也可以命令行:
备份完确认文件生成、大小合理:
Container 用 tar 打包 /config,注意要停掉 HA 再打包,否则数据库文件在写、打包出来是坏的:
docker stop homeassistant
tar czf /mnt/nas/pre-migration-20261029.tar.gz -C /opt/ha config
docker start homeassistant
这里特别强调:备份文件要验证能解压,别备份完就信了。我备份过几次损坏的 tar,都是因为没停容器就打包。
2.2 系统信息评估(迁移前必做)
这一步是给迁移"拍张照",后面所有对比都靠它。我把要记的信息列成清单,挨个记录:
数据库大小与文件路径:
# 找到 HA 数据库文件
find /config -name "*.db" -o -name "*.db-*" 2>/dev/null
# 常见结果:/config/home-assistant_v2.db
# 看大小和增长
du -sh /config/home-assistant_v2.db
ls -lh /config/home-assistant_v2.db*
purge_keep_days 配置(决定历史保留多长,直接影响迁移数据量):
这个值很关键:如果原来是 purge_keep_days: 365,说明你要迁一年的历史;如果只有 7,那历史库再大也别迁太多,只迁最近的就好,省一半功夫。
磁盘用量:
HA 版本与核心信息:
记录这些信息到一张纸上(或一个 .md 文件)。迁移后对照这张表做冒烟测试,缺什么一眼就能看出来。
2.3 迁移前检查清单
我把这步整理成 checklist,贴在下面,迁移前逐条打勾:
[ ] 全量备份完成且验证可解压(含历史库文件)
[ ] 记录数据库路径与大小(home-assistant_v2.db)
[ ] 记录 purge_keep_days 配置值
[ ] 记录 HA / Supervisor / 系统版本
[ ] 记录所有启用的集成列表(Settings → Devices & Services)
[ ] 记录所有自定义组件清单(/config/custom_components)
[ ] 记录所有自动化与脚本数量
[ ] 导出所有实体注册表(.storage/core.entity_registry)
[ ] 确认目标机磁盘剩余空间 > 源数据库 × 2
[ ] 确认目标机能联网(下载集成、addon 需要)
别嫌麻烦。第 9 章五个事故,至少三个就是"没做这一步"导致的。
2.4 备份的三种策略怎么选
结合我们站上那篇备份策略深度解析,迁移前的备份我分三个级别,按你的风险承受力选:
| 级别 | 做法 | 适用 |
|---|---|---|
| L1 最小 | 只备份 /config 目录 tar |
迁移后源机还能开机 |
| L2 推荐 | L1 + 单独备份历史库文件 | 历史库大、源机可能被格式化 |
| L3 保险 | L2 + Supervisor 全量备份 + 云盘异地 | 换硬件、源机要销毁 |
我的习惯是:换硬件走 L3,换形态走 L2,只切数据库走 L1。因为换硬件意味着旧机器可能直接退役,数据只剩备份这一份,必须上异地。只切数据库的话源机还在、数据库文件还在,L1 就够。
2.5 用一份"迁移记录单"管理全过程
这一步被多数人忽略,但它是三天迁移教训里最值钱的一条。我建议在迁移前建一个 migration-notes.md,像这样:
# HA 迁移记录单 - 2026-10-29
源机: 树莓派4 / HAOS 2024.1 / SQLite
目标: J4125 / HAOS 2024.1 / MariaDB 11
---
数据库大小: 18.2 GB (home-assistant_v2.db)
purge_keep_days: 30
磁盘: 源 / 92% 目标 / 41%
---
集成清单:
[x] MQTT (核心)
[x] Xiaomi Miot (custom_components)
[x] Node-RED (addon)
---
实体数: 286 | 自动化数: 47 | 脚本数: 12
---
迁移时间线:
[ ] 03.1 配置层 tar → [ ] 03.2 目标解包 → [ ] 04.1 历史库备份
[ ] 05.4 sqlite3-to-mysql → [ ] 05.5 行数校验 → [ ] 06.2 custom_components
[ ] 10.x 冒烟测试全绿
这份记录单的作用:一是迁移时照着打勾不漏层,二是出问题时能回溯"哪一步、哪一层、用了什么命令"。我在事故④(statistics 没迁)之后才学会用这招,之前全靠脑记,漏了就漏了。
2.6 评估数据库性能劣化的量化方法
判断"历史库大是否真的拖垮系统",不能光看大小,要看量化指标。我常用的三个观测点:
① recorder 组件 CPU 占用:
② 历史面板加载耗时:打开 Developer Tools → 历史面板,选最近 7 天,记录加载时间。> 10 秒就是劣化信号。
③ 数据库文件增长速率:
综合这三个指标,再结合 purge_keep_days(保留天数越长,库越大),就能判断是"该清历史"还是"该迁 MariaDB"。如果库大但 purge 只有 7 天,说明历史保留不长,可能只是某段时间写入爆发,先 recorder.purge 清理再观察,不一定非要迁库。如果 purge 是 30 天以上且库仍在涨,那就是真该迁了。
2.7 一个容易被忽略的点:purge_keep_days 迁移后要同步
很多人迁移完只顾着迁数据,忘了目标机的 purge_keep_days 可能和源机不一致。如果目标机是全新安装,默认 purge_keep_days 是 10 天,而源机设了 365 天,那么迁移过来的历史会在几天内被 HA 自动 purge 掉,你辛辛苦苦迁的大历史库白迁了。
迁移后务必确认目标机 recorder.purge_keep_days ≥ 源机的值。这是我踩过的隐性坑,比事故①②③④⑤更隐蔽——它不报错,只是历史"悄悄变少"。
3. 第一层:配置迁移
配置层是 HA 的"骨架",它决定 HA 能不能启动、集成对不对。这一层出问题,界面能开但所有设备是红的。
3.1 要迁什么
配置层不是只有 configuration.yaml,它其实是四个部分:
- configuration.yaml + 所有 include 的 yaml(automations、scripts、scenes、zones 等)
- secrets.yaml(密码、Token,最容易忘)
- .storage 目录(实体注册表、设备注册表、认证、能量统计、云连接状态)
- 自定义集成配置(部分集成把配置存在
.storage,部分存在 yaml,都要带上)
其中 .storage 是大家最常忽略的。很多人只拷 configuration.yaml,结果 HA 起来了,但所有实体 ID 都变了、登录要重新来、能量统计归零。因为实体 ID 和用户认证都存在 .storage 里。
3.2 具体命令
HA OS:直接在主机上操作,/config 是数据目录。
# 先停 HA,避免 .storage 写入中
ha core stop
# 打包配置层(不含历史库,历史库单独迁)
tar czf /backup/config-layer.tar.gz \
-C /config \
configuration.yaml \
secrets.yaml \
automations.yaml \
scripts.yaml \
scenes.yaml \
zones.yaml \
.storage
ha core start
Container:路径是容器内的 /config,挂载到宿主机。
docker stop homeassistant
tar czf /mnt/nas/config-layer.tar.gz -C /opt/ha/config \
configuration.yaml secrets.yaml automations.yaml .storage
docker start homeassistant
注意:.storage 里的文件很多是 JSON,打包前必须停 HA,否则这些 JSON 正在写,拷出来可能是半个文件,HA 启动时直接报 JSON 解析错误。
3.3 恢复配置到目标机
目标机先装好相同版本的 HA(第 7 章讲怎么装),然后:
解包后先别急着启动,做三件事:
① 检查 secrets.yaml 的路径。如果换机后 secrets.yaml 引用路径变了(比如之前用绝对路径),要改。
② 检查自定义集成是否齐。configuration.yaml 里 sensor:、light: 等引用自定义平台,如果 custom_components 没迁,HA 启动会报 Integration not found。这也是第 9 章事故①的根源。
③ 检查 include 文件是否存在。如果 configuration.yaml 里写 automation: !include automations.yaml,但 automations.yaml 没拷过来,HA 直接启动失败。
配置层的验证标准:HA 能启动、日志里没有 Invalid config、Settings 里集成列表和源机一致。
3.4 .storage 里到底有什么,哪些必须迁
很多人对 .storage 是"一个目录直接拷",其实它里面的文件各司其职,迁移时要分清主次。我列出最关键的几个:
| 文件 | 内容 | 不迁的后果 |
|---|---|---|
core.entity_registry |
实体 ID、平台、唯一 ID 映射 | 实体 ID 变化、自动化模板断链(事故⑤) |
core.device_registry |
设备注册表(设备名、型号、连接) | 设备信息丢失、集成识别异常 |
auth |
用户认证、Token | 登录失效、必须重新登录 |
energy |
能量统计配置、能源面板布局 | 能源面板配置丢失 |
cloud |
Nabu Casa 云连接状态 | 云连接需要重新授权 |
core.config_entries |
集成配置条目(流配置) | 集成需要重新配置 |
其中 core.entity_registry 和 core.config_entries 是重中之重。core.config_entries 决定集成是否"已配置",如果它没迁,很多集成(尤其流配置的)会回到"需要设置"状态,你得手动重配,非常痛苦。
一个易踩的坑:.storage 里有些文件是机器相关的,比如 core.uuid(机器唯一 ID)。迁移时如果带着源机的 UUID 去目标机,某些集成会认为"这是另一台机器"而拒绝工作(比如某些云同步集成)。遇到这种情况,删除目标机的 core.uuid 让 HA 重新生成即可:
3.5 配置迁移的三种拷贝方式
拷配置层,我用过三种方式,各有适用场景:
方式一:tar 打包(推荐,保权限和结构):
方式二:rsync 增量(大配置、多次迁移时):
方式三:scp 单文件(小配置、快速):
三种方式的核心差异在权限保留和增量能力。tar 和 rsync 保权限(HA 对某些文件有特殊权限要求),scp 不保。如果你的配置里有脚本(shell_command)需要执行权限,务必用 tar 或 rsync。
4. 第二层:历史数据迁移
历史数据是 HA 里最"重"的一层,也是迁移时最容易被跳过的一层。很多人觉得"历史不重要,迁了配置就够",实际上没有历史,你的能量统计、长期统计、历史面板全是空的。
4.1 历史数据存在哪
历史数据由 recorder 组件管理,默认存 SQLite 文件:
如果你配置了外部数据库(MariaDB 等),则存在外部库,路径在 configuration.yaml 的 recorder: db_url: 里。
判断当前用哪种:
4.2 SQLite 文件直接拷贝
这是最简单的情况,源和目标都是 SQLite。先停 HA,然后拷贝:
ha core stop
cp /config/home-assistant_v2.db /backup/
# 或者直接拷到目标机
scp /config/home-assistant_v2.db user@target:/config/
ha core start
关键点:必须停 HA 再拷。SQLite 的 WAL 模式(-wal 和 -shm 文件)如果不停止就拷,拷出来的是不一致的库,HA 起来会报 database disk image is malformed。
如果不想停 HA,可以用 SQLite 的在线备份:
.backup 命令是 SQLite 官方的在线一致性备份,不用停服务,但要确保你机器上有 sqlite3 CLI。
4.3 外部库(MariaDB)导出
如果源已经是 MariaDB,用 mysqldump 导出。一定要带 --complete-insert,否则导入时某些行会因为缺列而报错:
mysqldump -u ha -p'password' \
--complete-insert \
--single-transaction \
homeassistant > /backup/ha-historical.sql
注意 --single-transaction:保证导出时数据一致性,不锁表。对千万行的大库,这个参数很关键。
4.4 历史迁移的核心坑:表要迁全
SQLite 的 home-assistant_v2.db 里有十几张表,最重要的几张是:
| 表名 | 作用 | 不迁的后果 |
|---|---|---|
states |
实体状态历史(核心) | 历史面板全空 |
events |
事件日志 | 自动化/日志时间线断档 |
statistics |
长期统计数据(能耗聚合) | 能量统计为 0 |
statistics_short_term |
短期统计数据 | 能耗图无短期数据 |
state_attributes |
状态属性 | 属性丢失 |
很多人只迁 states 和 events,觉得够了,结果能量统计一片空白。statistics 和 statistics_short_term 必须一起迁。这是第 9 章事故④的直接原因。
4.5 别迁的:metadata 和 context 的边界
这里有个容易搞错的地方:metadata 表(实体元数据)和 context 表(事件上下文)必须和 states 一起迁,因为 states 表通过外键引用 metadata_id。只迁 states 不迁 metadata,状态行会变成孤儿,历史面板能显示 ID 但查不到元数据。
反过来,event_data、state_attributes 这种大字段表,如果历史库过大,可以只迁最近 N 天,用 WHERE 过滤。但 statistics 表是聚合表,行数少、价值高,建议全迁。
4.6 历史库迁移的三种目标形态
历史数据迁到哪,取决于目标机的配置。我把它分成三种:
形态 A:源目标都是 SQLite(换机,不换库)——直接 cp 文件或 .backup,最省事。
形态 B:源 SQLite → 目标 MariaDB(性能升级)——走第 5 章完整流程。
形态 C:源 MariaDB → 目标 MariaDB(换机但库不变)——用 mysqldump 导出导入:
# 源机导出
mysqldump -u ha -p --complete-insert --single-transaction \
homeassistant > /backup/ha-historical.sql
# 目标机导入
mysql -u ha -p homeassistant < /backup/ha-historical.sql
形态 C 的坑:mysqldump 导出的是逻辑 SQL,包含 CREATE TABLE 和 INSERT。如果目标机 MariaDB 里已经建过同样的表(比如 HA 启动时自动建的),导入会因 CREATE TABLE 冲突报错。解决:导入前先 DROP 目标机的同名表,或加 --add-drop-table。
形态 B 的变体——先导 schema 再导数据:SQLite→MariaDB 如果整库跑,sqlite3-to-mysql 会边建表边插数据。但 18GB 大库建议分两步:先只建表(--table 逐个或靠工具自动),再导数据。这样如果中途失败,重跑时不会因为表已存在而冲突。分步还有个好处:能单独补迁漏掉的表(事故④就是这么修的),不用整库重跑。
4.7 历史库迁移时的空间规划
历史库是迁移里最占空间的部分。18GB 的库,迁移过程中需要:
- 源库文件 18GB(保留)
- tar/导出文件 18GB(备份)
- 目标库 18GB+(MariaDB 数据目录)
- 临时文件若干(WAL、binlog)
总共需要约 60GB 的可用空间,是原始库的 3 倍以上。很多迁移卡死不是因为 --chunk,是因为目标磁盘满了,INSERT 报 disk full 但 sqlite3-to-mysql 没及时退出,挂着不动。迁移前务必确认目标机磁盘剩余 > 源库 × 3。
另外,MariaDB 的 binlog 在批量导入时会飞速增长。如果磁盘紧张,导入前临时关掉 binlog:
导入完成后再开回来。
5. SQLite → MariaDB 完整步骤
这一章是很多人点进来的原因:历史库太大,SQLite 拖垮系统,要迁到 MariaDB。我当年踩了事故②(18GB 卡死)之后总结出的完整流程,照着走基本稳。
5.1 为什么迁 MariaDB
先讲清楚动机。SQLite 不是不能用,它是单文件、零配置、对单机 HA 很友好。但它的短板在并发:
- 表级锁:SQLite 整个数据库写操作是串行的,一个慢查询会阻塞所有写入。
- WAL 膨胀:历史库大、写入频繁时,
-wal文件会持续膨胀,需要定期 checkpoint。 - 历史查询阻塞写入:你打开历史面板,HA 要扫几千万行
states,这时候新状态写入被卡住,自动化可能延迟触发。
MariaDB 的 InnoDB 引擎行级锁,读写并发,recorder 的 purge 增量删除也稳定。对 5GB 以上、且你经常看历史/能量统计的场景,值得迁。
5.2 部署 MariaDB
HA OS 用官方 addon:
然后通过 addon 的 Web UI 或命令行创建数据库和用户:
CREATE DATABASE homeassistant CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ha'@'localhost' IDENTIFIED BY 'strong_password';
GRANT ALL PRIVILEGES ON homeassistant.* TO 'ha'@'localhost';
FLUSH PRIVILEGES;
Container 用 Docker 起一个 MariaDB:
docker run -d --name mariadb \
-e MARIADB_ROOT_PASSWORD=rootpass \
-e MARIADB_DATABASE=homeassistant \
-e MARIADB_USER=ha \
-e MARIADB_PASSWORD=strong_password \
-v /opt/ha/mariadb:/var/lib/mysql \
mariadb:11
5.3 准备转换工具
迁数据库不能直接 cp,SQLite 和 MariaDB 的 SQL 方言不同(自增主键、日期格式、BLOB 处理都有差异)。推荐用 sqlite3-to-mysql,Python 写的,社区用得多。
安装:
5.4 完整迁移命令
这是我当年跑通的流程,关键在 --chunk 和 --with-index 两个参数。
第一步,导出 SQLite 为中间格式(其实 sqlite3-to-mysql 直接读 SQLite 文件,不需要中间导出):
# 先停 HA,避免迁移过程中写入
ha core stop
# 从 SQLite 迁到 MariaDB
sqlite3-to-mysql \
--sqlite-file /config/home-assistant_v2.db \
--mysql-database homeassistant \
--mysql-user ha \
--mysql-password strong_password \
--mysql-host localhost \
--chunk 50000 \
--with-index \
--without-foreign-key
参数解释:
| 参数 | 作用 | 我的取值建议 |
|---|---|---|
--chunk |
每批插入行数 | 50000(大库),10000-20000(小内存) |
--with-index |
迁移后重建索引 | 一定要加,否则查询超慢 |
--without-foreign-key |
跳过外键约束 | 建议加,避免约束冲突导致中断 |
--skip-... |
跳过指定表 | 可按需跳过大字段表 |
--chunk 50000 是血泪教训。我第一次跑用默认值(约 5000),18GB 的库跑到一半卡死,states 表几千万行,每批 5000 行 commit 一次,MySQL 的 binlog + InnoDB 刷盘跟不上,最后卡在 40% 不动,CPU 100% 但进度不涨。改成 50000 后,commit 次数少了 10 倍,跑完 18GB 只用了不到 2 小时。第 9 章事故②就是这个。
5.5 row count 校验(迁移后必做)
迁移完千万别直接切配置,先做行数校验。这一步能发现"迁了一半"或"漏表"的问题。
# SQLite 侧行数
sqlite3 /config/home-assistant_v2.db \
"SELECT 'states', count(*) FROM states UNION ALL SELECT 'events', count(*) FROM events UNION ALL SELECT 'statistics', count(*) FROM statistics;"
# MariaDB 侧行数
mysql -u ha -p'strong_password' homeassistant -e \
"SELECT 'states', count(*) FROM states UNION ALL SELECT 'events', count(*) FROM events UNION ALL SELECT 'statistics', count(*) FROM statistics;"
两侧数字一致才算成功。如果不一致,看差在哪张表,用 --table 参数单独重迁那张表:
sqlite3-to-mysql \
--sqlite-file /config/home-assistant_v2.db \
--mysql-database homeassistant \
--mysql-user ha \
--mysql-password strong_password \
--table states \
--chunk 50000
5.6 切换 recorder 到 MariaDB
校验通过后,改 configuration.yaml 的 recorder:
recorder:
db_url: mysql://ha:strong_password@localhost/homeassistant
purge_keep_days: 30
commit_interval: 30
重启 HA:
看日志确认连接成功:
5.7 大库迁移的内存与时间经验
给几个我实测的数字,供你参考:
| 库大小 | chunk | 内存 | 预计耗时 |
|---|---|---|---|
| < 2GB | 20000 | 2GB | 10-20 分钟 |
| 5GB | 50000 | 4GB | 40-60 分钟 |
| 18GB | 50000 | 8GB | 1.5-2 小时 |
| > 30GB | 100000 | 16GB | 3-4 小时 |
迁移期间 HA 必须停,且要保证迁移机器内存够。18GB 库 + chunk 50000,峰值内存大概在 6-8GB,机器内存不足会直接 OOM。
5.8 迁移常见报错速查
迁移过程中最容易遇到的报错,我列出来,你照着排查:
报错 1:sqlite3.OperationalError: database is locked
原因:迁移时 HA 还在运行,SQLite 文件被 HA 进程占用。解决:先 ha core stop 再迁移,迁移完再 ha core start。这条是新手最容易犯的——忘了停 HA 就开跑。
报错 2:pymysql.err.OperationalError: (1045, "Access denied")
原因:MySQL 用户名密码错,或用户没有 homeassistant 库的权限。解决:用 mysql -u root -p 重新授权:
报错 3:pymysql.err.OperationalError: (2003, "Can't connect to MySQL server")
原因:MySQL 没启动、或 --mysql-host 地址错。解决:systemctl status mariadb 或 ha addons start local_mariadb,确认 3306 端口在监听:ss -tlnp | grep 3306。
报错 4:迁移中途 KeyboardInterrupt 或进程被杀
原因:终端断连、内存 OOM、或你按了 Ctrl+C。解决:这类中断会留下半迁移的数据库——部分表已迁、部分没有。千万不要直接切换 recorder,一定要重新跑完整迁移(sqlite3-to-mysql 对已存在的表会跳过或重建,取决于工具行为),然后重做 5.5 的行数校验,确认全表一致再用。
报错 5:ERROR 1114 (HY000): The table is full
原因:磁盘满了。解决:腾空间,把目标库的 datadir 指向剩余空间大的分区,或临时关 binlog(SET GLOBAL sql_log_bin = 0)减少磁盘占用,重新导入。
5.8 迁移完成后:旧库处理与回滚
迁移成功后,SQLite 旧库还在源机 /config/home-assistant_v2.db。别急着删,它是你唯一的回滚保障。我建议:
- 保留旧库 7 天,确认 MariaDB 一切正常(历史、能量、自动化全绿)。
- 7 天后,把旧库改名备份(
mv home-assistant_v2.db home-assistant_v2.db.bak),而不是直接删,万一发现漏数据还能找回。 - 再过 30 天确认无误,再彻底删掉。
如果迁移后发现问题要回滚,操作也很简单——把 recorder.db_url 改回 SQLite:
重启后 HA 会重新读 /config/home-assistant_v2.db,回到迁移前状态。
5.9 一个真实的迁移输出参考
给你看一段我跑 18GB 库时 sqlite3-to-mysql 的真实输出,方便你判断进度是否正常:
[INFO] Connected to MySQL database: homeassistant
[INFO] Connected to SQLite database: /config/home-assistant_v2.db
[INFO] Creating table states
[INFO] Transferring data for table states
[INFO] Progress: 10000000 / 42000000 rows (23.8%)
[INFO] Progress: 20000000 / 42000000 rows (47.6%)
[INFO] Progress: 30000000 / 42000000 rows (71.4%)
[INFO] Table states done. Inserted 42000000 rows
[INFO] Creating table events
[INFO] Transferring data for table events
[INFO] Table events done. Inserted 5600000 rows
[INFO] Creating table statistics
...
[INFO] All tables transferred successfully.
注意进度条是按 --chunk 每批更新一次。如果进度停在某个百分比超过 15 分钟不动,大概率是 chunk 太小或磁盘满,按事故②的处理方法排查,别干等。
6. 第三层:custom_components 与 apps 迁移
这一层是最容易被遗忘、却又最容易导致"迁移后自动化全挂"的。第 9 章事故①就是它。
6.1 为什么这层独立
custom_components 是第三方集成代码,它们不在 configuration.yaml 里,也不在 .storage 里,而是一个独立目录。HA 的核心集成(如 mqtt、http)是内置的,但第三方集成(Xiaomi Miot、bemfa、HACS 装的集成)都在这层。
如果你只拷了 configuration.yaml 和 .storage,没拷 custom_components,HA 启动时找不到这些集成,configuration.yaml 里引用它们的 sensor:、light:、switch: 全部报 Integration not found,依赖这些实体的自动化全部 unavailable。
6.2 迁移命令
# 打包 custom_components
tar czf /backup/custom-components.tar.gz -C /config custom_components
# 解包到目标机
tar xzf /backup/custom-components.tar.gz -C /config
6.3 apps 层(Node-RED / AppDaemon)
如果你用了 Node-RED 或 AppDaemon,它们的流/应用也要单独迁。
Node-RED:流存在 addon 的目录,通常打包整个 Node-RED 配置目录:
ha addons stop core_nodered
tar czf /backup/nodered.tar.gz -C /addons/config/nodered .
ha addons start core_nodered
或者更简单:Node-RED 的 UI 里 Export → All flows,导出 JSON,目标机 Import。
AppDaemon:直接在 /config/appdaemon/apps 目录,拷贝即可:
6.4 版本匹配是这层最大的坑
custom_components 里的第三方集成强依赖 HA 版本。如果你的源机 HA 是 2024.1,目标机装的是 2026.10,这些集成大概率加载失败(API 变了)。
所以迁移这层时,目标机 HA 版本要和源机一致或接近,迁移完再逐步升级。这是"三层分开迁"的另一个原因——配置和 custom_components 是绑定版本的,历史数据不是。
6.5 迁移后验证
再手动进 Settings → Devices & Services,确认每个第三方集成状态是"已连接"而非"报错"。
6.6 HACS 的特殊处理
如果你用了 HACS,它是这层里最特殊的。HACS 本身是一个自定义集成,但它管理着一大堆"子集成"。
迁移 HACS 的关键:HACS 集成本身在 custom_components/hacs,但它的下载仓库元数据存在 .storage/hacs 和 custom_components/hacs/const.py 里。如果你只拷 custom_components/hacs 但没拷 .storage/hacs,HACS 会以为没有任何已下载的集成,虽然代码在,但界面列表是空的。
稳妥做法:HACS 目录 + .storage/hacs 一起迁:
更省心的做法是:迁移后进 HACS 点 Redownload 逐个重装。因为 HACS 下载的集成代码在 custom_components/ 下,如果你已经整体迁了 custom_components,HACS 界面重新扫描通常能识别。但如果 HACS 报"集成目录存在但未注册",删掉 .storage/hacs 让 HACS 重建,再重新下载。
6.7 依赖 Python 包的自定义组件
少数自定义组件(如某些 custom_components 用了 pymodbus、aiohttp 之外的三方库)需要在目标机安装额外 Python 依赖。HA OS 下这些依赖通常由组件自带 manifest.json 的 requirements 字段声明,HA 会自动装。但离线迁移(目标机无外网)时会失败。
排查方法:迁移后看日志有没有 ModuleNotFoundError:
如果目标机能联网,HA 会自动安装缺失的 requirements,通常不用手动干预。只有离线环境才需要手动 pip install 到 HA 的 Python 环境(Container 下可以直接进容器装)。
核心提醒:custom_components 里每个组件的版本必须和源机一致。用 ls -l /config/custom_components/*/manifest.json 对比源目标两机的修改时间,不一致就重拷。这是第 9 章事故①的进阶排查点——有时目录拷了,但版本是旧的,同样会报错。
7. 跨硬件 / 跨形态路径
不同部署形态之间迁移,路径差异很大。这一章讲最常见的四种。
7.1 HA OS → HA Container
这是"换形态"最典型的一种,很多人从 HA OS 迁到 Docker 是为了更方便地加旁路服务(比如自己跑 MQTT、数据库)。
关键差异:
- HA OS 是整机系统,配置在
/config,通过haCLI 操作。 - HA Container 只有一个容器,配置挂载在宿主机目录(如
/opt/ha/config),通过docker exec操作。
迁移步骤:
- 在 HA OS 上备份
/config整个目录(配置 + 历史 + custom_components 一起打包)。 - 目标机装 Docker + HA Container,挂载一个空目录。
- 把备份解包到挂载目录。
- 改
configuration.yaml里的路径引用(如果有绝对路径)。 docker start homeassistant。
注意:HA OS 的 .storage 里的某些状态(如 supervisor 相关)在 Container 里没有意义,但不会报错,只是多余。真正要注意的是 http: 的 trusted_proxies、base_url、以及 SSL 配置,Container 默认走 http://localhost:8123,和 HA OS 一样,但如果你之前 HA OS 配了 HTTPS,Container 这边要重新配反向代理。
7.2 树莓派换机(同形态)
树莓派 4 换树莓派 5、或换更大 SD 卡,是最简单的迁移,因为形态相同。
方案 A(推荐):整卡镜像备份恢复
在源机上,用 dd 把整张卡做成镜像,直接烧到新卡:
# 源机(插着旧卡)
sudo dd if=/dev/mmcblk0 of=/mnt/nas/rpi-full.img bs=4M status=progress
# 新机(插着新卡)
sudo dd if=/mnt/nas/rpi-full.img of=/dev/mmcblk0 bs=4M status=progress
方案 B:仅迁 /config
如果你不想整卡,只迁数据:
# 源机
ha core stop
tar czf /mnt/nas/ha-config.tar.gz -C /config .
ha core start
# 目标机(装好同版本 HAOS)
tar xzf /mnt/nas/ha-config.tar.gz -C /config
树莓派换机最容易忽略的是外接设备:Zigbee 协调器(如 Sonoff、ConBee)要插到新机,且如果是 USB 直连,configuration.yaml 里串口路径可能从 /dev/ttyUSB0 变成 /dev/ttyUSB1,要改。
7.3 数据盘移动:ha os datadisk move
这是 HA OS 特有的,把数据从系统盘挪到外加的数据盘。场景:你给 HA 加了块 NVMe 或大容量 SSD,想把 /config 和数据库挪过去。
# 查看已挂载的数据盘
ha os datadisk list
# 输出示例:
# /dev/sda1 - /mnt/data (active)
# /dev/sdb1 - (inactive, unused)
# 如果没挂载,先挂载
ha os datadisk add /dev/sdb1
# 迁移数据到新盘(会停 HA 并重启)
ha os datadisk move /dev/sdb1
注意:move 会把数据盘设为 active,原系统盘上的数据仍在,但之后 HA 读写都走新盘。迁移完确认 /config 在新盘上:
7.4 虚拟机迁移(HA OS 跑在 Proxmox / KVM)
如果你的 HA OS 是一台虚拟机,换宿主机的正确姿势是虚拟机级备份恢复,不是进 HA 内部迁数据。
Proxmox 上:
# 备份整机(含磁盘)
qm backup 100 /backup/ha-vm-20261029
# 新宿主机
qm restore 100 /backup/ha-vm-20261029.vma.zst
这样连数据盘、配置、历史一起带走,最省事。只有当你从"虚拟机里的 HA OS"迁到"裸机 Container"这种跨形态时才需要走前面 7.1 的流程。
7.5 各路径的坑对比表
四种跨形态/跨硬件路径的坑各不相同,我把关键差异整理成一张表,迁移前扫一眼:
| 路径 | 主要坑 | 关键动作 |
|---|---|---|
| HA OS → Container | .storage 含 supervisor 冗余、http/SSL 配置、绝对路径引用 |
改 base_url、trusted_proxies、检查挂载目录 |
| 树莓派换机(同形态) | Zigbee 协调器串口路径变化、外接 USB | 改 /dev/ttyUSB*、插回外设 |
| 数据盘 move | 双数据盘冲突、断电数据不一致 | 先 datadisk list、先全量备份 |
| VM 迁移 | 虚拟机磁盘类型(IDE→SATA)、网卡 MAC | 用 qm restore 整机恢复、确认磁盘总线 |
其中 VM 迁移有个容易忽略的点:HA OS 的 os-agent 和 Supervisor 依赖虚拟机的磁盘总线类型。如果旧 VM 用 IDE 总线、新 VM 用 SATA,某些固件版本可能启动失败。Proxmox 上新建 VM 时记得和源机保持一致的总线类型。
7.6 迁移时外设和网络要重新确认
迁移换硬件后,有两个"看不见的"依赖最容易出问题:
① 外接设备串口。Zigbee 协调器、USB 蓝牙、RS485 模块,换了机器后 /dev/ttyUSB0 可能变成 /dev/ttyUSB1。排查方法:
找到新路径后,改 configuration.yaml 里 zha: 或 mqtt: 的 port,或通过 UI 重新选串口。
② 网络与 IP。换机后 IP 可能变化,http.base_url、internal_url、external_url 都要确认。如果之前用固定 IP,新机要重新绑定或改配置。这一步漏了,会出现"能访问但 WebSocket 报错"或"外网访问失效"。
8. 双数据盘冲突事故(Multiple data disks detected)
这个事故值得单独一章,因为它最容易吓到人,但其实是 HA OS 的一个已知机制。
8.1 症状
我在树莓派换机(7.2 方案 B)后,加了块 SSD 做数据盘,执行 ha os datadisk move 时报错:
Multiple data disks detected:
- /dev/sda1 (4.0 GB) - /mnt/data (active)
- /dev/sdb1 (120 GB) - (inactive)
Only one data disk can be active at a time.
Please select which disk to use.
8.2 排查
这个报错的意思是:系统检测到两个数据盘。为什么会有两个?因为我换机时用了"整卡镜像恢复"(方案 A),旧卡的 /mnt/data 分区(4GB)还在系统盘上,我又外加了一块 120GB 的 SSD,于是 HA 同时看到两块数据盘,不知道该用哪块。
8.3 根因
HA OS 的 datadisk 机制规定:同一时间只能有一块 active 数据盘。当系统盘上残留了旧的 /mnt/data 分区、同时你又加了一块新盘时,就出现多盘冲突。常见于:
- 树莓派换机用了整卡恢复,旧卡的数据盘分区带到新卡
- 之前做过一次
datadisk move但没清掉旧盘 - 插了两块 U 盘 / SSD
8.4 修复
解决思路是"二选一",把不用的那块盘从数据盘列表移除。有两种做法:
做法一:指定用哪块(推荐,如果你确定要新盘):
# 先卸载不用的盘
ha os datadisk remove /dev/sda1
# 再激活新盘
ha os datadisk add /dev/sdb1
ha os datadisk move /dev/sdb1
做法二:清掉系统盘上的残留分区(如果旧数据不要了):
关键教训:做 datadisk move 之前,先 ha os datadisk list 确认只有一块盘,或者明确知道哪块是目标盘。如果列出来有多个,先 remove 掉不需要的,再 move,否则必然冲突。
另外,datadisk move 是移动数据,如果中途断电或失败,数据可能处于不一致状态。所以执行前务必先 ha backup new 做一次全量备份。
9. 五个真实事故复盘
这一章是全文的精华,全部是我真实踩过的坑。每个按"症状 → 排查 → 根因 → 修复"四段式讲,你能直接复用。
在逐个讲之前,先给你一条总规律,这比五个事故本身更值钱:
五个事故里,①③⑤是"忘了迁某一层",②④是"迁的方法不对"。 前者靠 checklist 解决,后者靠参数调优解决。所以迁移的成败 = 三层一个不少 × 每层方法正确。
记住这个公式,你就能理解为什么我强调"三层分开迁"——每一层有独立的失败模式,混在一起迁只会让失败互相掩盖。事故①和事故⑤往往同时发生(custom_components 版本不一致 + 实体 ID 变化),你如果不分层排查,会以为是同一件事,修了半天只修好一半。
事故①:迁移后自动化全挂(custom_components 没迁)
症状:迁移完成后 HA 能启动,界面能打开,但所有依赖第三方集成的自动化全部显示 unavailable,light.living_room、switch.gate 这些实体在 Developer Tools 里是红的。
排查:看日志。
根因:我只拷了 configuration.yaml 和 .storage,忘了拷 custom_components。configuration.yaml 里 sensor: 引用了 xiaomi_miot 平台,但目标机没有这个集成代码,platform 加载失败,实体注册了但 unavailable,所有依赖它的自动化跟着挂。
修复:把源机的 custom_components 整个目录拷过来,重启 HA。这里有个细节:拷贝后要清一次缓存,否则 HA 可能用旧的编译缓存继续报错。
tar xzf /backup/custom-components.tar.gz -C /config
rm -rf /config/.storage/.*.cache # 清缓存
ha core restart
教训:迁移清单里必须有一条"列出所有第三方集成并确认已迁"。custom_components 目录大小一眼就能看出有没有漏——源机如果这个目录有几十 MB,目标机却是空的,就是漏了。
延伸——为什么"自动化全挂"不是配置的锅:很多人第一反应是"configuration.yaml 写错了"。其实配置层只要 include 文件都在,HA 就能加载;真正让自动化 unavailable 的是实体来源的集成加载失败。自动化本身是 automations.yaml 里的规则,它没错,错的是它依赖的实体(light.xxx)因为集成缺失变成 unavailable。所以排查顺序应该是:先看日志有没有 not found,再看实体状态,最后才怀疑自动化配置。
事故②:18GB 历史库迁移卡死(--chunk 太小)
症状:跑 sqlite3-to-mysql 迁 18GB 库,进度到 40% 左右停止不动,CPU 100%,等了两小时没有进展,states 表行数在 MariaDB 侧不再增长。
排查:
看 MySQL 进程状态:
根因:--chunk 默认值太小(约 5000)。18GB 的 states 表有数千万行,每批 5000 行 commit 一次,MySQL 的 InnoDB 刷盘 + binlog 写入跟不上插入速度,最终锁等待、死锁、进程挂住。chunk 太小导致 commit 次数过多,是大库迁移的致命伤。
修复:杀掉卡住的进程,把 --chunk 调大到 50000,重新跑。同时把 MySQL 的 innodb_flush_log_at_trx_commit 临时设为 0(批量导入时降低刷盘频率,提高吞吐):
mysql -u root -p -e "SET GLOBAL innodb_flush_log_at_trx_commit = 0;"
sqlite3-to-mysql \
--sqlite-file /config/home-assistant_v2.db \
--mysql-database homeassistant \
--mysql-user ha \
--mysql-password strong_password \
--chunk 50000 \
--with-index \
--without-foreign-key
跑完记得恢复:
教训:大库迁移,chunk 宁大勿小。5000 是给几百万行用的,几千万行必须上 50000。但也不要无脑 100000,内存不足会 OOM。经验值:机器内存每 2GB 对应 chunk 10000-15000,8GB 内存配 50000。
延伸——为什么 18GB 会卡在 40%:这不是巧合。40% 恰好是 states 表快迁完、开始迁大字段表(state_attributes、event_data)的位置。这些表单行数据大(一条事件属性可能几 KB),chunk 5000 意味着每批要 insert 几 MB 数据,加上索引重建,InnoDB 缓冲池被撑爆,触发换页风暴。所以大库卡死的位置通常在大字段表,而不是 states。提前知道这点,你能在进度到 40% 时预判风险,主动调大 chunk。
事故③:双数据盘名冲突(Multiple data disks detected)
症状:见第 8 章,ha os datadisk move 报 Multiple data disks detected,迁移中止。
排查:
根因:换机时整卡镜像恢复把旧数据盘分区也带过来了,系统盘上有残留的 /mnt/data,加上新加的 SSD,出现两块数据盘。HA OS 规定同一时间只能 active 一块。
修复:先 ha os datadisk remove /dev/sda1 移除系统盘上残留的分区,再 add + move 新盘。注意 remove 会卸载该分区,数据仍在其上,不会丢,但 move 目标必须是那块你要用的盘。
教训:任何 datadisk 操作前先 list 确认盘的数量和状态,多盘先清理再操作。
事故④:时间线 / 统计错乱(statistics 表没迁全)
症状:迁移后历史面板能显示状态变化(states 有数据),但能量统计全是 0,长期统计(Long-term Statistics)没有数据,能耗图空白。
排查:
mysql -u ha -p homeassistant -e "SELECT count(*) FROM statistics;"
# 返回 0 → 没迁
mysql -u ha -p homeassistant -e "SELECT count(*) FROM states;"
# 返回几千万 → states 迁了
根因:我只迁了 states 和 events 表,漏了 statistics 和 statistics_short_term。能量统计不是实时从 states 算的,而是 recorder 定时聚合到 statistics 表。没有这张表,能量面板查不到聚合数据,显示 0。时间线断档同理——events 表缺数据,事件时间线是断的。
修复:单独补迁 statistics 表:
sqlite3-to-mysql \
--sqlite-file /config/home-assistant_v2.db \
--mysql-database homeassistant \
--mysql-user ha \
--mysql-password strong_password \
--table statistics \
--chunk 50000
教训:迁移历史库,states、events、statistics、statistics_short_term、metadata、context 这六张表一个都不能少。我后来把"六表齐全"写进了迁移校验脚本,逐表对比行数。
事故⑤:实体 ID 变化导致模板断链
症状:迁移后实体存在、状态正常,但部分自动化不触发,且这些自动化的 condition 或 trigger 里引用了 sensor.xxx、binary_sensor.yyy,在 Developer Tools 里查这些实体发现 ID 变了,或者变成了 unavailable。
排查:对比 .storage/core.entity_registry 源机和目标机。
# 源机
grep -o '"entity_id": *"[^"]*"' /config/.storage/core.entity_registry | sort > /backup/entities-old.txt
# 目标机
grep -o '"entity_id": *"[^"]*"' /config/.storage/core.entity_registry | sort > /backup/entities-new.txt
# 对比
diff /backup/entities-old.txt /backup/entities-new.txt
根因:实体 ID 由 recorder 和 core.entity_registry 共同管理。如果迁移时 .storage 没迁全(只迁了部分),或者源机有实体在迁移前刚被移除,目标机的实体注册表重建,导致实体 ID 变化。自动化里的模板引用的是旧 ID,断链后不触发。
修复:这个最麻烦。如果只是少数实体,直接在自动化里把旧 ID 改成新 ID。如果大批实体 ID 变了,最靠谱的是从源机完整迁移 .storage,让实体注册表一致:
# 目标机停 HA,用源机的 .storage 覆盖
ha core stop
rm -rf /config/.storage
tar xzf /backup/config-layer.tar.gz -C /config
ha core start
教训:.storage 必须完整迁移,尤其是 core.entity_registry 和 core.device_registry。迁移前先导出实体清单(源机),迁移后 diff 一遍,ID 不一致提前发现,别等自动化不触发才排查。
延伸——实体 ID 变化的真正来源:很多人以为是 HA "自己改了",其实是迁移时 .storage/core.entity_registry 里每个实体的 unique_id 与 platform 组合没匹配上。实体注册表靠 unique_id 定位实体,如果集成(custom_components)版本不一致,unique_id 的生成逻辑变了,HA 就会生成新实体、把旧实体标记为 unavailable,于是 ID 变化。所以实体 ID 变化往往和 custom_components 版本不一致是同一件事的两种表现——事故①和事故⑤经常同时出现。排查时先对比 custom_components 版本,再 diff 实体注册表,顺序别反。
10. 迁移后冒烟测试 checklist
迁移完成,别急着收工,跑一遍冒烟测试。这是"迁移成功"和"能跑但不对"的分水岭。我按层列成清单,全绿才算通过。
10.1 第一层:配置与实体
[ ] HA 正常启动,无 "Invalid config" 报错
[ ] Settings → Devices & Services:所有集成显示"已连接",无红色报错
[ ] 实体数量与源机一致(Developer Tools → States 对比)
[ ] 登录账号能登录(.storage 认证已迁)
[ ] 无 "Integration not found" 日志
10.2 第二层:历史数据
[ ] 历史面板能加载,过去 7 天有数据
[ ] 时间线完整,无断档
[ ] 长期统计有数据(Settings → Statistics)
[ ] 能量仪表盘正常,能耗有数值
[ ] 数据库行数校验通过(states/events/statistics 三表一致)
10.3 第三层:自动化
[ ] 自动化列表完整(数量与源机一致)
[ ] 手动触发每个关键自动化,实体状态按预期变化
[ ] 无 unavailable 实体被自动化引用
[ ] 模板引用能解析(Developer Tools → Templates 测试)
10.4 常用命令速查
| 命令 | 用途 |
|------|------|
| ha core logs | 查看 HA 日志 |
| ha core logs | grep -i "not found" | 找集成缺失 |
| sqlite3 /config/home-assistant_v2.db "SELECT count(*) FROM states" | SQLite 行数 |
| mysql -u ha -p homeassistant -e "SELECT count(*) FROM states" | MariaDB 行数 |
| ha os datadisk list | 看数据盘状态 |
| du -sh /config/home-assistant_v2.db | 看数据库大小 |
| diff /backup/entities-old.txt /backup/entities-new.txt | 对比实体 ID |
10.5 收尾
冒烟测试全绿后,源机先别急着销毁,保留 7 天。为什么?因为迁移后头几天可能发现遗漏(比如某个不常看的集成、某条不常触发的自动化),源机还在就能随时补迁。我一般保留两周,确认新机稳定才格式化旧盘。
迁移不是拷贝完成的那一刻结束,而是新机跑满 7 天、旧机仍可回滚的那一刻才结束。
10.6 一个可复用的冒烟测试脚本
冒烟测试手动跑太费劲,我写了个小脚本,一键输出关键指标,迁移后跑一遍对比源机记录单。你把它存成 smoke-test.sh 改改路径就能用:
#!/bin/bash
# HA 迁移后冒烟测试脚本
echo "=== 1. 集成加载错误 ==="
ha core logs | grep -iE "not found|Integration.*failed|Invalid config" | head -20 || echo "无错误"
echo "=== 2. 实体数量 ==="
curl -s -H "Authorization: Bearer $HA_TOKEN" \
http://localhost:8123/api/states | python3 -c "import sys,json; print(len(json.load(sys.stdin)),'个实体')"
echo "=== 3. 数据库行数 ==="
mysql -u ha -p'$DB_PASS' homeassistant -e \
"SELECT 'states' t, count(*) c FROM states UNION SELECT 'events', count(*) FROM events UNION SELECT 'statistics', count(*) FROM statistics;"
echo "=== 4. 自动化数量 ==="
ls /config/automations.yaml 2>/dev/null && grep -c "alias:" /config/automations.yaml || echo "0 条"
echo "=== 5. 磁盘使用 ==="
df -h /config | tail -1
跑完把输出和源机的迁移记录单对比,逐项一致即通过。重点看第 3 项数据库行数,这里是漏表(事故④)的照妖镜。
11. FAQ
Q1:只拷贝 configuration.yaml 够不够?
不够。配置、历史库、自定义组件三层都要迁。configuration.yaml 只是骨架,.storage 存认证与能量统计,home-assistant_v2.db 存历史,custom_components 是第三方集成代码。漏任何一层都会出现"能启动但功能残缺"。
Q2:SQLite 历史库多大该迁 MariaDB? 一般 5GB 以上、或历史查询明显卡顿就值得迁。SQLite 单连接写入强,但历史库大、并发查询多时表锁严重。MariaDB 支持并发、purge 增量更稳,长历史查询不阻塞写入。
Q3:--chunk 参数调多大合适? 经验值 20000-100000。内存充足的机器 50000 起步;内存紧张(2GB 以下)用 10000-20000。chunk 太小(5000)在千万行级会卡死;一次性全量导入又可能内存爆。先 50000,卡了就减半。
Q4:迁移后自动化全挂,最可能是什么? 90% 是 custom_components 没迁。第三方集成(Xiaomi Miot、bemfa 等)代码没拷过去,platform 加载失败,依赖它的自动化全部 unavailable。其次才是实体 ID 变化导致模板断链。
Q5:迁移后能源统计为 0、时间线断档怎么办? 大概率是 statistics 表没迁全。statistics 与 statistics_short_term 记录能耗聚合,只迁 events/states 不够。用 mysqldump --complete-insert 全表导入,别只迁 states 表。
相关文章
- HA 备份策略深度解析:三种场景备份差异与恢复演练 — 迁移前必做的备份与演练
- HAOS 升级与回滚实战:6 步安全升级 + 3 个失败事故复盘 — 迁移后版本管理
- HA OS + J4125 固件:从下载镜像到首次启动的五步路径 — 新机安装基础