触发器全家桶:时间、状态、事件、区域

触发器是自动化的发动机

上一篇讲了四要素的骨架,本篇把「触发」这一格彻底填满。HA 的触发器平台有十几种,但底层逻辑只有三类:时间到了、状态变了、事件发生了。区域类触发其实就是「设备状态变化」的一种特殊形态,webhook 和 mqtt 则是「事件」的外部来源。理解这个分类,看到一个新平台也能马上猜到它的脾气。

先给一张总览表,后面逐类展开:

分类 触发平台 一句话说明
时间 time、sun、template(时间型) 到点、日出日落、算时间
状态 state、numeric_state 开关变化、数值跨线
事件 event、webhook、mqtt、template(事件型) 总线事件、外部推送
位置 zone 手机进出围栏
设备 device 绑定具体设备的按钮等

注意最后一行的 device 触发器:它面向「某个具体设备」而非实体,常见于「无线按钮被按下」这类集成事件,优点是在编辑器里选设备就行,缺点是换设备后要重选。它本质仍是事件,只是被包装得更易用。

时间类:最朴素也最多坑

time 触发器最直观:每天某个时刻执行。它支持指定时间点、星期几,甚至可以配合一个 input_datetime 实体实现「闹钟联动」——改 helper 的时间,自动化跟着变,不用重载配置。典型写法:

trigger:
  - platform: time
    at: "07:00:00"
  - platform: time
    at: input_alarm_time

第二个触发器引用了一个 helper 实体,它的时间被改了,触发点也立刻跟着变——这就是「可调闹钟」的标准做法。

sun 触发器跟日照走:event: sunrise 或 sunset,还能加偏移量(offset)。黎明前 30 分钟开窗帘、日落后 10 分钟开灯,都是它的典型用法。不过要记住:偏移是相对天文事件的,跟实际天黑程度略有出入,可以再叠一个光照传感器条件校准。

template 触发器里面有一种时间型用法:写一段模板判断「现在该不该执行」,HA 每秒评估一次,返回值从假变真时触发。适合「每月最后一个周五」「只在电价谷段」这类规则型时间。

一天里的时间触发

时间类触发最常见的坑是时区与夏令时。HA 以实例时区为准,容器部署如果时区没设对,所有定时任务会整体偏移。另外时间触发每天只在精确到秒的那一刻发一次,如果当时 HA 恰好重启错过了,这一天就没了——关键任务建议加一个补救逻辑(比如开机时检查并补执行)。

状态类:变化即触发

state 触发器监听某个实体从一种状态变到另一种状态。门窗传感器从关到开、插座从关到开、设备从家到不在家,都吃这一套。写法关心三样:entity_id、to、from,三者可省略可组合,省略 to 表示「变成任何状态都算」。

numeric_state 是数值版本:above、below 画两条线,数值跨过去就触发。两个高频配件:for 表示「持续多久才算数」,用来过滤传感器抖动;value_template 表示先算出一个数再比较,灵活度很高的同时也提醒你——模板里取值要是数字类型。

一个经典组合:温度高于 28 度且持续 5 分钟 → 打开空调。少了 for,传感器在 27.9 和 28.1 之间抖两下就会触发三四次,配合 restart 模式还能自我叠加。状态触发 + for 参数 + restart 模式,是温控类自动化的稳定三件套。

写出来大概是这样:

trigger:
  - platform: numeric_state
    entity_id: sensor.living_temp
    above: 28
    for: "00:05:00"
action:
  - service: climate.set_temperature
    target:
      entity_id: climate.ac
    data:
      temperature: 26
mode: restart

for 的值是「持续时间」,格式为 时:分:秒。注意它只在「持续满足」后才发触发,期间数值回落会重新计时,天然过滤毛刺。

事件类:直通事件总线

event 触发器直接监听事件总线上的具名事件,比如 homeassistant_start(系统启动完成)、zha_event(Zigbee 设备事件)、call_service(任意服务被调用)。它的参数只有 event_type 和可选的 event_data 过滤条件,但能力是最强的——因为 HA 内部一切显著动作都会发事件。

一个实用的例子:监听开关被外部物理按下的事件:

trigger:
  - platform: event
    event_type: zha_event
    event_data:
      command: "on"

事件触发器拿到的数据可以在动作里通过 trigger.event.data 访问,相当于把「谁、按了什么」一路传到执行端。调试事件最好的工具是「开发者工具 → 事件」里的监听功能:开着监听然后物理操作设备,总线上流过的事件会实时打印出来,照着抄参数最靠谱。

webhook 触发器把一个 URL 变成触发器:任何能发 HTTP 请求的东西(路由器、群晖、第三方服务)都能通过回调 URL 点火。安全做法是开启本地模式或加强鉴权,别把裸 URL 暴露在公网。webhook 触发后用 trigger.webhook.body 取请求体,配合模板解析 JSON。

mqtt 触发器监听某个主题的消息,适合已有 MQTT 基础设施的玩家:传感器上报、自定义固件、Homebridge 桥接都能走这条路。消息体可以是 JSON,触发后用模板解析字段。如果你还没有代理,在 NAS 上跑一个容器即可,具体做法可参考 《群晖 DSM 指南》 的容器章节。

事件类触发的来源

区域类:回家与离家

zone 触发器依赖 device tracker 实体和地理围栏区域:手机进入或离开 zone.home(或你自建的办公楼围栏)时触发。它的精度取决于定位来源——手机 App 的集成定位精度不错,纯路由器判定则取决于路由器的在线检测快慢。

区域触发的一个典型搭配是多设备共识:家里两个人,只有「所有人都离开」才算离家。实现思路是写条件判断所有 tracker 的状态,或干脆维护一个「家里有几个人」的传感器。第 3 章「回家与离家」一篇会给出完整方案。

区域触发的写法同样简洁,进和出是两个独立事件:

trigger:
  - platform: zone
    entity_id: device_tracker.my_phone
    zone: zone.home
    event: enter

开发时善用「开发者工具 → 状态」页面观察 tracker 的状态值,不同集成返回的字符串可能是 home/not_home 或具体围栏名,条件判断别写错。

选择触发器的三条原则

  1. 优先选窄的:能用 numeric_state 就别用 template,能用 state 就别监听总事件——越精确的触发器,误触发越少。
  2. 事件只在状态不够用时上:状态类天然带「变化」语义,事件类需要你自己描述「发生了什么」。
  3. 外部来源优先走官方集成:设备厂商有的集成先走集成,集成不支持再考虑 webhook、mqtt 这类通用通道。

再加一条经验之谈:一条自动化可以有多个触发器。触发器之间是 OR 关系,任何一个发生都会启动流水线。所以「按键按下」和「定时到点」可以共存于一条自动化,再用条件区分是谁触发的(通过 trigger.platform 或 trigger.entity_id 判断),逻辑紧凑又好维护。

最后提醒:触发器选好后,一定到「开发者工具 → 状态」里核对实体真实的状态值与精度。很多「不触发」的问题,根源只是实体返回的是字符串而不是数字,或者状态拼写与预期不符。先把数据看清楚,触发器才写得明白。

延伸阅读

  • 存在检测与 device tracker 的完整方案,见本系列「回家与离家:存在检测实战」。
  • MQTT 基础设施搭建可参考 《OpenWrt 入门》 中的服务章节,或直接在 NAS 上用 《群晖 DSM 指南》 的容器套件部署代理。