[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

1 Like

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
5 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…

@gastonche and @Tarkoon, apologies I did not reply before - not notified of further posts to this.

Not sure if you have solved this but for future info.

As navigate is a function of the button actions (and you can only have 1 action on a button - exactly why this script got created), this needs a little bit of a workaround.

You will need to install browser mod as this creates a service that you can call to navigate to a page in your browser.

Modify the multi_tap_action script to be this:

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: >-
              {% set b =  {"browser_id": browser_id} if
              browser_id is defined and "browser_mod" in repeat.item.service else {} %} {{ dict(
              repeat.item.data, **b) }}
        - 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: >-
              {% set b =  {"browser_id": browser_id} if
              browser_id is defined and "browser_mod" in repeat.item.service else {} %} {{ dict(
              repeat.item.data, **b) }}
mode: parallel

and then on your button use like this (I have used the previous example showing all scenarios and now adding the navigate with browser_mod scenario. Note the button tap_action must be fire-dom-event and you must include the browser_id: THIS under data.

One caveat of this is that is basically uses browser mod to navigate to the page on the device you have clicked the button on. However, all browser windows that have HA on them on that device will navigate to your lovelace view, not just the one you are currently viewing.

type: button
tap_action:
  action: fire-dom-event
  browser_mod:
    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
        - service: browser_mod.navigate
          data:
            path: /lovelace/lounge
      browser_id: THIS
entity: sun.sun
show_name: true
show_icon: true

Hope that helps.

Hi,
I’m a new to scripts.
When I attempt to call the script multi tap action, I get the following error:

Logger: homeassistant.components.script.multi_tap_action
Source: helpers/script.py:1934
integration: Script (documentation, issues)
First occurred: 6:11:56 PM (2 occurrences)
Last logged: 6:11:59 PM

Multi Tap Action: Repeat ‘for_each’ must be a list of items in Multi Tap Action, got:


I'm calling it via:
                - element: shark.clean_den
                  entity:
                    - input_text.cleaning_living_area
                  tap_action:
                    action: call-service
                    service: script.multi_tap_action
                    data:
                      actions:
                        - service: sharkiq.clean_room
                          entity_id: vacuum.kitchen
                          data:
                            rooms: Den
                        - service: input_text.set_value
                          entity_id: input_text.cleaning_living_area
                          data:
                            value: den

I figured out my issue, you have to change “data” to “service_data”

I guess, scripting has changed in the last coupe of months:

The following works for me:

                - element: shark.clean_den
                  entity:
                    - input_text.cleaning_living_area
                  tap_action:
                    action: call-service
                    service: script.multi_tap_action
                    service_data:
                      actions:
                        - service: sharkiq.clean_room
                          entity_id: vacuum.kitchen
                          data:
                            rooms: Den
                        - service: input_text.set_value
                          entity_id: input_text.cleaning_living_area
                          data:
                            value: den
                    target: {}

Hello

I’ve tried to use this automation, but I ran into some problems:
here is the automation copied from above:

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: >-
              {% set b =  {"browser_id": browser_id} if browser_id is defined
              and "browser_mod" in repeat.item.service else {} %} {{ dict(
              repeat.item.data, **b) }}
        - 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: >-
              {% set b =  {"browser_id": browser_id} if browser_id is defined
              and "browser_mod" in repeat.item.service else {} %} {{ dict(
              repeat.item.data, **b) }}
mode: parallel
show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: script.multi_tap_action
  target: {}
  service_data:
    actions:
      - service: input_number.set
        entity_id: input_number.teste_number_1
        data:
          variable:
            value: 30
      - service: input_number.set
        entity_id: input_number.teste_number_2
        data:
          variable:
            value: 30
entity: script.multi_tap_action
show_state: true

I’ve tried several ways:

      - service: input_number.set
        entity_id: input_number.teste_number_1
        data:
          value: 30
      - service: input_number.set
        entity_id: input_number.teste_number_1
        data:
          variables:
             value: 30
      - service: input_number.set
        entity_id: input_number.teste_number_1
        data: 30
  action: call-service
  service: script.multi_tap_action
  target: {}
  data:

and got lots of errors:

Failed to call service script/multi_tap_action. extra keys not allowed @ data[‘value’]
Failed to call service script/multi_tap_action. extra keys not allowed @ data[‘variable’]
Service input_number.set called service script.multi_tap_action which was not found.
Failed to call service script/multi_tap_action. Error rendering data template: Result is not a Dictionary
Service input_number.set called service script.multi_tap_action which was not found.

Hope someone that can help is still watching and thanks in advance