Button press does not wait until finished / Delay not working

The problem

I have the following definition for 2 buttons

button:
  - platform: template
    entity_category: config
    name: "[A] Select"
    icon: mdi:button-pointer
    id: btn_select
    on_press:
      - lambda: |-
          id(select_pin).pin_mode(gpio::FLAG_OUTPUT);
      - output.turn_on: select_io
      - delay: ${pulse_length}
      - output.turn_off: select_io
      - delay: ${button_press_delay}
      - lambda: |-
          id(select_pin).pin_mode(gpio::FLAG_INPUT);
      - logger.log: "~~~ SELECT ~~~"
      
  - platform: template
    entity_category: config
    name: "[B] Set"
    icon: mdi:button-pointer
    id: btn_set
    on_press:
      - lambda: |-
          id(set_pin).pin_mode(gpio::FLAG_OUTPUT);      
      - output.turn_on: set_io
      - delay: ${pulse_length}
      - output.turn_off: set_io
      - delay: ${button_press_delay}
      - lambda: |-
          id(set_pin).pin_mode(gpio::FLAG_INPUT);
      - logger.log: "~~~ SET ~~~"

The delay function works accordingly and I see the logger output with the expected delay
Having debug loggin enabled I also see a message for the button press.

Example:

10:23:59 | [D] | [button:010] | '[A] Select' Pressed.
10:24:00 | [D] | [main:093] | ~~~ SELECT ~~~

Now I want to automate a button sequence a startup. A delay between the button presses is CRUCIAL!
And in my mind, I have the delay built into the button action.
However when running the boot code:

esphome: 
  on_boot:
    priority: -100.0
    then:
      - delay: 2s # ensure BBGone is up and running and accepting the buttons
      - repeat:
          count: 2
          then:
            - button.press: btn_select            
      - button.press: btn_set
      - repeat:
          count: 8
          then:
            - button.press: btn_mode
      - button.press: btn_set

I see things like:

10:23:59 | [D] | [button:010] | '[A] Select' Pressed.
10:23:59 | [D] | [button:010] | '[A] Select' Pressed.
10:24:00 | [D] | [main:093] | ~~~ SELECT ~~~
10:24:00 | [D] | [main:093] | ~~~ SELECT ~~~

Indicating that '- button.press: btn_select ’ does not wait until finished, but exectutes the next line immediately.
That leads to 2 (!) button presses started and the with the delay both finish!

This on the other hand works:

esphome: 
  on_boot:
    priority: -100.0
    then:
      - delay: 2s # ensure BBGone is up and running and accepting the buttons
      - repeat:
          count: 2
          then:
            - button.press: btn_select            
            - delay: ${button_press_delay}
      - button.press: btn_set
      - delay: ${button_press_delay}
      - repeat:
          count: 8
          then:
            - button.press: btn_mode
            - delay: ${button_press_delay}
      - button.press: btn_set
      - delay: ${button_press_delay}

While I could remove the delay from the button itself and keep it in the automation, how can I solve this:

select:
  - platform: template
    name: "Day/Night Mode"
    id: day_night_mode
    icon: mdi:lightbulb-on-50
    options:
     - "All Day"
     - "Daytime Only"
     - "Nighttime Only"
    restore_value: true
    initial_option: "Daytime Only"
    optimistic: true
    set_action:
      - lambda: |-
          ESP_LOGD("custom", "Global: %s / Requested: %s", id(glb_day_night_mode).c_str(), x.c_str());
          if (strcmp(id(glb_day_night_mode).c_str(), "Daytime Only") == 0) {
            ESP_LOGD("custom", "Daytime Only");
            if (strcmp(x.c_str(), "All Day") == 0) {
              id(btn_select).press(); // Daytime
              id(btn_select).press(); //Nighttime
              id(btn_select).press(); //All
              id(btn_set).press();
              ESP_LOGD("custom", "Setting All Day");
            }
            if (strcmp(x.c_str(), "Nighttime Only") == 0) {
              id(btn_select).press(); // Daytime
              id(btn_select).press(); //Nighttime
              id(btn_set).press();
              ESP_LOGD("custom", "Setting Nighttime Only");
            }
            if (strcmp(x.c_str(), "Daytime Only") == 0) {
              ESP_LOGD("custom", "Setting Daytime Only");
            }
            id(glb_day_night_mode) = x.c_str();
          } else if  (strcmp(id(glb_day_night_mode).c_str(), "Nighttime Only") == 0) {
            ESP_LOGD("custom", "Nighttime Only");
            if (strcmp(x.c_str(), "All Day") == 0) {
              id(btn_select).press(); //Nighttime
              id(btn_select).press(); //All
              id(btn_set).press();
              ESP_LOGD("custom", "Setting All Day");
            }
            if (strcmp(x.c_str(), "Nighttime Only") == 0) {
              ESP_LOGD("custom", "Setting Nighttime Only");
            }
            if (strcmp(x.c_str(), "Daytime Only") == 0) {
              id(btn_select).press(); //Nighttime
              id(btn_select).press(); //All
              id(btn_select).press(); // Daytime
              id(btn_set).press();
              ESP_LOGD("custom", "Setting Daytime Only");
            }
            id(glb_day_night_mode) = x.c_str();
          } else if  (strcmp(id(glb_day_night_mode).c_str(), "All Day") == 0) {
            ESP_LOGD("custom", "All Day");
            if (strcmp(x.c_str(), "All Day") == 0) {
              ESP_LOGD("custom", "Setting All Day");
            }
            if (strcmp(x.c_str(), "Nighttime Only") == 0) {
              id(btn_select).press(); //All
              id(btn_select).press(); // Daytime
              id(btn_select).press(); //Nighttime
              id(btn_set).press();
              ESP_LOGD("custom", "Setting Nighttime Only");
            }
            if (strcmp(x.c_str(), "Daytime Only") == 0) {
              id(btn_select).press(); //All
              id(btn_select).press(); // Daytime
              id(btn_set).press();
              ESP_LOGD("custom", "Setting Daytime Only");
            }
            id(glb_day_night_mode) = x.c_str();
          }

I need a delay between the individual button presses!
I know I can do that without lambda, but how can I handle the whole select without lambda?

I my mind, this is a bug, but maybe it is intentional?!
If it is designed to not wait for ‘.press()’ to finish then how to add delay?

Hope this all makes sense

Which version of ESPHome has the issue?

latest

What type of installation are you using?

Home Assistant Add-on

Which version of Home Assistant has the issue?

latest

What platform are you using?

ESP32

Not a bug.

delay: is non blocking. So when you call the button_press: outside of the action inside the button, it doesn’t wait for the action to complete. It just does it again.

Putting the delay between the calls to button_press: (your final example) is the only way delay will produce the desired effect.

Maybe you could look at moving your logic from a button to a script?

Scripts are quite flexible. You can wait for a script, stop them and call them from a lambda etc.