Home Assistant 折腾之路:从 Docker 到 UTM 虚拟机,再到接入 Claude Code
阅读 187 · 评论 0
Home Assistant 折腾之路:从 Docker 到 UTM 虚拟机,再到接入 Claude Code
这篇文档记录我从零开始折腾 Home Assistant 的完整路线:最初用 Docker 部署,接入米家官方集成,后来为了装 MCP server 被迫迁移到 Mac mini 上的 UTM 虚拟机,最终把整个智能家居接入 Claude Code,用自然语言管理全屋设备。
整体路线图:
textDocker 部署 HA Container
│
▼
接入米家官方集成(ha_xiaomi_home)
│
▼
官方集成拿不到音箱对话 ──► 音箱单独走 hass-xiaomi-miot(双集成并行)
│
▼
选型 MCP:官方集成 vs ha-mcp ──► 选了非官方 ha-mcp
│
▼
发现 Docker 版装不了(需要 Add-on / HACS)
│
▼
迁移:Mac mini + UTM 虚拟机跑 HAOS
│
▼
MCP 接入 Claude Code ✅
一、起点:Docker 安装 Home Assistant
最开始图省事,选了最轻量的部署方式——Docker(即官方所说的 Home Assistant Container):
bashdocker run -d \
--name homeassistant \
--restart=unless-stopped \
--privileged \
-e TZ=Asia/Shanghai \
-v /path/to/config:/config \
--network=host \
ghcr.io/home-assistant/home-assistant:stable
跑起来非常快,浏览器打开 http://<主机IP>:8123 就能进入 onboarding。这个阶段的体验是:日常使用完全没问题——设备接入、自动化、仪表盘都正常。
但 Docker 版有一个后面才会踩到的坑:它只是 Home Assistant Core 的容器化版本,没有 Supervisor,因此没有 Add-on Store(加载项商店)。当时不觉得是问题,后面选 MCP 方案时它成了迁移的直接原因。
二、接入米家:小米官方集成 ha_xiaomi_home
家里设备以米家为主,以前社区方案(Xiaomi Miot 之类)要折腾 token,现在小米出了官方集成 ha_xiaomi_home,直接走小米账号 OAuth 登录,体验好了一个量级。
安装方式(当时还在 Docker 环境,用的手动安装):
bashcd config
git clone https://github.com/XiaoMi/ha_xiaomi_home.git
cd ha_xiaomi_home
./install.sh /path/to/config
然后重启 Home Assistant,在 设置 → 设备与服务 → 添加集成 中搜索 Xiaomi Home,按提示用小米账号登录授权即可。
几个值得记的点:
- 登录即用:OAuth 授权后自动同步账号下的所有米家设备,不需要逐个抓 token。
- 支持中枢网关/局域网控制:默认走小米云,但可以开启中枢网关控制和局域网控制,降低延迟。
- 设备名称同步:米家 App 里的房间和设备名直接带过来,省去大量重命名工作。
到这一步,全屋米家设备都进了 Home Assistant,自动化随便写,已经比米家 App 自由很多。
三、补一刀:官方集成拿不到小爱音箱的对话,上 hass-xiaomi-miot
用了一阵子发现官方集成有一个绕不过去的短板:拿不到小爱音箱的对话记录。
我的目标场景是:对小爱说一句话 → Home Assistant 截获这句话 → 交给大模型生成回答 → 再让小爱音箱把回答播出来。也就是把小爱从"人工智障"升级成真正的 LLM 语音入口。这条链路的第一环——"截获用户说了什么"——官方集成做不到,它只同步设备实体,不暴露音箱的对话内容。
解决方案是社区老牌集成 hass-xiaomi-miot(al-one 维护,基于 miot-spec 协议)。通过 HACS 安装后,用小米账号(云端模式)接入音箱,小爱音箱会多出一个 conversation 传感器(sensor.xxx_conversation),实时记录最近一次对话内容。配合它提供的服务,整条链路就通了:
- 截获对话:监听 conversation 传感器的状态变化,拿到用户对小爱说的原话;
- 生成回答:把原话丢给大模型(HA 的 conversation agent 或自定义脚本调 API);
- 播放回答:调用
xiaomi_miot.intelligent_speaker服务,把回答文本交给小爱播报(execute: false朗读文本;execute: true还能让小爱执行文本指令,配合silent静默执行)。
实战:「你想想」唤醒 OpenAI 问答
这是我书房音箱上实际跑着的自动化。先在 HA 里装好 OpenAI Conversation 集成(得到一个 conversation agent 实体),然后整条链路全部用原生自动化拼出来,一行外部脚本都不用写:
yamlalias: 书房音箱·你想想·OpenAI问答
description: >-
书房音箱对话以『你想想』开头时:先播『我想想』打断小爱,
再把『你想想』之后的问题发给 OpenAI,用音箱播报答案。
triggers:
- trigger: state
entity_id: sensor.xiaomi_l17a_5803_conversation
conditions:
- condition: template
value_template: >-
{{ trigger.to_state.state not in ['unavailable', 'unknown', '']
and trigger.to_state.state.startswith('你想想') }}
variables:
question: >-
{{ (trigger.to_state.state[3:])
| regex_replace('^[ ,,。.、::!!??…~]+', '') | trim }}
actions:
- action: xiaomi_miot.intelligent_speaker
data:
entity_id: media_player.xiaomi_l17a_5803_play_control
text: 我想想
execute: false
- choose:
- conditions:
- condition: template
value_template: "{{ question | length > 0 }}"
sequence:
- action: conversation.process
data:
agent_id: conversation.openai_conversation
text: "{{ question }}"
response_variable: ai_result
- action: xiaomi_miot.intelligent_speaker
data:
entity_id: media_player.xiaomi_l17a_5803_play_control
text: "{{ ai_result.response.speech.plain.speech }}"
execute: false
default:
- action: xiaomi_miot.intelligent_speaker
data:
entity_id: media_player.xiaomi_l17a_5803_play_control
text: 你想让我想什么呢?
execute: false
mode: restart
使用效果:对小爱说"你想想,黑洞的事件视界是什么",音箱先回一句"我想想",一两秒后播出 OpenAI 生成的回答。
几个关键设计点,都是踩过坑之后才定型的:
- 用触发词「你想想」做前缀过滤。conversation 传感器会记录所有对话,如果不过滤,每次喊小爱开个灯都会触发大模型。以固定前缀开头才接管,其余对话照常走小爱原生逻辑,两边互不打扰。
- 先抢答一句「我想想」,一石二鸟:一是打断小爱——它对听不懂的问题会自己抢着回"我还在学习中"之类,必须用
intelligent_speaker把它顶掉;二是掩盖延迟——大模型生成需要几秒,先给一句即时反馈,体验上就不是"没听见"而是"在思考"。 - 用
conversation.process调用 HA 原生 conversation agent(agent_id指向 OpenAI Conversation 集成),response_variable直接拿回结构化结果,从ai_result.response.speech.plain.speech取纯文本播报。不用自己写脚本管 API key、拼 HTTP 请求,换模型也只是换一个 agent 实体。 - 问题文本要清洗:
variables里把状态值切掉前 3 个字("你想想"),再用regex_replace去掉残留的逗号、空格等前导标点——"你想想,xxx"和"你想想xxx"都能正确解析。 mode: restart:上一个回答还在播的时候问新问题,直接打断重来,而不是排队(single会丢弃新问题,queued会把旧答案播完才理你)。- 空问题兜底:只喊了"你想想"没有下文时,回一句"你想让我想什么呢?",而不是把空字符串发给大模型。
这套方案的延迟主要在大模型生成那一步,日常问答整体 2~4 秒可以接受。要注意 conversation 传感器依赖云端轮询,偶尔会有一两秒的捕获延迟,属于这套"曲线救国"方案的固有成本。
但要注意:hass-xiaomi-miot 支持的设备动作比官方集成少。官方集成对米家设备的 action/property 覆盖更全、更新更快,社区集成在一些新设备上会缺动作或属性。所以最佳实践不是二选一,而是两套集成并行、各管一摊:
| 设备 | 走哪个集成 | 原因 |
|---|---|---|
| 灯、开关、传感器、家电等全屋设备 | 官方 ha_xiaomi_home | 动作覆盖全、官方维护、OAuth 省心 |
| 小爱音箱 | hass-xiaomi-miot | 有 conversation 传感器 + intelligent_speaker 服务 |
两套集成各自用小米账号登录互不冲突,只需在 hass-xiaomi-miot 里只勾选音箱设备(或在官方集成里排除音箱),避免同一设备出现两套重复实体。
四、MCP 选型:官方集成 vs ha-mcp
接下来想把 Home Assistant 接到 AI 助手上(目标是 Claude Code),这就需要一个 MCP server。调研下来有两个候选:
- 官方 MCP Server 集成:https://www.home-assistant.io/integrations/mcp_server/
- 非官方 ha-mcp:https://github.com/homeassistant-ai/ha-mcp
两者定位差别很大,ha-mcp 的 README 里有一张对比表,直接说明了我为什么选它:
| 能力 | 官方集成 | ha-mcp |
|---|---|---|
| 控制设备(开关灯、家电) | ✅ | ✅ |
| 创建/编辑自动化、脚本 | ❌ | ✅ |
| 创建/编辑仪表盘 | ❌ | ✅ |
| 调试自动化(trace、历史记录) | ❌ | ✅ |
| 管理助手、区域、标签 | ❌ | ✅ |
| 备份、加载项、设备注册表管理 | ❌ | ✅ |
| 搜索实体/历史数据 | ❌ | ✅ |
一句话总结两者的差异:
官方集成是"语音控制"思路——把暴露的实体交给 LLM 去开关; ha-mcp 是"运维管理"思路——让 AI 能配置、调试、维护整个 Home Assistant。
官方集成基于 HA 的 Assist API,只暴露工具/提示/资源三类基础 MCP 能力,明确不支持搜索和历史查询;而 ha-mcp 基于 FastMCP 构建,提供约 83 个工具,覆盖模糊搜索、批量控制、自动化创建与调试、仪表盘编辑、备份管理、日志统计等,所有请求都在本地局域网内完成。
我的需求恰恰是"让 Claude 帮我写自动化、查问题",而不只是"喊一声开灯",所以毫不犹豫选了 ha-mcp。
五、踩坑:Docker 版装不了 ha-mcp
选好了方案,回头一看部署环境,问题来了。
ha-mcp 的推荐安装方式是 Home Assistant Add-on(加载项),完整功能(文件系统访问、YAML 编辑)还需要通过 HACS 安装配套的 ha_mcp_tools 自定义组件。而我的 Docker 版 Home Assistant:
- 没有 Supervisor,就没有 Add-on Store——加载项这条路直接堵死;
- HACS 这类生态工具在 Container 环境下的安装和维护也远不如 HAOS 顺滑。
换句话说,Docker 版适合"纯净极客自维护",但一旦想用 Add-on 生态(MCP、Node-RED、各种官方加载项),就必须上完整的 Home Assistant OS(HAOS)。
于是决定迁移。
六、迁移:Mac mini + UTM 虚拟机跑 HAOS
家里正好有台常开的 Mac mini(Apple Silicon),官方文档有现成的 macOS 安装指引:https://www.home-assistant.io/installation/macos/
要点如下:
- 下载镜像:Apple Silicon 选 Apple Silicon 专用的
.vdi镜像(Intel 芯片选 VirtualBox.vdi镜像)。 - 安装 UTM:macOS 上体验最好的虚拟机软件,基于 QEMU,对 Apple Silicon 支持完善。
- 创建虚拟机:
- 选择 Virtualize(虚拟化) 而不是 Emulate,性能接近原生;
- 资源按官方建议至少 2 vCPU + 2GB RAM(我直接给了 4GB,HAOS 加一堆 Add-on 之后内存不嫌多);
- 导入下载好的
.vdi磁盘镜像作为启动盘。
- 网络必须用桥接(Bridged)模式:这是最关键的一步。桥接后虚拟机在路由器上拿到独立 IP,和家里其他设备处于同一网段——米家设备的局域网控制、mDNS 发现(
homeassistant.local)、手机 App 直连都依赖这一点。默认的共享网络(NAT)模式会让 HA 找不到局域网设备。 - 启动并恢复数据:开机后访问
http://homeassistant.local:8123,onboarding 时选择 从备份恢复,把 Docker 时代的全量备份直接灌进去,所有集成、自动化、历史数据无缝迁移。
💡 建议在路由器上给虚拟机的 MAC 地址绑定静态 IP,并设置 UTM 随登录自启,Mac mini 设置永不睡眠(或允许网络唤醒),这样 HA 就是一台准 7x24 的"家庭服务器"。
迁移完成后,设置 → 加载项 里终于出现了 Add-on Store,HACS 也按官方脚本顺利装上。之前堵死的路全通了。
七、终点:MCP 接入 Claude Code
最后一步,把 ha-mcp 接入 Claude Code:
- 在 HA 中安装 ha-mcp Add-on:把 ha-mcp 的仓库地址添加到 Add-on Store 的仓库列表,安装并启动;
- (可选)通过 HACS 安装
ha_mcp_tools自定义组件:解锁文件系统访问和 YAML 直接编辑能力; - 生成长期访问令牌:HA 用户头像 → 安全 → 长期访问令牌;
- 在 Claude Code 中注册 MCP server:
bashclaude mcp add ha-mcp -- <ha-mcp 启动命令,按其 README 配置 HA 地址和令牌>
配置完成后重启 Claude Code,用 /mcp 命令确认连接状态。
接入后的实际体验,举几个真实用法:
- "客厅的灯现在什么状态?把亮度调到 30%" —— 直接查询并控制;
- "帮我写一个自动化:工作日早上 7 点,如果卧室有人,缓慢调亮灯光并播报天气" —— Claude 直接创建好自动化,不用自己点 UI;
- "昨晚 3 点扫地机器人为什么自己启动了?" —— 它会去翻自动化 trace 和历史记录,定位触发源;
- "给我做一个能耗概览仪表盘" —— 仪表盘也能直接生成。
这就是当初选 ha-mcp 而不是官方集成的全部意义:AI 不只是一个语音遥控器,而是一个会运维你智能家居的管家。
总结与建议
| 阶段 | 方案 | 适合谁 |
|---|---|---|
| Docker (Container) | 轻量、纯手动维护 | 只用核心功能、不需要 Add-on 的极客 |
| HAOS on UTM (Mac mini) | 完整生态:Supervisor + Add-on + HACS | 想用 MCP、Node-RED 等加载项生态的人 |
回头看几条经验:
- 如果将来可能用到 Add-on 生态,一开始就直接上 HAOS,省一次迁移。Docker 版省下的资源远不值后面折腾的时间。
- 米家设备主力走官方集成 ha_xiaomi_home,OAuth 登录 + 局域网控制、动作覆盖最全;但官方集成拿不到音箱对话,小爱音箱单独走 hass-xiaomi-miot(conversation 传感器 + intelligent_speaker 服务),两套集成并行各管一摊。
- MCP 选型看需求:只要"开灯关灯",官方集成够用且配置简单;想让 AI 写自动化、查日志、调试问题,选 ha-mcp。
- UTM 桥接网络是关键,NAT 模式会导致局域网设备发现失败,排查起来非常隐蔽。
- 迁移前先做全量备份,HAOS 的恢复功能可以无缝继承 Docker 时代的所有数据。
参考链接
- 小米官方集成:https://github.com/XiaoMi/ha_xiaomi_home/blob/main/doc/README_zh.md
- hass-xiaomi-miot(音箱对话方案):https://github.com/al-one/hass-xiaomi-miot
- HA 官方 MCP Server 集成:https://www.home-assistant.io/integrations/mcp_server/
- 非官方 ha-mcp:https://github.com/homeassistant-ai/ha-mcp
- HA macOS 安装指南:https://www.home-assistant.io/installation/macos/
- UTM 虚拟机:https://mac.getutm.app/
评论
登录后可以发表评论,游客仍然可以完整阅读正文。
- 还没有评论,第一条留言会很显眼。