跳转到内容

操作、触发器、条件

ESPHome 操作 是我们让 ESPHome 设备 执行某些操作 的方式。

让我们从一个例子开始。假设您有一个配置文件,其中包含:

switch:
- platform: gpio
pin: GPIOXX
name: "客厅除湿机"
binary_sensor:
- platform: gpio
pin: GPIOXX
name: "客厅除湿机切换按钮"

使用此文件,您已经可以执行一些基本任务。您可以从 Home Assistant 的前端控制客厅除湿机的开/关状态。但在许多情况下,完全从前端控制所有内容并不理想。这就是为什么您还在除湿机旁边安装了一个简单的按钮,连接到 GPIOXX 引脚。只需按下此按钮即可切换除湿机的状态。

可以 在 Home Assistant 的自动化引擎中编写自动化来执行此任务,但 IoT 设备不应依赖网络连接来执行其工作——尤其是对于像开关除湿机这样简单的操作。

使用 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_releaseon_clickon_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 中操作的介绍到此结束。它们是一个强大的工具,可以用简单的语法自动化设备上的几乎所有内容。下面是常用操作的索引,您一定会发现它们对于构建各种自动化非常有用(甚至是必不可少的)。

此操作将操作列表中下一个操作的执行延迟指定的时间段。

on_...:
then:
- switch.turn_on: relay_1
- delay: 2s
- switch.turn_off: relay_1
# 使用模板,仅当干簧管处于活动状态时等待 1 秒(1000 毫秒)
- delay: !lambda "if (id(reed_switch).state) return 1000; else return 0;"

NOTE

这是一个”智能”异步延迟——其他代码仍将在延迟期间在后台运行。使用 lambda 调用时,您应该返回以毫秒为单位的延迟值。

此操作首先评估 condition:,然后如果条件返回 true 则执行 then: 分支,如果条件返回 false 则执行 else: 分支。

当所选分支(thenelse)执行完成后,执行下一个操作。

例如,下面的自动化检查传感器值是否低于 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

必须提供 conditionallany 中的至少一个。

  • condition (可选, 条件): 要检查的条件,用于确定执行哪个分支。如果配置为条件列表,则它们必须全部为 true 条件才为 true。

  • all (可选, 条件): 接受一个条件列表,所有条件都必须为 true(因此等同于 condition。)

  • any (可选, 条件): 接受一个条件列表;如果至少有一个为 true,则条件将为 true。

  • then (可选, 操作): 如果条件评估为 true 则执行的操作。默认为不执行任何操作。

  • else (可选, 操作): 如果条件评估为 false 则执行的操作。默认为不执行任何操作。

此操作执行任意 C++ 代码(参见 Lambda)。

on_...:
then:
- lambda: |-
id(some_binary_sensor).publish_state(false);

此操作允许您重复执行一个块指定的次数。 例如,下面的自动化将闪烁灯五次。

on_...:
- repeat:
count: 5
then:
- lambda: ESP_LOGI("main", "Turning lights on for iteration [%d]", iteration);
- light.turn_on: some_light
- delay: 1s
- lambda: ESP_LOGI("main", "Turning lights off for iteration [%d]", iteration);
- light.turn_off: some_light
- delay: 10s
  • count (必需, int): 操作应重复的次数。计数器可以通过隐式脚本参数 iteration 在 lambda 中使用。

  • then (必需, 操作): 要重复的操作。

此操作允许您的自动化等待直到条件评估为 true。(所以这只是编写带有空 then 块的 while 操作的一种简写方式。)

# 在触发器中:
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: "二进制传感器可能就绪"
  • condition (必需, 条件): 等待变为 true 的条件。
  • timeout (可选, 时间): 超时前等待的时间。默认为永不超时。

此操作类似于 if 操作。while 操作只要给定条件为 true 就循环执行一个块。

# 在触发器中:
on_...:
- while:
condition:
binary_sensor.is_on: some_binary_sensor
then:
- logger.log: "仍在执行"
- light.toggle: some_light
- delay: 5s
  • condition (必需, 条件): 要检查的条件,用于确定是否执行。

  • then (必需, 操作): 执行直到条件评估为 false 的操作。

使用此操作您可以手动调用组件的 update() 方法。

请注意,这仅适用于某些组件类型,其他组件将导致编译错误。

on_...:
then:
- component.update: my_component
# 等同于:
- lambda: 'id(my_component).update();'

使用此操作您可以手动调用组件的 stop_poller() 方法。

执行此操作后,组件将停止刷新。

当轮询器暂停时,仍然可以通过使用 component.update 触发按需更新。

请注意,这仅适用于 PollingComponent 类型,其他组件将导致编译错误。

on_...:
then:
- component.suspend: my_component
# 等同于:
- lambda: 'id(my_component).stop_poller();'

使用此操作您可以手动调用组件的 start_poller() 方法。

执行此操作后,组件将以原始 update_interval 速率刷新。

这将允许组件以定义的间隔恢复自动更新。

此操作还允许更改更新间隔,无需暂停即可直接替换轮询器。

请注意,这仅适用于 PollingComponent 类型,其他组件将导致编译错误。

on_...:
then:
- component.resume: my_component
# 等同于:
- lambda: 'id(my_component).start_poller();'
# 更改轮询器间隔
on_...:
then:
- component.resume:
id: my_component
update_interval: 15s

“条件”提供了一种方式,让您的设备仅在满足特定条件(集)时才执行操作。

检查条件的组合。alland 的同义词,anyor 的同义词。 allany 也可以直接用于代替 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_sensor

允许您检查给定条件是否已持续 true 至少指定的时间。

on_...:
if:
condition:
for:
time: 5min
condition:
api.connected:
then:
- logger.log: API 已保持连接至少 5 分钟!
  • time (必需, 可模板化, 时间): 条件必须持续为 true 的时间。

  • condition (必需, 条件): 要检查的条件。

此条件检查给定组件是否空闲。如果组件已完成设置、未被标记为失败且当前未被循环任务调用,则认为该组件处于空闲状态。这对于将操作与组件状态同步非常有用,例如,需要大量时间更新显示面板的电子墨水屏组件。

on_...:
then:
- if:
condition:
component.is_idle: some_component
# ...

此条件执行任意 C++ 代码(参见 Lambda) 可用于在操作中创建条件流程。

on_...:
then:
- if:
condition:
# 应返回 true 或 false
lambda: |-
return id(some_sensor).state < 30;
# ...

自动化在没有网络连接的情况下是否工作

Section titled “自动化在没有网络连接的情况下是否工作”

这是一个常见问题,答案是 是的! 您在 ESPHome 中定义的所有自动化都在微控制器本身上执行,即使 Wi-Fi 网络断开或 MQTT 服务器不可达,它们仍将继续工作。

但有一个注意事项:如果没有连接到其 API,ESPHome 将定期自动重启。这有助于在设备网络栈出现问题导致其在网络上无法访问时进行恢复。您可以在以下任何组件中使用 reboot_timeout 选项来调整此行为(甚至禁用自动重启):

请注意,禁用重启超时实际上会禁用重启看门狗,因此如果设备在网络上无法访问/持续无法访问,您需要手动重启设备。

虽然 ESPHome 不提供定时器结构,但您可以通过组合 scriptdelay 轻松实现它们。您可以使用脚本模式 singlerestart 分别实现绝对超时或滑动超时。

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 条件来了解您的”定时器”是否处于活动状态。