动作、触发器、条件
ESPHome 的 动作 是我们让 ESPHome 设备 执行某些操作 的方法。
让我们从一个例子开始。假设你有一个配置文件,其中包含:
switch:
- platform: gpio
pin: GPIOXX
name: "客厅除湿器"
binary_sensor:
- platform: gpio
pin: GPIOXX
name: "客厅除湿器切换按钮"使用这个文件,你就可以执行一些基本任务。你可以从 Home Assistant 的前端控制客厅除湿器的开/关状态。但在许多情况下,严格从前端控制所有东西并不理想。这就是为什么你还在除湿器旁边安装了一个简单的按钮,连接到 GPIOXX 引脚。按下这个按钮应该切换除湿器的状态。
你 可以 在 Home Assistant 的自动化引擎中编写自动化来完成这个任务,但物联网设备不应该依赖于网络连接来执行它们的工作——尤其是像开关除湿器这样简单的事情。
使用 ESPHome 的自动化引擎,你可以使用一种(希望)与 Home Assistant 一样易于使用的语法来定义自动化。例如,以下配置将实现除湿器所需的行为:
switch:
- platform: gpio
pin: GPIOXX
name: "客厅除湿器"
id: dehumidifier1
binary_sensor:
- platform: gpio
pin: GPIOXX
name: "客厅除湿器切换按钮"
on_press:
then:
- switch.toggle: dehumidifier1让我们逐步了解这里发生的事情:
switch:
- platform: gpio
# ...
id: dehumidifier1首先,我们必须给除湿器的 switch 一个 ID,以便我们可以在自动化内部引用它。
触发器
binary_sensor:
- platform: gpio
# ...
on_press:我们现在将特殊的属性 on_press 添加到二进制传感器(代表按钮)。这部分称为“触发器”。在这个例子中,接下来的几行代码中的 自动化 将在有人 开始按下 按钮时执行。请注意,术语遵循你在鼠标按钮上如何称呼这些事件。按下 发生在你开始按下按钮时。还有其他触发器,如 on_release、on_click 或 on_double_click。
# ...
on_press:
then:
- switch.toggle: dehumidifier1动作
现在来到了实际的自动化块。使用 then,你告诉 ESPHome 当按下发生时应该做什么。在这个块中,你可以定义几个“动作”,这些动作将按顺序执行。例如,switch.toggle 和后面的那行代码形成一个动作。每个动作由一个破折号分隔,并且可以通过简单地添加另一个 - 来执行多个动作,如下所示:
# ...
on_press:
then:
- switch.toggle: dehumidifier1
- delay: 2s
- switch.toggle: dehumidifier1使用这个自动化,按下按钮会使除湿器开启/关闭 2 秒,然后恢复到原始状态。你也可以有一个触发器,带有多个自动化:
# ...
on_press:
- then:
- switch.toggle: dehumidifier1
- then:
- light.toggle: dehumidifier_indicator_light
# 与下面的相同:
on_press:
then:
- switch.toggle: dehumidifier1
- light.toggle: dehumidifier_indicator_light作为最后一个例子,让我们使我们的除湿器“智能”。让它在上报的传感器湿度超过 65% 时自动开启,并在低于 50% 时再次关闭:
sensor:
- platform: dht
humidity:
name: "客厅湿度"
on_value_range:
- above: 65.0
then:
- switch.turn_on: dehumidifier1
- below: 50.0
then:
- switch.turn_off: dehumidifier1
temperature:
name: "客厅温度"这有很多缩进。 😉
on_value_range 是传感器的特殊触发器,当传感器的值在/高于/低于指定范围内时触发。在第一个例子中,这个范围被定义为“任何高于或等于 65.0 的值”,第二个范围指的是任何(湿度)值 50% 或更低。
最后,对于“纯粹的” YAML 自动化无法完全满足的情况,ESPHome 提供了另一个非常强大的工具:模板。
现在,ESPHome 动作的介绍就结束了。它们是一种易于使用的语法,可以自动化设备上的几乎所有内容。以下是一个索引,列出了你一定会发现有用(甚至必不可少)的常见动作,用于构建各种自动化。
常见动作
delay 动作
这个动作通过指定的时间段延迟动作列表中的下一个动作的执行。
on_...:
then:
- switch.turn_on: relay_1
- delay: 2s
- switch.turn_off: relay_1
# 模板化,只有在干簧开关激活时才等待 1s(1000ms)
- delay: !lambda "if (id(reed_switch).state) return 1000; else return 0;"ℹ️ Note
这是一个“智能”的异步延迟——在延迟发生时,后台仍然会运行其他代码。使用 lambda 调用时,你应该以毫秒为单位返回延迟值。
if 动作
这个动作首先评估 condition:,然后如果条件返回 true,则执行 then: 分支;如果返回 false,则执行 else: 分支。
在选择的分支(then 或 else )执行完成后,将执行下一个动作。
例如,下面是一个自动化,它检查传感器值是否低于 30,如果是,则打开灯 5 秒。否则,灯会立即关闭。
on_...:
then:
- if:
condition:
lambda: 'return id(some_sensor).state < 30;'
then:
- logger.log: "传感器值低于 30!"
- light.turn_on: my_light
- delay: 5s
else:
- logger.log: "传感器值高于 30!"
- light.turn_off: my_light配置变量
至少必须提供 condition、all 或 any 中的一个。
condition (可选,Condition): 要检查的条件,以确定要采取哪个分支。 如果配置了条件列表,则所有条件都必须为
true,条件才为true。all (可选,Condition): 接受一个条件列表,所有条件都必须为
true(因此与condition等价。)any (可选,Condition): 接受一个条件列表;如果至少有一个为
true,条件将为true。then (可选,Action): 如果条件评估为
true,要执行的动作。 默认为不执行任何操作。else (可选,Action): 如果条件评估为
false,要执行的动作。 默认为不执行任何操作。
lambda 动作
这个动作执行任意一段 C++ 代码(见 Lambda)。
on_...:
then:
- lambda: |-
id(some_binary_sensor).publish_state(false); repeat 动作
这个动作允许你重复指定次数的块。 例如,下面的自动化将点亮灯五次。
on_...:
- repeat:
count: 5
then:
- light.turn_on: some_light
- delay: 1s
- light.turn_off: some_light
- delay: 10s配置变量
count (必须,int): 动作应该重复的次数。计数器可以使用保留字 “iteration” 在 lambda 中访问。
then (必须,Action): 要重复的动作。
wait_until 动作
这个动作允许你的自动化等待条件评估为 true。 (所以这只是编写 while 动作并带有空 then 块的简写方式。)
# 在触发器中:
on_...:
- logger.log: "等待二进制传感器"
- wait_until:
binary_sensor.is_on: some_binary_sensor
- logger.log: "二进制传感器准备好了"如果你想要使用超时,则需要使用 “condition”:
# 在触发器中:
on_...:
- logger.log: "等待二进制传感器"
- wait_until:
condition:
binary_sensor.is_on: some_binary_sensor
timeout: 8s
- logger.log: "二进制传感器可能准备好了"配置变量
while 动作
这个动作类似于 if 动作。while 动作会一直循环一个块,直到给定的条件为 true。
# 在触发器中:
on_...:
- while:
condition:
binary_sensor.is_on: some_binary_sensor
then:
- logger.log: "仍在执行"
- light.toggle: some_light
- delay: 5s配置变量
component.update 动作
使用这个动作,你可以手动调用组件的 update() 方法。
请注意,这仅适用于某些组件类型,其他类型将导致编译错误。
on_...:
then:
- component.update: my_component
# 与下面的相同:
- lambda: 'id(my_component).update();'component.suspend 动作
使用这个动作,你可以手动调用组件的 stop_poller() 方法。
执行此动作后,组件将停止刷新。
在轮询器挂起期间,仍然可以通过使用 component.update 来触发按需更新。
请注意,这仅适用于轮询组件类型,其他类型将导致编译错误。
on_...:
then:
- component.suspend: my_component
# 与下面的相同:
- lambda: 'id(my_component).stop_poller();'component.resume 动作
使用这个动作,你可以手动调用组件的 start_poller() 方法。
执行此动作后,组件将按照原始的 update_interval 速率刷新
这将允许组件在定义的间隔内恢复自动更新。
此动作还允许更改更新间隔,在不挂起的情况下调用它,将直接替换轮询器。
请注意,这仅适用于轮询组件类型,其他类型将导致编译错误。
on_...:
then:
- component.resume: my_component
# 与下面的相同:
- lambda: 'id(my_component).start_poller();'
# 更改轮询器间隔
on_...:
then:
- component.resume:
id: my_component
update_interval: 15s常见条件
“条件”为你的设备提供了一种方法,只有在特定的(一组)条件得到满足时才执行动作。
and / all / or / any / xor / not 条件
检查条件组合。all 是 and 的同义词,any 是 or 的同义词。
all 和 any 也可以直接用于代替 condition。
on_...:
then:
- if:
condition:
# `and` 条件和 `xor` 条件的语法相同
or:
- binary_sensor.is_on: some_binary_sensor
- binary_sensor.is_on: other_binary_sensor
# ...
- if:
any:
- not:
binary_sensor.is_off: some_binary_sensor
- binary_sensor.is_on: some_other_sensorfor 条件
允许你检查给定的条件是否至少已经为给定的时间为 true。
on_...:
if:
condition:
for:
time: 5min
condition:
api.connected:
then:
- logger.log: API 已经保持连接至少 5 分钟了!配置变量
time (必须,templatable,Time): 条件必须为
true的时间。condition (必须,condition): 要检查的条件。
lambda 条件
这个条件执行任意一段 C++ 代码(见 Lambda),并可用于在动作中创建条件流程。
on_...:
then:
- if:
condition:
# 应该返回 true 或 false
lambda: |-
return id(some_sensor).state < 30;
# ...所有动作
⚠️ Data not found for branch: 2025.8.4
所有条件
⚠️ Data not found for branch: 2025.8.4
小贴士和技巧
无网络连接时自动化是否工作
这是一个常见问题,答案是 是的! 你在 ESPHome 中定义的所有自动化都在微控制器上执行,即使 Wi-Fi 网络中断或 MQTT 服务器不可达,它们仍然可以继续工作。
不过,有一个例外:如果 ESPHome 没有连接到其 API,它将自动定期重启。这有助于在设备网络栈出现问题,导致设备无法在网络中可达的情况下。你可以使用以下组件中的 reboot_timeout 选项来调整此行为(甚至禁用自动重启):
但是要注意,禁用重启超时实际上禁用了重启看门狗,因此如果设备被证明/仍然无法在网络中可达,你需要手动断电重启设备。
定时器和超时
虽然 ESPHome 没有提供定时器结构,但你可以通过结合 script 和 delay 来轻松实现它们。你可以通过使用 script 模式 single 和 restart 分别来实现绝对超时和滑动超时。
script:
- id: hallway_light_script
mode: restart # 灯将在最新执行脚本的时间后保持开启 1 分钟
then:
- light.turn_on: hallway_light
- delay: 1 min
- light.turn_off: hallway_light
...
on_...: # 可以从不同的墙壁开关调用
- script.execute: hallway_light_script有时,你可能还需要一个不执行任何操作的定时器;在这种情况下,你可以使用单个 delay 动作,然后在你的自动化中使用 script.is_running 条件来知道你的“定时器”是否活跃。