【ESPHome】on_loop 中如果 delay 了,会影响整个 Esphome 程序运行吗?

如题。

配置如下,问每秒刷新的 text_sensor 是否会被 on_loop 中的 delay:3s 阻塞?

# Apply to ESPHOME 1.14.3
# 测试开发板:Goouuu MiniS1
# board: ESP8266-S1 由于 PIO 不支持这个板子,山寨板子只有2M Flash故此选择 esp8285

substitutions:
  devicename: 'wifi_hotport'
  wifi_ssid: !secret wifi_ssid
  wifi_password: !secret wifi_password
  api_password: !secret api_password
  ota_password: !secret ota_password
  status_light_time: "4s"
  hotport_ssid: !secret hotport_ssid
  hotport_password: !secret hotport_password

esphome:
  name: $devicename
  platform: ESP8266
  board: esp8285
  on_boot:
    # --------------------------------------------
    #这个板子默认亮起 led 灯,所以启动时候要灭掉。
    - light.turn_off: red_light
    - light.turn_off: green_light
    - light.turn_off: blue_light
  # ----------------------------------------------
  # 循环检查 wifi 状态,修改指示灯。
  on_loop:
    then:
        - light.turn_on: red_light
        - delay: 3s
        - light.turn_off: red_light

wifi:
  # 设置ID 可以在 lambda 下用 id($id_name) 调用,继承 WiFiComponent 类。
  id: wifi_state
  ssid: $wifi_ssid
  password: $wifi_password
  # 启动 AP 模式,当
  ap:
    ssid: $hotport_ssid
    password: $hotport_password
captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: $api_password
  reboot_timeout: 0s


text_sensor:
  - platform: template
    name: "TEST"
    lambda: |-
      return {"Hello World"};
    update_interval: 1s

ota:
  password: $ota_password

light:
  - platform: binary
    name: "red_light"
    id: "red_light"
    output: RED_LED_GPIO12
  - platform: binary
    name: "blue_light"
    id: "blue_light"
    output: BLUE_LED_GPIO14
  - platform: binary
    name: "green_light"
    id: "green_light"
    output: GREEN_LED_GPIO13

output:
  - platform: gpio
    id: RED_LED_GPIO12
    pin: GPIO12
    inverted: true
  - platform: gpio
    id: BLUE_LED_GPIO14
    pin: GPIO14
    inverted: true
  - platform: gpio
    id: GREEN_LED_GPIO13
    pin: GPIO13
    inverted: true

经过测试

  on_loop:
    then:
        - light.turn_on: red_light
        - delay: 3s
        - light.turn_off: red_light

这样写是错误的。

这三个动作都是 同时进行。on 和 off 还有delay 分别是三个不同的任务。

所以没法delay?

并不是没有办法,从 esphome 翻译过来的 C++ 文件看,这样写是不对的,这样他生成了三个自动化实例,然后多任务(只是猜测)执行他们。

  delayaction = new DelayAction<>();
  App.register_component(delayaction);
  delayaction->set_delay(4000);
  light_lightcontrolaction_5 = new light::LightControlAction<>(red_light);
  light_lightcontrolaction_5->set_state(false);
  automation_2->add_actions({light_lightcontrolaction_4, delayaction, light_lightcontrolaction_5});

但是 换一个做法。

  on_loop:
    then:
      lambda: |-
        // 如果 WIFI 连接上了
        if (id(wifi_state).is_connected())
        {
          //ESP_LOGD("WIFI","WIFI connected Code:%d",int(id(wifi_state).is_connected()));
          // 蓝灯未亮起
          if (!id(blue_light).remote_values.get_state())
          {
            auto blue_light_on = id(blue_light).turn_on();
            blue_light_on.perform();
          }
        }
        // 如果 WiFi 未连接
        else
        {
          //ESP_LOGD("WIFI","WIFI not connect Code:%d",int(id(wifi_state).is_connected()));
          auto blue_light_off = id(blue_light).turn_off();
          auto red_light_on = id(red_light).turn_on();
          red_light_on.perform();
          delay(3000);
          auto red_light_off = id(red_light).turn_off();
          red_light_off.perform();
        }

直接在 on_loop 中写 lambda 的话,使用 delay(3000) 就会阻塞主程序。

所以 on_loop 里面不能使用 lambda 来写 delay。

实现 WIFI 指示灯的功能如下:

# Apply to ESPHOME 1.14.3
# 测试开发板:Goouuu MiniS1
# board: ESP8266-S1 由于 PIO 不支持这个板子,山寨板子只有2M Flash故此选择 esp8285

substitutions:
  devicename: 'wifi_hotport'
  wifi_ssid: !secret wifi_ssid
  wifi_password: !secret wifi_password
  api_password: !secret api_password
  ota_password: !secret ota_password
  status_light_time: "4s"
  hotport_ssid: !secret hotport_ssid
  hotport_password: !secret hotport_password

esphome:
  name: $devicename
  platform: ESP8266
  board: esp8285
  on_boot:
    # --------------------------------------------
    #这个板子默认亮起 led 灯,所以启动时候要灭掉。
    - light.turn_off: red_light
    - light.turn_off: green_light
    - light.turn_off: blue_light
  # ----------------------------------------------
  # 循环检查 wifi 状态,修改指示灯。
  on_loop:
    then:
      # 如果 wifi 未连接,关闭蓝灯,执行 script:red_binary(红灯闪烁)
      # 这里 script 是异步处理的,script 里面加延迟并不会阻塞主程序
      # 也不能使用以下方式
      # ----错误示范-----
        # on_loop:
        #   then:
        #       - light.turn_on: red_light
        #       - delay: 3s
        #       - light.turn_off: red_light
      # -----------------
      # 上方的做法只是三个任务分开执行,关闭红灯和亮起红灯在主程序时间线上是同步执行的.
      - if:
          condition:
            not:
              - wifi.connected:
          then:
            if:
              condition:
                not:
                  - script.is_running: red_binary
              then:
                - script.execute: red_binary
      # 如果 wifi 连接正常,并蓝灯还没亮起,那么亮起蓝灯。
      - if:
          condition:
            and:
              - light.is_off: blue_light
              - wifi.connected:
          then:
            - light.turn_on: blue_light

wifi:
  # 设置ID 可以在 lambda 下用 id($id_name) 调用,继承 WiFiComponent 类。
  id: wifi_state
  ssid: $wifi_ssid
  password: $wifi_password
  # 启动 AP 模式,当
  ap:
    ssid: $hotport_ssid
    password: $hotport_password
captive_portal:

# AP 模式下必须启用
web_server:
  port: 80

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: $api_password
  reboot_timeout: 0s


text_sensor:
  - platform: template
    name: "TEST"
    lambda: |-
      return {"Hello World"};
    update_interval: 2s

ota:
  password: $ota_password

light:
  - platform: binary
    name: "red_light"
    id: "red_light"
    output: RED_LED_GPIO12
  - platform: binary
    name: "blue_light"
    id: "blue_light"
    output: BLUE_LED_GPIO14
  - platform: binary
    name: "green_light"
    id: "green_light"
    output: GREEN_LED_GPIO13

output:
  - platform: gpio
    id: RED_LED_GPIO12
    pin: GPIO12
    inverted: true
  - platform: gpio
    id: BLUE_LED_GPIO14
    pin: GPIO14
    inverted: true
  - platform: gpio
    id: GREEN_LED_GPIO13
    pin: GPIO13
    inverted: true

script:
  - id: red_binary
    then:
      # 如果蓝灯亮起就熄灭它
      - if:
          condition:
            light.is_on: blue_light
          then:
            light.turn_off: blue_light
      - light.turn_on: red_light
      - delay: 1000ms
      - light.turn_off: red_light
      - delay: 1000ms