自动化的四要素:触发、条件、动作、模式

从「远程开关」到「不用管的系统」

装好 Home Assistant 之后,大多数人最先学会的是打开网页或手机 App,点一下把客厅灯关掉。这本质上还是「人操作」,只不过把墙上的物理面板换成了屏幕。真正让 HA 值得折腾的,是自动化——让系统在合适的时机自己干活,你不用管,它也办得妥当。

一条最小化的自动化,用一句话概括就是:当某件事发生时(触发),如果当时的情况允许(条件),就去做一件事(动作)。这三样,再加上一个专门处理「撞车」的 mode(模式),就是 HA 自动化的四要素。本章后续所有花活——模板、场景、事件总线、Node-RED——说到底都是在这四个位置上做加法。先把这四个位置认清楚,后面学什么都快。

自动化执行流水线

触发:自动化的起点

trigger 决定「什么时候让这条自动化入场」。它不是某个具体的时间点,而是一个「信号发生了」的事件:门窗被打开、温度跨过某条线、时钟走到某一刻、太阳落山、有人从外面回到家,都可以成为触发。常见的触发器可以分成四大类:

触发类别 典型代表 适合做什么
状态类 state、numeric_state 门窗开合、温湿度跨阈值
时间类 time、sun、template 定时任务、日出日落联动
事件类 event、webhook、mqtt 第三方推送、自定义事件
位置类 zone 手机进出某个地理围栏

要建立的关键认知是:触发只管「发车」,不管「该不该去」。很多新手写出来的自动化会在凌晨三点把全屋灯打开,通常不是触发写错了,而是缺了条件。触发器的详细用法会在本系列「触发器全家桶」一篇展开,这里先记住它在流水线上的位置:一切从触发开始,但一切又不能止于触发。

另一条容易踩的坑是「触发太敏感」。温度传感器每跳一次数值都可能触发一次自动化,如果动作里还包含发通知,你的手机就会被刷屏。因此状态类触发通常配合 for 参数使用——「持续 5 分钟都高于 26 度」才算数,把抖动过滤掉,自动化才稳定。

条件:决定要不要执行

condition 是刹车。它在触发之后、动作之前被评估,所有条件全部通过,动作才会真正执行。HA 给的条件种类不少,常用的有这几种:

  • state:某个实体正处于某个状态,比如「电视是开着的」。
  • time:当前时间落在某个区间内,比如「晚上十点到早上六点」。
  • sun:太阳在地平线以上或以下,适合做日出日落相关的判断。
  • numeric_state:数值类的判断,比如「室温高于 26 度」。
  • template:写一段 Jinja2 模板,返回真或假,表达力最强,也最容易翻车。

条件之间可以组合:AND 表示全部满足,OR 表示满足其一,NOT 表示取反。写条件时一个常见错误是「把条件当成触发」:比如你想要「回到家且天黑了才开灯」,其中「回到家」是触发,「天黑了」是条件——因为「回家」是瞬间发生的事件,而「天黑」是一个持续的状态。分清「事件」和「状态」,是写好自动化的第一道分水岭,很多「为什么不触发」的疑问,想通这一点就豁然开朗。

条件也可以写进 YAML 里,直观感受一下:

condition:
  - condition: sun
    after: sunset
  - condition: time
    after: "22:00:00"
    before: "06:00:00"
  - condition: state
    entity_id: input_boolean.guest_mode
    state: "on"

这段同时判断了「太阳下山」「夜里十点到早上六点」「访客模式开着」三件事,三个条件之间是 AND 关系,全部成立才会往下走。注意条件本身不带触发力:就算天黑了、时间也到了,只要你没回家,这条自动化依然纹丝不动。

动作:让设备真正动起来

action 是执行体,也是最容易写出花样的一环。核心动作是调用服务(service call),比如开灯、切换插座、发通知。除了直接调用服务,action 里还能放这些结构:

  • delay:延迟若干秒,用来给窗帘、空调这类慢半拍的设备留出动作时间。
  • wait_template:等到某个条件成立再继续,比死等固定秒数优雅得多。
  • choose:条件分支,相当于 if/else,可以把多种情况塞进同一条自动化。
  • repeat:循环,配合 wait_template 可以做轮询直到成功。
  • service_template:根据模板动态决定调哪个服务,灵活但排查问题时会绕一些。

动作的顺序就是执行的顺序,从上到下一步步走。想跨设备并行,可以用后面章节讲的 script 和场景,也可以在自动化里调用一个脚本,把复杂度封装出去——这条思路在「场景与脚本的分工」一篇会详细展开。

动作里还有两个细节值得记住。其一,调用服务时可以带数据:开灯不只是「开」,还能指定亮度、色温甚至过渡时长,同样的 light.turn_on 配上不同数据就是完全不同的体验。其二,动作默认是阻塞式顺序执行的,遇到 delay 会真的停在那里等,所以一条自动化里塞太多等待会让整条流水线变得很钝——该拆成脚本的就拆出去。

模式:重叠触发时的行为

mode 是四要素里最容易被忽略、却最能决定体验的一个。它管的是:上一次执行还没结束,新的触发又来了,怎么办。HA 提供四种取值:

模式 行为 典型场景
single 忽略新触发(默认) 通知类、不怕漏的轻任务
restart 中断当前执行,从头来 延迟熄灯、联动灯光
queued 排队依次执行 串行操作设备,避免冲突
parallel 多个实例并行跑 互不干扰的通知广播

四种模式对比

举个例子:你写了一条「门一开就延时 3 分钟关灯」,用的是默认的 single。结果你前脚刚开过一次门,家人后脚又开门——第二次触发被忽略,灯可能就不按预期关了。同样的逻辑换成 restart,每次开门都重新计时,体验立刻顺滑。延时类自动化几乎都该用 restart,串行控制设备用 queued,这两条经验能解决大半的「自动化时灵时不灵」。

再补一个 queued 的场景:你家有两条自动化都要操作同一台电动窗帘,如果并行执行,电机收到的指令会打架。给它们都配上 queued,指令排队依次执行,硬件就不会犯迷糊。模式不是面子工程,它决定了一条自动化在「高频触发」下还靠不靠谱。

一个完整的例子

把四要素串起来,看一条真实可用的自动化:「晚上回家时,如果天已经黑了,就把玄关和客厅灯打开」。逻辑拆解:触发是「手机进入家庭围栏」,条件是「太阳已下山」,动作是「打开两盏灯」,模式用默认的 single 即可。

用 YAML 写出来大致是这个样子:

alias: 晚上回家开灯
trigger:
  - platform: zone
    entity_id: device_tracker.my_phone
    zone: zone.home
    event: enter
condition:
  - condition: sun
    after: sunset
action:
  - service: light.turn_on
    target:
      entity_id:
        - light.entry
        - light.living
mode: single

这段配置相当于一个填空题:trigger 填「谁、在哪、进还是出」,condition 填「什么时候算天黑」,action 填「开哪几盏灯」。把其中任意一块换成模板或脚本,就能演化出复杂得多的玩法,但骨架永远是这个骨架。

运行环境也得跟上。如果你是把 HA 装在软路由上的玩家,可以参考 《软路由指南》 里关于旁路由与端口规划的章节,确保手机定位和外部访问这条链路通畅;若是装在 NAS 上,《NAS 搭建指南》 里虚拟机与 Docker 的部署方式同样适用,自动化跑起来之后并不占多少资源,配好「助手」分类下的 helper 实体就够用了。

延伸阅读

  • 《群晖 DSM 指南》 中关于 Docker 套件与容器资源限制的部分,适合把 HA 长期挂在 NAS 上的读者。
  • 触发器的完整清单与各平台参数,见本系列「触发器全家桶:时间、状态、事件、区域」一篇。