[Helper Script] Call various services on multiple entities in data templates

Hi, I am not sure if there is a more elegant way in achieving this, however I thought this might be useful for others too.
This script reduces coding overhead when writing automations. If you wish to call multiple services on multiple entities under particular conditions in an automation you can use this script.

For example: My presence detection automation is triggered on status change. Depending on the status I wish to execute various operations: e.g. when I leave, all my lights and my media player should be switched off, thus requiring multiple services and potentially multiple entities to be iterated.
Also, when I arrive I want certain lights to switch on and have a particular scene activated.

I did not find a way to pass multiple entities and services to multiline data_templates using multiple services.

The script works by separating service calls on entities by commas “,” and separating individual entities by vertical bars “|” . The first element defines the service to be called e.g.
homeassistant.turn_on al following elements are entities , all elements are separated by a “|” to call another service use a comma.

Have a look at the example that makes it more clear.

With this script all can be handled in a single easily readable automation:

Let me know if you find this useful, or if there is a more elegant way in achieving what I wanted to do.

Data format:

service1|entityA|entityB|entityC,
service2|entityX|entityY|entityZ

Here the automation code:

- alias: Tom presence status change
  trigger:
- platform: state
  entity_id: sensor.sensor_presence_tom
  action:
- service: notify.notify_tom_telegram
  data_template:
    message: > 
      Toms status has changed to "{{ states.sensor.sensor_presence_tom.state }}"  
- service: python_script.python_script_call_service_on_multiple_entities
  data_template:
    operations: >
      {% set topic = states.sensor.sensor_presence_tom.state %}
      {% if topic == 'Fort' %}
        media_player.media_stop|media_player.spotify,
        light.turn_off|group.all_lights|group.all_switches
      {% elif topic == 'Gerade angekommen' %}          
        scene.turn_on|scene.comfortable|test,
        homeassistant.turn_on|group.office
        scene.turn_on|scene.comfortable
      {% else %}
      {% endif %}

This is the script:
#==================================================================================================
# python_scripts/python_script_call_service_on_multiple_entities.py
#==================================================================================================

#--------------------------------------------------------------------------------------------------
# Call multiple services on multiple entities in an automation template
# currently does not support additional payload such as color information or brightness
#--------------------------------------------------------------------------------------------------

"""
Data format: service1|entityA|entityB|entityC,
            service2|entityX|entityY|entityZ

Example Usage: 
    - service: python_script.python_script_call_service_on_multiple_entities
      data_template:
        operations: >
          {% set topic = states.sensor.sensor_presence_tom.state %}
          {% if topic == 'Fort' %}
            media_player.media_stop|media_player.spotify,
            light.turn_off|group.all_lights|group.all_switches
          {% elif topic == 'Gerade angekommen' %}          
            scene.turn_on|scene.comfortable|test,
            homeassistant.turn_on|group.office
            scene.turn_on|scene.comfortable
          {% else %}
          {% endif %}
"""


operations = data.get('operations')
if not operations:
    logger.debug("Error, wrong data format or empty.")
else:
    logger.debug("tasks {0} end".format(operations))  
    tasks = operations.replace("\n","").replace(" ","").split(",")
    
    for task in tasks:
      logger.warning("tasks {0}".format(tasks)) 
      data = task.split("|")
      operation = data[0].split(".")
      service = operation[0]
      action = operation[1]
      if hass.services.has_service(service,action):
        for entity in data[1:]:
          if hass.states.get(entity) is not None:
            logger.debug("Calling {0}.{1} on Entity {2}".format(service,action,entity))
            hass.services.call(service, action, {"entity_id" : entity}, False)
          else:
            logger.warning("Could not find entity \"{0}\"".format(entity))
      else:
        logger.warning("Error: Service \"{0}\" not found".format(service))
3 Likes

I have no clue about the technical merits of your code, but part of why I love this community is the contribution and innovation. Bravo.

nice solution, gonna test this for some of my automations.

@lihuuhloi did you in the meantime make any updates to your python script? what’s your experience so far?

Thanks for this, I’ve been struggling with the syntax to do this properly for hours, this script fixed it right up! Seems like it shouldn’t be necessary, but I guess it is.

Great to know that this is actually helping some people :slight_smile: after all this while. I too was amazed that this is not possible in HA natively.

So far I did not make any further tweaks to the script, as this has been sufficient for me. However, one could always think of making it possible to add different options per entity but I think it might make the syntax more complicated.

So far it has been working great for me: Basically it was install and forget :slight_smile: