Pass multiple entities or devices in templated if statement

Hi all

I’m trying to pass multiple entities or devices to the light.turn_on service depending on certain conditions but I am scratching my head to find the correct format because having more than one entity/device is throwing errors no matter how I’ve tried to format those list entries. Below is an example but I have tried various ways but nothing is working for me.

games_room_ceiling_on:
  sequence:
    - service: light.turn_on
      data:
        transition: 5
        brightness_pct: 100
      target:
        device_id: >
          {% if is_state('media_player.games_room_tv' , 'on') and (states.sensor.time.state < '17:00') %} 
            - cd9669400b2545458f02bc2806b203cb
            - 530e62a916114e98b95f10ce93ee9b27
          {% elif is_state('media_player.games_room_tv' , 'off') and (states.sensor.time.state < '17:00') %} cd9669400b2545458f02bc2806b203cb
          {% elif is_state('media_player.games_room_tv' , 'off') %} c3aeb277056c4c398b6d06a9dcb7dd64
          {% endif %}

Am I just going about this the wrong way or how would I correctly format a list of entries under each condition?

Thanks.

1 Like
games_room_ceiling_on:
  sequence:
    - service: light.turn_on
      data:
        transition: 5
        brightness_pct: 100
      target:
        device_id: >
          {% set tv_on = is_state('media_player.games_room_tv', 'on') %}
          {% if tv_on and now().hour < 17 %} ['cd9669400b2545458f02bc2806b203cb', '530e62a916114e98b95f10ce93ee9b27']
          {% elif not tv_on and now().hour < 17 %} cd9669400b2545458f02bc2806b203cb
          {% elif not tv_on %} c3aeb277056c4c398b6d06a9dcb7dd64
          {% endif %}

NOTE

You need to improve the template’s logic because it contains gaps. For example, if the tv is on but it’s after 17:00 the template will report nothing and that’s not an acceptable value for device_id.

Thanks for the input but I’m still having trouble with getting more than one device controlled under a single statement.

Trying your suggestion I receive the following:

2022-10-01 15:16:16.336 ERROR (MainThread) [homeassistant.components.script.games_room_ceiling_on] games_room_ceiling_on: Error executing script. Invalid data for call_service at pos 1: template value should be a string @ data['device_id'][0]
2022-10-01 15:16:16.340 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 451, in _async_run
    return await self.script.async_run(script_vars, context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1513, in async_run
    await asyncio.shield(run.async_run())
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 405, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 449, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 472, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 447, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 680, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1692, in async_call
    processed_data: dict[str, Any] = handler.schema(service_data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 232, in __call__
    return self._exec((Schema(val) for val in self.validators), v)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 355, in _exec
    raise e if self.msg is None else AllInvalid(self.msg, path=path)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 351, in _exec
    v = func(v)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 229, in _run
    return self._exec(self._compiled, value, path)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 355, in _exec
    raise e if self.msg is None else AllInvalid(self.msg, path=path)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/validators.py", line 353, in _exec
    v = func(path, v)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
  File "/usr/local/lib/python3.10/site-packages/voluptuous/schema_builder.py", line 433, in validate_mapping
    raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: template value should be a string @ data['device_id'][0]

It works fine if I pass a single device id so I am still stumoed as to how I can pass more that one device at a time.

This format isn’t working for me unfortunately :cry:

['cd9669400b2545458f02bc2806b203cb', '530e62a916114e98b95f10ce93ee9b27']

Device doesn’t support multiple. Have to iterate them or use entity_ids.

        entity_id: >
          {% set tv_on = is_state('media_player.games_room_tv', 'on') %}
          {% if tv_on and now().hour < 17 %} 
            {% set devices = ['cd9669400b2545458f02bc2806b203cb', '530e62a916114e98b95f10ce93ee9b27'] %}
          {% elif not tv_on and now().hour < 17 %}
             {% set devices = ['cd9669400b2545458f02bc2806b203cb'] %}
          {% elif not tv_on %}
             {% set devices = ['c3aeb277056c4c398b6d06a9dcb7dd64'] %}
          {% endif %}
          {{ expand(device_entities(devices)) | selectattr('domain', 'eq', 'light') | map(attribute='entity_id') | list }}

My mistake; I didn’t know device_id doesn’t support multiple values (FWIW, I never reference an entity via its device_id).

Why not just reference the light entities directly via their entity_id?

games_room_ceiling_on:
  sequence:
    - service: light.turn_on
      data:
        transition: 5
        brightness_pct: 100
      target:
        entity_id: >
          {% set tv_on = is_state('media_player.games_room_tv', 'on') %}
          {% if tv_on and now().hour < 17 %} ['light.first', 'light.second']
          {% elif not tv_on and now().hour < 17 %} light.first
          {% elif not tv_on %} light.third
          {% endif %}

Replace light.first, light.second, and light.third with the entity_id of the actual three lights you have.

Thanks so much guys. I will go with entity ids as it keeps things simpler and easier to read.

I just could not find the correct format anywhere I looked. But once you know, you know :smiley:

I was able to use my original logic and it works fine for what I want to achieve. ['entity_id', 'entity_id'] allows me to expand on my scripts and automations quite a bit so should keep me busy for a while.

          {% if is_state('media_player.games_room_tv' , 'on') and (states.sensor.time.state < '17:00') %} ['light.games_room_1', 'light.games_room_5']
          {% elif is_state('media_player.games_room_tv' , 'off') and (states.sensor.time.state < '17:00') %} light.games_room_4
          {% elif is_state('media_player.games_room_tv' , 'off') %} light.games_room_6
          {% endif %}

Thanks again.

There’s no need to reference sensor.time in the template because now() serves the same purpose (and is more concise). Also, consider using a variable in order to avoid calling is_state multiple times (and it also makes the template more concise).

        entity_id: >
          {% set tv_on = is_state('media_player.games_room_tv', 'on') %}
          {% if tv_on and now().hour < 17 %} ['light.games_room_1', 'light.games_room_5']
          {% elif not tv_on and now().hour < 17 %} light.games_room_4
          {% elif not tv_on %} light.games_room_6
          {% endif %}

Don’t forget that there’s still a gap in the template’s logic; it should be corrected to prevent a potential runtime error.

That makes sense as I will definitely expand on the above and cover as many conditions as possible so saves repeating the device state. Setting the variable is probably better practice to get into the habit of also.

Much appreciated.