为什么要自己搭中枢
厂商云的好处是开箱即用,坏处是把控制权、可用性和数据流向都交了出去:服务器一次维护就是全屋失联,一次账号策略调整就让自动化失效,厂商停止运营则设备直接变成砖。自建中枢要解决的就是这三件事——控制权、可用性和数据归属。
衡量一个智能家居中枢是否合格,最简单的标准是:把外网断掉,它还能不能完成你日常百分之八十的操作。
Home Assistant 是开源方案里生态最完整的一个:支持数千种设备与云服务集成、内置自动化引擎、支持本地控制、并提供标准化的 REST API 与其他程序互通。它不追求开箱即用的华丽,而是把可编排性和可控性放在第一位,这正是自建中枢的价值所在。
安装形态与目录结构
Home Assistant 常见的几种安装形态,适用场景差异明显,选错会在后续维护上付出很多时间。
- 操作系统镜像:整机安装,包含受管操作系统与所有附加组件,升级最省心,适合长期运行的主力机。
- 容器部署:跑在既有服务器或 NAS 的容器里,资源利用率高,适合已经有家庭服务器、并且愿意自行管理升级的人。
- 核心程序直装:在通用 Linux 上直接运行 Python 程序,可控性最强,但要自己处理依赖与开机自启,不适合追求省事的人。
无论哪种形态,配置目录的结构都是一致的,理解它比记住菜单更重要。
- configuration.yaml主配置入口,声明集成、自定义传感器、通知渠道等基础设置。
- automations.yaml自动化规则的默认存放位置,图形界面创建的自动化也落在这里,可以手工编辑。
- secrets.yaml保存密码与令牌,主配置里用
!secret引用,避免密钥散落在多处。 - .storage/存放界面与集成运行期产生的数据,手工编辑容易损坏,建议只在排障时查看。
接入设备:集成、实体与命名
Home Assistant 里所有可被控制或读取的东西都是实体,实体由集成创建。接入设备时,尽量优先使用本地协议集成而不是云集成:本地集成不依赖外网、响应更快,也不会因为厂商账号策略变化而失效。只有在设备确实只提供云接口时,才退而求其次。
命名是这一阶段最容易被忽视、后果最持久的事。实体标识一旦被自动化引用,后期改名就要同步修改所有引用,容易出现“改了名字但自动化还在操作旧实体”的隐性故障。因此建议在接入阶段就定好命名规范:
- 实体标识用“类型_位置_用途”的顺序,例如客厅的主灯命名为客厅主灯,玄关的门磁命名为玄关门磁。
- 位置与设备名保持一致,避免同一个房间出现三种叫法。
- 对暂时不用的实体设置隐藏或归类,而不是直接改名占位,减少以后重复劳动。
自动化:触发器、条件与动作
Home Assistant 的自动化由三部分组成:触发器决定“什么时候检查”,条件决定“这次要不要执行”,动作描述“执行什么”。三者分离的设计让规则可以写得很清晰,也更容易排查——一条自动化没生效,只需要沿着这三个环节依次确认。
# automations.yaml:玄关开门自动亮灯(仅环境暗时执行)
- id: hallway_light_on_door_open
alias: 玄关-开门亮灯-夜间
trigger:
- platform: state
entity_id: binary_sensor.xuanguan_door
to: "on"
condition:
- condition: numeric_state
entity_id: sensor.xuanguan_illuminance
below: 60 # 环境照度低于 60 lx 才需要开灯
action:
- service: light.turn_on
target:
entity_id: light.xuanguan_main
data:
brightness_pct: 70
- delay: "00:02:00" # 保持两分钟后自动关闭
- service: light.turn_off
target:
entity_id: light.xuanguan_main
mode: restart # 重复触发时重启计时,避免灯被提前关掉
这条规则里有三个细节值得单独说明。第一,条件是照度而不是时间,因为冬天傍晚六点已经很暗,而夏天七点还很亮,用光照判断比用时钟判断更贴近人的感受。第二,mode: restart 解决了“开门又开门”的场景——如果连续触发,上一轮的关闭计时会被取消,灯不会在你还站在门口时突然熄灭。第三,延迟关闭写在动作里而不是另开一条自动化,避免出现“开了灯但没关”的孤儿状态。
写自动化的通用原则可以总结成三条:让触发器只做触发、把所有判断逻辑放进条件、让动作序列可以被中断与重启。违背这三条,规则数量一多就会互相打架。
用 REST API 打通外部程序
Home Assistant 提供了完整的 REST API,任何能发起 HTTP 请求的程序都可以读写实体状态、调用服务。这让它成为家庭里各类脚本的天然枢纽:定时任务、自建看板、告警推送、甚至机器学习脚本都能挂上来。
import os
import requests
HA_URL = "http://192.168.1.30:8123"
TOKEN = os.environ["HA_TOKEN"] # 长期访问令牌,务必放进环境变量
HEADERS = {"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"}
def call_service(domain, service, entity_id, **data):
"""调用实体服务,例如 light.turn_off"""
resp = requests.post(
f"{HA_URL}/api/services/{domain}/{service}",
headers=HEADERS,
json={"entity_id": entity_id, **data},
timeout=5,
)
resp.raise_for_status()
return resp.json()
def get_state(entity_id):
"""读取实体当前状态与属性"""
resp = requests.get(f"{HA_URL}/api/states/{entity_id}",
headers=HEADERS, timeout=5)
resp.raise_for_status()
return resp.json()
# 场景一:离家时关闭全屋灯,并把客厅空调设为 26 度
call_service("light", "turn_off", "all")
call_service("climate", "set_temperature",
"climate.keting_air", temperature=26)
# 场景二:读取客厅温度用于外部告警脚本
state = get_state("sensor.keting_temperature")
print("客厅温度:", state["state"],
state["attributes"].get("unit_of_measurement"))
使用 API 时有两条安全规则必须遵守:令牌只能存放在环境变量或密钥文件里,绝不写进代码提交到仓库;对外暴露接口时应当经由反向代理并加上访问控制,不要直接把服务端口映射到公网——一旦被扫描到,整屋的设备都会被陌生人控制。
备份、隐私与数据保留
自建中枢意味着数据责任也由自己承担,这件事的收益和风险是同一枚硬币的两面。
- 定期备份:完整的配置目录备份应设为自动任务,至少保留最近七份,并把其中一份放在另一台设备上——同一块硬盘上的备份在硬盘故障时毫无意义。
- 备份要验证:每隔一段时间用备份做一次实际恢复演练,只备份不恢复的备份等于没有备份。
- 控制外网暴露:远程访问优先使用带访问控制的方案,而不是把服务端口直接暴露到公网。
- 数据分级:摄像头、门锁、人体存在传感器这类涉及隐私的设备,尽量选择本地存储或端侧处理,不要把原始数据上传到第三方云。
- 记录保留策略:历史数据无限制增长会让数据库越跑越慢,为每类实体单独设置保留天数。
稳定性维护清单
一套自建中枢能不能长期稳定运行,取决于日常有没有做这几件小事。
- 升级前先备份、再升级、后观察:自动化失效绝大多数出现在升级之后的头两天。
- 关注日志中的集成错误:某个集成反复重连,往往是设备固件或网络问题的早期信号。
- 限制自动化数量与层级:规则超过百条后,建议按房间或功能拆分成包,避免维护期互相干扰。
- 为关键自动化加失效告警:当它连续 N 天没有执行时主动通知,比等到发现问题再排查要好。
- 给硬件留出余量:CPU 长期高于 60%、内存持续增长,都会在某个时刻变成随机宕机。
做到这些,自建中枢就能把“折腾”变成“基础设施”:你不再需要每天关心它,但随时可以按自己的想法改造它。这种可控性,是任何封闭生态都无法提供的。