动作、触发器、条件
ESPHome 动作(actions)是我们让 ESPHome 设备执行操作的方式。
让我们从一个例子开始。假设你有一个包含以下内容的配置文件:
switch: - platform: gpio pin: GPIOXX name: "Living Room Dehumidifier"
binary_sensor: - platform: gpio pin: GPIOXX name: "Living Room Dehumidifier Toggle Button"使用这个文件,你已经可以执行一些基本任务。你可以通过 Home Assistant 的前端控制客厅除湿机的开关状态。但在许多情况下,严格通过前端控制一切并不理想。这就是为什么你还在除湿机旁边安装了一个连接到 GPIOXX 引脚的简单按钮。只需按下这个按钮,就应该切换除湿机的状态。
你可以在 Home Assistant 的自动化引擎中编写自动化来完成此任务,但 IoT 设备不应依赖网络连接来执行其工作——尤其对于像开关除湿机这样简单的操作。
使用 ESPHome 的自动化引擎,你可以使用一种(希望)与 Home Assistant 同样易于使用的语法来定义自动化。例如,以下配置可以实现你对除湿机的期望行为:
switch: - platform: gpio pin: GPIOXX name: "Living Room Dehumidifier" id: dehumidifier1
binary_sensor: - platform: gpio pin: GPIOXX name: "Living Room Dehumidifier Toggle Button" on_press: then: - switch.toggle: dehumidifier1让我们逐步了解这里发生的事情:
switch: - platform: gpio # ... id: dehumidifier1首先,我们必须给除湿机 switch 一个 ID,以便在自动化中引用它。
binary_sensor: - platform: gpio # ... on_press:现在我们给二进制传感器(代表按钮)附加一个特殊属性 on_press。这部分称为”触发器”。在此示例中,接下来的几行中的自动化将在有人开始按下按钮时执行。请注意,术语遵循鼠标按钮事件的命名方式。按下(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
# Same as:on_press: then: - switch.toggle: dehumidifier1 - light.toggle: dehumidifier_indicator_light作为最后一个示例,让我们让除湿机变得”智能”。当传感器报告的湿度高于 65% 时自动开启,当湿度降至 50% 以下时自动关闭:
sensor: - platform: dht humidity: name: "Living Room Humidity" on_value_range: - above: 65.0 then: - switch.turn_on: dehumidifier1 - below: 50.0 then: - switch.turn_off: dehumidifier1 temperature: name: "Living Room Temperature"缩进真不少。😉
on_value_range 是传感器的一种特殊触发器,当传感器值在指定范围内/高于/低于指定范围时触发。在第一个示例中,范围定义为”大于或等于 65.0 的任何值”,第二个范围指任何 50% 或以下的(湿度)值。
最后,对于那些”纯”YAML 自动化还不够用的情况,ESPHome 还提供了另一个极其强大的工具:模板。
至此,ESPHome 中的动作介绍就结束了。它们是使用易于使用的语法自动化设备上几乎所有功能的强大工具。下面是一些常用动作的索引,你一定会发现它们对构建各种自动化非常有用(甚至必不可少)。
delay 动作
Section titled “delay 动作”该动作将动作列表中下一个动作的执行延迟指定的时间段。
on_...: then: - switch.turn_on: relay_1 - delay: 2s - switch.turn_off: relay_1 # Templated, waits for 1s (1000ms) only if a reed switch is active - delay: !lambda "if (id(reed_switch).state) return 1000; else return 0;"NOTE
这是一个”智能”异步延迟——延迟发生时,其他代码仍会在后台运行。使用 lambda 调用时,应以毫秒为单位返回延迟值。
该动作首先计算 condition:,如果条件返回 true 则执行 then: 分支,如果条件返回 false 则执行 else: 分支。
所选分支(then 或 else)执行完毕后,继续执行下一个动作。
例如,下面是一个自动化,它检查传感器值是否低于 30,如果是,则打开灯 5 秒钟。否则,立即关闭灯。
on_...: then: - if: condition: lambda: 'return id(some_sensor).state < 30;' then: - logger.log: "The sensor value is below 30!" - light.turn_on: my_light - delay: 5s else: - logger.log: "The sensor value is above 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 动作
Section titled “lambda 动作”该动作执行任意一段 C++ 代码(参见 Lambda)。
on_...: then: - lambda: |- id(some_binary_sensor).publish_state(false);repeat 动作
Section titled “repeat 动作”该动作允许你重复执行一个块指定次数。 例如,下面的自动化将闪烁灯五次。
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: 10swait_until 动作
Section titled “wait_until 动作”该动作允许你的自动化等待直到某个条件评估为 true。(这实际上是一种简写方式,等价于编写一个 then 块为空的 while 动作。)
# In a trigger:on_...: - logger.log: "Waiting for binary sensor" - wait_until: binary_sensor.is_on: some_binary_sensor - logger.log: "Binary sensor is ready"如果你想使用超时,则需要使用”condition”这个术语:
# In a trigger:on_...: - logger.log: "Waiting for binary sensor" - wait_until: condition: binary_sensor.is_on: some_binary_sensor timeout: 8s - logger.log: "Binary sensor might be ready"while 动作
Section titled “while 动作”该动作类似于 if 动作。while 动作在给定条件为 true 时循环执行一个块。
# In a trigger:on_...: - while: condition: binary_sensor.is_on: some_binary_sensor then: - logger.log: "Still executing" - light.toggle: some_light - delay: 5scomponent.update 动作
Section titled “component.update 动作”使用此动作可以手动调用组件的 update() 方法。
请注意,这仅适用于某些组件类型,其他类型将导致编译错误。
on_...: then: - component.update: my_component
# The same as: - lambda: 'id(my_component).update();'component.suspend 动作
Section titled “component.suspend 动作”使用此动作可以手动调用组件的 stop_poller() 方法。
执行此动作后,组件将停止刷新。
在轮询器暂停期间,仍然可以通过使用 component.update 触发按需更新。
请注意,这仅适用于 PollingComponent 类型,其他类型将导致编译错误。
on_...: then: - component.suspend: my_component
# The same as: - lambda: 'id(my_component).stop_poller();'component.resume 动作
Section titled “component.resume 动作”使用此动作可以手动调用组件的 start_poller() 方法。
执行此动作后,组件将按原始的 update_interval 速率进行刷新。
这将允许组件在定义的间隔恢复自动更新。
此动作还允许更改更新间隔,无需先暂停,直接替换轮询器。
请注意,这仅适用于 PollingComponent 类型,其他类型将导致编译错误。
on_...: then: - component.resume: my_component
# The same as: - lambda: 'id(my_component).start_poller();'
# Change the poller intervalon_...: then: - component.resume: id: my_component update_interval: 15s“条件”为你的设备提供了一种仅在满足特定(一组)条件时才执行动作的方式。
and / all / or / any / xor / not 条件
Section titled “and / all / or / any / xor / not 条件”检查条件的组合。all 是 and 的同义词,any 是 or 的同义词。
all 和 any 也可以直接替代 condition 使用。
on_...: then: - if: condition: # Same syntax for `and` as well as `xor` conditions 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 条件
Section titled “for 条件”允许你检查给定条件是否已经持续为 true 至少指定的时间。
on_...: if: condition: for: time: 5min condition: api.connected: then: - logger.log: API has stayed connected for at least 5 minutes!component.is_idle 条件
Section titled “component.is_idle 条件”此条件检查给定组件是否处于空闲状态。如果组件已完成设置、未被标记为失败且当前未被循环任务调用,则认为该组件处于空闲状态。这对于将动作与组件状态同步非常有用,例如,需要大量时间更新显示面板的电子纸显示组件。
on_...: then: - if: condition: component.is_idle: some_component # ...lambda 条件
Section titled “lambda 条件”此条件执行任意一段 C++ 代码(参见 Lambda),可用于在动作中创建条件流程。
on_...: then: - if: condition: # Should return either true or false lambda: |- return id(some_sensor).state < 30; # ...- api:
respond - at581x:
reset,settings - ble_client:
ble_write,connect,disconnect,numeric_comparison_reply,passkey_reply,remove_bond - homeassistant:
action,event,tag_scanned
没有网络连接时自动化能工作吗
Section titled “没有网络连接时自动化能工作吗”这是一个常见问题,答案是**能!**你在 ESPHome 中定义的所有自动化都在微控制器本身上执行,即使 Wi-Fi 网络断开或 MQTT 服务器不可达,它们也能继续工作。
不过有一个注意事项:ESPHome 会在无法连接到其 API 时定期自动重启。这有助于解决设备网络栈出现问题导致无法在网络中访问的情况。你可以通过以下任一组件中的 reboot_timeout 选项来调整此行为(甚至禁用自动重启):
但请注意,禁用重启超时将有效地禁用重启看门狗,因此如果设备无法(或持续无法)在网络中访问,你将需要手动重新启动设备。
定时器与超时
Section titled “定时器与超时”虽然 ESPHome 没有提供专门的定时器构造,但你可以通过组合 script 和 delay 轻松实现定时器。通过分别使用脚本模式 single 和 restart,你可以实现绝对超时或滑动超时。
script: - id: hallway_light_script mode: restart # Light will be kept on during 1 minute since # the latest time the script is executed then: - light.turn_on: hallway_light - delay: 1 min - light.turn_off: hallway_light
... on_...: # can be called from different wall switches - script.execute: hallway_light_script有时你还需要一个不执行任何操作的定时器;在这种情况下,你可以使用单个 delay 动作,然后在(自动化中)使用 script.is_running 条件来判断你的”定时器”是否处于活动状态。