Are Fan Events broken?

Good day!

The following configuration should turn a fan on and off at specified intervals. The initial state doesn’t matter. According to home assistant, when the esp32 board starts, it turns off the fan. That should trigger the on_turn_off event. But nothing happens. The events don’t seem to get called.

esp32:
  board: esp32dev
  framework:
    type: arduino

fan:
  - platform: binary
    id: fan1
    name: "Fan"
    output: gpio_fan
    on_turn_on:
      - delay: 60min
      - fan.turn_off: fan1
    on_turn_off:
      - delay: 120min
      - fan.turn_on: fan1

Many Greetings!
Remo

May relate to this. Setting of the initial state may not trigger the event.

As alternatives you could look into using on_boot: and/or interval:

Hi Mahko!

No, this suggestion is, in my opinion, a needless increase of complexity. You can solve that with scripts.

Actually the documentation doesn’t state, when exactly the events get called. So I assumed the fan has an uninitialized state during boot and gets a new state during initialization. But it seems that there is no such thing as an uninitialized state and the initialization is no state change.

Triggering with on_boot event works, but since I need asymmetric time delays, the interval component wont work. But eventually I solved it with an endless loop in a script now, that allows for cleaner code and solves some potential technical issues the initial solution with events has. Like what happens if a manual toggle occurs while one of the event handlers is still running.

Many Greetings!
Remo

1 Like

Great you found a solution you prefer. Please share it back for the next person;) I can see how a script could work well too. They are quite flexible.

You could include delays in the interval to handle that. Probably in a similar way to how your script is working. Script prob sounds better though.

Hi Mahko!

Yes, a solution was not the reason for this thread. I wanted to find out more about events in esp home. But here is my current solution for a binary fan with asymmetric on/off interval. The current code has one remaining issue: After boot, when fan automation is restored as on, the first turn on command is lost. It may be solved with a higher on_boot priority. Or a more robust command queue in esp home.

esphome:
  name: cabinet
  friendly_name: Cabinet
  on_boot:
    - script.execute: fan_operate

esp32:
  board: esp32dev
  framework:
    type: arduino

number:
  - platform: template
    id: fan_on_min
    name: "Fan On Minutes"
    optimistic: true
    restore_value: true
    min_value: 5
    max_value: 240
    step: 5
    initial_value: 60
    icon: "mdi:timer"

  - platform: template
    id: fan_off_min
    name: "Fan Off Minutes"
    optimistic: true
    restore_value: true
    min_value: 5
    max_value: 240
    step: 5
    initial_value: 120
    icon: "mdi:timer"

script:
  - id: fan_operate
    mode: restart
    then:
      - while:
         condition:
          - lambda: "return true;"
         then:
          - if:
              condition:
                lambda: "return id(fan_auto).state;"
              then:
                - fan.turn_on: fan1
          - delay: !lambda "return id(fan_on_min).state * 60000.0;"
          - if:
              condition:
                lambda: "return id(fan_auto).state;"
              then:
                - fan.turn_off: fan1
          - delay: !lambda "return id(fan_off_min).state * 60000.0;"

binary_sensor:
  - platform: gpio
    name: "Fan Button"
    pin:
      number: GPIO18
      mode:
        input: true
        pullup: true
    filters:
      - invert:
      - delayed_on: 10ms
      - delayed_off: 10ms
    on_press:
      then:
        - fan.toggle: fan1

switch:
  - platform: template
    id: fan_auto
    name: "Fan Automation"
    optimistic: true
    icon: "mdi:fan-clock"
    restore_mode: RESTORE_DEFAULT_ON
    on_turn_on: 
      - script.execute: fan_operate

output:
  - platform: gpio
    id: gpio_fan
    pin: GPIO14

fan:
  - platform: binary
    id: fan1
    name: "Fan"
    output: gpio_fan

In my opinion it would be great if this script could be solved without any lambdas.

Many Greetings!
Remo

Well now we know;)

^^ That part you can replace with a switch condition if you prefer.

^^ This part I think needs to stay as a lambda if you want to be able to adjust it during operation.

^^ Not sure what this part is for?

Hi Mahko!

Thanks for the hint with the switch condition.

while (true) …
Is an endless loop. I was thinking about different solutions and I think this one has the least complexity.

Many Greetings!
Remo

1 Like

Oh of course…

^^ You might be able to replace this with this if you prefer. Not sure though.

    condition:
      - script.is_running: fan_operate

Hi Mahko!

While this might be technically working, I don’t like the circular reference it creates.

Many Greetings!
Remo

1 Like

Default restore_mode is ALWAYS_OFF which means - Always initialize the fan as OFF on bootup.

IMHO Initialize as OFF is not a same as turn it OFF. That is a reason of not calling on_turn_off.

I just realized that I got the boot priority the wrong way around. The final version works without quirks and probably the least amount of lambdas.

esphome:
  name: cabinet
  friendly_name: Cabinet
  on_boot:
    priority: 400
    then:
      - script.execute: fan_operate

esp32:
  board: esp32dev
  framework:
    type: arduino

number:
  - platform: template
    id: fan_on_min
    name: "Fan On Minutes"
    optimistic: true
    restore_value: true
    min_value: 5
    max_value: 240
    step: 5
    initial_value: 60
    icon: "mdi:timer"

  - platform: template
    id: fan_off_min
    name: "Fan Off Minutes"
    optimistic: true
    restore_value: true
    min_value: 5
    max_value: 240
    step: 5
    initial_value: 120
    icon: "mdi:timer"

script:
  - id: fan_operate
    mode: restart
    then:
      - while:
          condition:
            switch.is_on: fan_auto
          then:
            - fan.turn_on: fan1
            - delay: !lambda "return id(fan_on_min).state * 60000.0;"
            - if:
                condition:
                  switch.is_on: fan_auto
                then:
                  - fan.turn_off: fan1
                  - delay: !lambda "return id(fan_off_min).state * 60000.0;"

binary_sensor:
  - platform: gpio
    name: "Fan Button"
    pin:
      number: GPIO18
      mode:
        input: true
        pullup: true
    filters:
      - invert:
      - delayed_on: 10ms
      - delayed_off: 10ms
    on_press:
      then:
        - fan.toggle: fan1

switch:
  - platform: template
    id: fan_auto
    name: "Fan Automation"
    optimistic: true
    icon: "mdi:fan-clock"
    restore_mode: RESTORE_DEFAULT_ON
    on_turn_on: 
      - script.execute: fan_operate

output:
  - platform: gpio
    id: gpio_fan
    pin: GPIO14

fan:
  - platform: binary
    id: fan1
    name: "Fan"
    output: gpio_fan

Many Greetings!
Remo

1 Like