跳转至

HA 自动化翻车 10 例:从反复亮灭到循环触发,一次讲清根因和修法

自动化这东西,写的时候觉得自己想得很清楚,跑起来却总在奇怪的地方翻车。我整理了 10 个最高频的翻车现场——没有一个是"逻辑想错了",全是触发器、条件、上下文这三件套没吃透。每个都给根因和可直接抄的 YAML 修法,照着改就能避坑。

基础概念(trigger / condition / action、mode)先复习 自动化入门;模板报错这一类专门看 Jinja2 模板排障。

第 1 例:人体传感器抖动,灯反复亮灭

现象:人坐那没动,灯自己一闪一闪;或者人走了灯还亮、回来又灭。

根因:人体/红外传感器边缘会抖动,一次经过可能触发好几次;门窗磁也一样,信号偶尔跳变。自动化每次都被带着重跑,灯就跟着抽风。

修法:要么让触发"持续一小段时间才算数",要么让同一次事件只跑一遍:

trigger:
  - platform: state
    entity_id: binary_sensor.hall_motion
    to: "on"
    for: "00:00:05"   # 持续 5 秒才认定有人,抖一下不算

或者把自动化 mode 设成不叠加:

mode: single   # 上一次没跑完,新触发直接忽略;也可用 restart

结论:传感器抖动是第一大坑,for: 去抖 + mode: single 基本能灭掉九成的反复亮灭。

第 2 例:两个自动化抢同一盏灯

现象:一个自动化说"有人开灯",另一个说"没人关灯",结果灯在开/关之间反复横跳。

根因:把"开"和"关"拆成两条独立自动化,它们各自判断、各自执行,谁也不知对方存在,于是互相打架。

修法:同一设备的所有逻辑合并进一个自动化,用 choose 分支:

trigger:
  - platform: state
    entity_id: binary_sensor.hall_motion
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: binary_sensor.hall_motion
            state: "on"
        sequence:
          - service: light.turn_on
            target: { entity_id: light.hall }
      - conditions:
          - condition: state
            entity_id: binary_sensor.hall_motion
            state: "off"
        sequence:
          - service: light.turn_off
            target: { entity_id: light.hall }

结论:控制面收敛到一处。同一盏灯的所有逻辑在一个自动化里用 choose 分流,别让两条自动化各管各的。

第 3 例:condition 写对了却从不触发

现象:加了 condition 之后自动化干脆不跑了,去掉又乱跑。

根因:把"某个状态等于 X"写成了 trigger 上下文里的判等。trigger 类条件只在"由触发引起"的上下文里有值;你想判断"当前实时状态是不是 X",得用 state 触发或在 condition 里显式写实体。

修法:分清两种判等:

# 想判断"现在状态是不是 on",用 state 条件,写清实体
condition:
  - condition: state
    entity_id: light.hall
    state: "on"

trigger 与 condition 的区别、trigger 上下文变量怎么用,看 trigger 与 condition 区别。

结论:trigger 上下文只活在"触发那一刻",判断实时状态必须用 state 条件写实体 id。

第 4 例:晚上自动化大白天跑

现象:设了"日落后开灯",结果下午也开;或定时任务时间点全差了 8 小时。

根因:时区没设对。HA 的 time / sun 触发器按系统时区算,装完没配 timezone 或 Docker 没传 TZ,就按 UTC 跑,比本地晚 8 小时。

修法:先确认时区:

  • 设置 → 系统 → 常规 里把时区设成本地(如 Asia/Shanghai);
  • Docker 启动务必传 -e TZ=Asia/Shanghai,否则容器内时间还是 UTC。
docker run -d --name ha \
  -e TZ=Asia/Shanghai \
  -p 8123:8123 \
  ghcr.io/home-assistant/home-assistant:stable

结论:所有"时间不对"的怪事,先查时区,再查自动化的时间窗口。

第 5 例:模板报错,整条自动化挂掉

现象:改了个模板,自动化直接不执行,日志里一堆 Jinja 报错。

根因:模板语法错(少了括号、变量不存在、用了列表当字符串),HA 解析 YAML 时整条挂。

修法:上线前先到 开发者工具 → 模板 里把模板跑一遍,能渲染出预期结果再粘进自动化。常见写法:

# 先判断变量存在,避免 None 当字符串用
action:
  - service: notify.mobile_app
    data:
      message: "温度 {{ states('sensor.living_temp') }}"

模板排错的完整套路看 Jinja2 模板排障。

结论:模板先 dev tools 测、再进自动化,能省掉一半"改完就挂"的来回。

第 6 例:设备离线,condition 永远不过

现象:某个设备掉线后,依赖它的自动化要么卡死、要么永远不执行。

根因:condition 判某个实体状态,但设备离线时实体是 unavailable,既不是你判的 on 也不是 off,于是条件永远不满足。

修法:用 availability 把离线状态显式处理,或给状态判断加兜底:

condition:
  - condition: state
    entity_id: binary_sensor.door
    state: "on"
  - condition: template
    value_template: "{{ states('binary_sensor.door') not in ['unavailable','unknown'] }}"

或直接在 action 里判断可用性再执行,避免对离线设备发指令。

结论:凡依赖外部设备状态的自动化,都要显式处理 unavailable,否则设备一掉线逻辑就失聪。

第 7 例:升级之后自动化失效

现象:某次升级后,原本好用的自动化不动了,也没报错。

根因:用了 device 触发器/条件。设备重新接入或重命名后 device id 会变,绑定 device 的自动化就断了;而 entity id 稳定得多。

修法:一律用 entity 写触发器和条件,别用 device:

# 不推荐:platform: device,device_id 一变就断
# 推荐:
trigger:
  - platform: state
    entity_id: light.hall   # 实体稳定,改名也只改这一处

结论:device 图省事但脆弱,entity 才是长期不坏写法。升级后失效先查是不是用了 device。

第 8 例:灯一亮又触发自身再开灯(循环触发)

现象:自动化开灯 → 灯状态变 on → 又触发"灯变 on 就开灯" → 无限循环或卡死。

根因:trigger 监听了"灯状态变化",而 action 本身又改变了灯状态,事件回灌把自己喂死了。

修法:trigger 只听"人/传感器",不听"灯自己";或用 trigger 上下文过滤掉自身引起的变化:

trigger:
  - platform: state
    entity_id: binary_sensor.hall_motion
    to: "on"
# 注意:别把 light.hall 放进 trigger,否则开关灯都会反噬

结论:触发源和动作目标要隔离——听传感器,别听被控制的设备自己。

第 9 例:只在工作日执行的自动化,周末也跑

现象:"上班时间离家关灯"周末也触发了,人还在家灯就灭了。

根因:只用时间窗口判断,没区分工作日/周末。

修法:接 workday 集成(或 binary_sensor.workday),把"是不是工作日"作为 condition:

condition:
  - condition: state
    entity_id: binary_sensor.workday
    state: "on"

结论:涉及"工作日/节假日"的逻辑,别靠手写时间,用 workday 集成兜底。

第 10 例:2FA 挡住了 service 调用

现象:自动化调用某个 service 时报权限错,手动点却正常。

根因:该 service 需要管理员上下文,而自动化默认上下文被 2FA / 管理员保护挡下。

修法:确认 service 本身是否需要提权;用 HA 自动化入门 里讲到的 automation 上下文,或在调用前显式声明所需权限。更稳妥的是把敏感操作拆成需要人工确认的步骤,而不是让自动化偷偷提权。

结论:自动化不是万能钥匙,涉及管理员权限的 service 要显式授权,别让自动化绕过 2FA。

10 例实操的最小避坑清单

  1. 传感器抖动 → trigger 加 for: 或自动化 mode: single(第 1 例)。
  2. 多自动化抢设备 → 合并到一处用 choose(第 2 例)。
  3. condition 不触发 → 判实时状态用 state 条件写实体(第 3 例)。
  4. 时间全错 → 先查时区 TZ(第 4 例)。
  5. 模板报错 → 上线前 dev tools 测(第 5 例)。
  6. 设备离线失聪 → 显式处理 unavailable(第 6 例)。
  7. 升级失效 → 用 entity 别用 device(第 7 例)。
  8. 循环触发 → 触发源隔离,别听被控设备(第 8 例)。
  9. 周末漏逻辑 → 接 workday 集成(第 9 例)。
  10. 权限被挡 → automation 上下文显式授权(第 10 例)。

一句话总结:自动化翻车几乎都落在"触发谁、条件判什么、上下文是谁"这三件事上。把这三件套想清楚,再复杂的联动也能稳。想用节点流替代 YAML 的,参考 Node-RED 自动化。

相关教程