[PoC] Multiple actions on tap action

I sometimes want to do multiple actions from one frontend button. I searched for it, multiple threads (1, 2, 3, 4, 5, 6, 7, 8 and even a PR by thomasloven), but the only option was to build an script for each set of actions. I don’t like that clutter :sweat_smile:

So, here’s my Proof of Concept approach.

1. ONE generic script for all
Right now it’s very basic, it only supports up to 3 actions, and limited to services with one entity.

alias: Convert to actions
sequence:
  - service: "{{ service1 }}"
    data:
      entity_id: "{{ entity_id1 }}"
  - if:
      - condition: template
        value_template: "{{ service2 is defined }}"
    then:
      - service: "{{ service2 }}"
        data:
          entity_id: "{{ entity_id2 }}"
  - if:
      - condition: template
        value_template: "{{ service3 is defined }}"
    then:
      - service: "{{ service3 }}"
        data:
          entity_id: "{{ entity_id3 }}"
mode: single

I think it can easily be expanded to support other service data other than entity_id

What I’m not so sure about is how to support other actions. Since it does go through a script, I guess it is limited to certain things. But

I’m also not sure if it should be parallel instead of sequential, or what happens with the next if the previous fails. For now it’s enough for me.

2. The tap_action in the front-end
We are passing each service and entity_id as service data to the script

tap_action:
  action: call-service
  service: script.convert_to_action
  service_data:
    service1: fan.turn_off
    entity_id1: fan.ventilador_habitacion
    service2: scene.turn_on
    entity_id2: scene.ventilador_habitacion_off

Happy to know your thoughts and improvements!

Reference links:
Multiple actions on tap
Way to call multiple actions from button?
Possible to trigger multiple actions with a single tap on the button card?
How to add two (or more) actions to a single Button-card?
How to perform multiple actions
Having two tap_actions within one button
One button with two actions
Picture-elements card: Multipe actions/services on tap_action
Allow multiple tap/hold/doubletap actions. by thomasloven · Pull Request #8125 · home-assistant/frontend · GitHub

How about passing a list of actions with possibility of different params then you are not limited to number of actions and can call different service types. Example below only shows 2 service param types but more could be added.

alias: Multi Tap Action
sequence:
  - repeat:
      for_each: "{{actions}}"
      sequence:
        - if:
            - condition: template
              value_template: "{{repeat.item.entity_id is defined}}"
          then:
            - service: "{{repeat.item.service}}"
              data:
                entity_id: "{{repeat.item.entity_id}}"
        - if:
            - condition: template
              value_template: "{{repeat.item.message is defined}}"
          then:
            - service: "{{repeat.item.service}}"
              data:
                message: "{{repeat.item.message}}"
mode: parallel

The use like this.

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: script.multi_tap_action
  service_data:
    actions:
      - service: light.turn_on
        entity_id: light.lounge_lamps
      - service: notify.persistent_notification
        message: Lounge lamps on
entity: sun.sun
1 Like

Wow, thank you for building on this. It works great, and as you said can be expanded based on one’s needs.

I like it. What about if you need to include service data?

e.g.

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: script.multi_tap_action
  service_data:
    actions:
      - service: light.turn_on
        entity_id: light.lounge_lamps
        data:
          brightness: 255
          hs_color: [0,100]
      - service: notify.persistent_notification
        message: Lounge lamps on bright red
entity: sun.sun

Yes, I was thinking about that and actually, I think it can be much simpler (as I think all services accept the entity id in data??)

Script

alias: Multi Tap Action
sequence:
  - repeat:
      for_each: "{{actions}}"
      sequence:
          service: "{{repeat.item.service}}"
          data: "{{repeat.item.data}}"
mode: parallel

Button

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: script.multi_tap_action
  data:
    actions:
      - service: light.turn_on
        data:
          entity_id: light.lounge_lamps
          brightness_pct: 53
      - service: notify.persistent_notification
        data:
          message: Lounge lamps on
  target: {}
entity: sun.sun

Yes… but no.

Yes they should accept an entity id in the data block for backwards compatibility, but no that is not always the case. In fact there have been examples where a service does not work at all with the entity_id in the data block. I’ll see if I can find an example, but they were all from quite a while ago. They may have been fixed.

Ideally we should be using

target:
  entity_id: domain.object_id

That always works.

Ah ok, then we should go for the higher certainty. I think then there are 4 scenarios for a service call.

  1. Without entity or data
  2. With only entity
  3. With only data
  4. With entity and data

As such, maybe this is the script…

alias: Multi Tap Action
sequence:
  - repeat:
      for_each: "{{actions}}"
      sequence:
        - if:
          - condition: template
            value_template: "{{repeat.item.entity_id is not defined and repeat.item.data is not defined }}"
          then:
            service: "{{ repeat.item.service }}"
        - if:
          - condition: template
            value_template: "{{repeat.item.entity_id is defined and repeat.item.data is not defined }}"
          then:
            service: "{{ repeat.item.service }}"
            target: 
              entity_id: "{{repeat.item.entity_id}}"
        - if:
          - condition: template
            value_template: "{{repeat.item.entity_id is not defined and repeat.item.data is defined }}"
          then:
            service: "{{ repeat.item.service }}"
            data: "{{ repeat.item.data }}"
        - if:
          - condition: template
            value_template: "{{repeat.item.entity_id is defined and repeat.item.data is defined }}"
          then:
            service: "{{ repeat.item.service }}"
            target: 
              entity_id: "{{repeat.item.entity_id}}"
            data: "{{ repeat.item.data }}"
mode: parallel

4 examples to show (what I think!?) is all combinations.

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: script.multi_tap_action
  data:
    actions:
      - service: frontend.reload_themes
      - service: switch.turn_off
        entity_id: switch.bedroom_lamps
      - service: notify.persistent_notification
        data:
          message: Lounge lamps on
      - service: light.turn_on
        entity_id: light.lounge_lamps
        data:
          brightness_pct: 53
  target: {}
entity: sun.sun
2 Likes

I have a scenario where I need to pause between calling the first service and the second. I added the following after the 4 conditions:

        - if:
            - condition: template
              value_template: "{{repeat.item.wait is defined}}"
          then:
            - delay:
                hours: 0
                minutes: 0
                seconds: 0
                milliseconds: "{{repeat.item.wait | float}}"
1 Like

Hello, excellent script!!! It works perfect for running multiservices. Any ideas to navigate?

service1: switch.turn_on
service2: navigate
url_path:“/lovelace/…”

thanks

1 Like

That is exactly what I would need too!
I navigate to a sub dashboard with a tap_action, showing camera snapshots with the ability to browse through them. I would love so much being able to reset the chosen snapshot to the newest one in the same tap_action that navigates to the sub dashboard.
Currently I always need to take a separate action like double click to reset…