Using template generated list of device_id in action service

After long time searching I am out of ideas and maybe I found a bug…

I want to call the service set_temperature in an automation on multiple device_id as target. These device_ids are generated by a template. After many try-and-error I finally found a way to hand it over as a list. But the system still throws an error. Here my setup:

Using this macro:

{% macro get_devices_by_label_with_excludelist(get_label, exclude_list=[]) -%}
  {% set ns = namespace(devices=[]) -%}
  {% set ns.devices = label_devices(get_label) -%}
  {% for l in exclude_list -%}
    {% set ns.devices = ns.devices|reject('in', label_devices(l)|list) -%}
  {% endfor -%}
  {{ ns.devices|join(",") }}
{% endmacro -%}

I call the following automation (here only the important bit):

I use here ccd for the list of devices and cce for the list of entities within the devices. Why? I will explain later!

variables:
  get_label: heizgruppe
  exclude_list: 
    - badezimmer
  control_climate_devices: >
    {%- from 'labels.jinja' import get_devices_by_label_with_excludelist -%}
    {{ get_devices_by_label_with_excludelist(get_label, exclude_list) }}
  ccd: "{{ control_climate_devices.split(',') }}"
  cce: "{{ control_climate_devices.split(',') | map('device_entities') | sum(start=[])| select('is_state', 'heat')| sort }}"

Using ccd, the list of devices, is not working.

    sequence:
      - action: climate.set_temperature
        metadata: {}
        data:
          temperature: "{{ states('input_number.home_heizung_raum_tages_temperatur') }}"
        target:
          device_id: >-
            {{ ccd }}
        alias: Zieltemperatur für normale Räume setzen

Here is the trace output of the variables section:

control_climate_devices: >-
  0812835ce77e70e60c03844965660b3a,7d26100c74eb9381829a56dc2a47c532,255a2ded6783d3ff8ec07e51f14cbd1b,8962e94f57dadf53827ce9a9cfc37e27,f989416a8941e4d7d7950e6360570caf,ccdb9ac6389e71ab09392614addb1c49,2cd403863e80e27a566c27dbb1e4a9f1,fd375b022dec43f32157d1593e18fc4a,dce120ab088a86210330527dad12dcdb,bfa95343f68ad3acae9c931b7308fee5,785c77f29e23394d34df2d26bc0fa08e,528598e69db66c02bc34b7b4f9e046c4,b59d91a9a81e8345c7c2d5cd41f065b7,5533f71505a8ec1f951220a1d9f06019
ccd:
  - 0812835ce77e70e60c03844965660b3a
  - 7d26100c74eb9381829a56dc2a47c532
  - 255a2ded6783d3ff8ec07e51f14cbd1b
  - 8962e94f57dadf53827ce9a9cfc37e27
  - f989416a8941e4d7d7950e6360570caf
  - ccdb9ac6389e71ab09392614addb1c49
  - 2cd403863e80e27a566c27dbb1e4a9f1
  - fd375b022dec43f32157d1593e18fc4a
  - dce120ab088a86210330527dad12dcdb
  - bfa95343f68ad3acae9c931b7308fee5
  - 785c77f29e23394d34df2d26bc0fa08e
  - 528598e69db66c02bc34b7b4f9e046c4
  - b59d91a9a81e8345c7c2d5cd41f065b7
  - 5533f71505a8ec1f951220a1d9f06019
cce:
  - climate.home_eg_flur_heizgruppe
  - climate.home_eg_kueche_heizgruppe
  - climate.home_eg_wcgast_heizgruppe
  - climate.home_eg_zimmer1_heizgruppe
  - climate.home_eg_zimmer3_heizgruppe
  - climate.home_eg_zimmer4_heizgruppe
  - climate.home_eg_zimmer5_heizgruppe
  - climate.home_ug_flur_heizgruppe
  - climate.home_ug_zimmer1_heizgruppe
  - climate.home_ug_zimmer2_heizgruppe
  - climate.home_ug_zimmer3_heizgruppe
  - climate.home_ug_zimmer4_heizgruppe
  - climate.home_ug_zimmer5_heizgruppe

And here the error. You can see that the list is treated as a string.

Error: template value should be a string @ data['device_id'][0]
Result:

params:
  domain: climate
  service: set_temperature
  service_data:
    temperature: 21.5
    device_id:
      - - 0812835ce77e70e60c03844965660b3a
        - 7d26100c74eb9381829a56dc2a47c532
        - 255a2ded6783d3ff8ec07e51f14cbd1b
        - 8962e94f57dadf53827ce9a9cfc37e27
        - f989416a8941e4d7d7950e6360570caf
        - ccdb9ac6389e71ab09392614addb1c49
        - 2cd403863e80e27a566c27dbb1e4a9f1
        - fd375b022dec43f32157d1593e18fc4a
        - dce120ab088a86210330527dad12dcdb
        - bfa95343f68ad3acae9c931b7308fee5
        - 785c77f29e23394d34df2d26bc0fa08e
        - 528598e69db66c02bc34b7b4f9e046c4
        - b59d91a9a81e8345c7c2d5cd41f065b7
        - 5533f71505a8ec1f951220a1d9f06019

Using cce, the list of entity_ids, work fine. There is no error.

    sequence:
      - action: climate.set_temperature
        metadata: {}
        data:
          temperature: "{{ states('input_number.home_heizung_raum_tages_temperatur') }}"
        target:
          entity_id: >-
            {{ cce }}
        alias: Zieltemperatur für normale Räume setzen
Result:

params:
  domain: climate
  service: set_temperature
  service_data:
    temperature: 21.5
    entity_id:
      - climate.home_eg_flur_heizgruppe
      - climate.home_eg_kueche_heizgruppe
      - climate.home_eg_wcgast_heizgruppe
      - climate.home_eg_zimmer1_heizgruppe
      - climate.home_eg_zimmer3_heizgruppe
      - climate.home_eg_zimmer4_heizgruppe
      - climate.home_eg_zimmer5_heizgruppe
      - climate.home_ug_flur_heizgruppe
      - climate.home_ug_zimmer1_heizgruppe
      - climate.home_ug_zimmer2_heizgruppe
      - climate.home_ug_zimmer3_heizgruppe
      - climate.home_ug_zimmer4_heizgruppe
      - climate.home_ug_zimmer5_heizgruppe

I have checked multiple times using the UI with non-template hard coded devices such as the following example:

action: climate.set_temperature
data:
  temperature: 21.5
enabled: true
target:
  device_id:
    - 4c8aa5317f7c3a7dfb397ddd4b89b101
    - 785c77f29e23394d34df2d26bc0fa08e

Either I do sonething wrong when I use device_id or there is a bug. Anyone suggestions or can spot my mistake?

Try:

target: "{{ {'device_id': ccd } }}"

Hi voco,

Device_id’s were designed with the intention that they would be used with the UI automation stuff and were not meant to duplicate the functions already there with entity_id’s. Therefore most template functions do not work with device_id’s. If you look in the docs, if it doesn’t specifically say it applies to device_id’s, then the template function will not work and is designed that way. This means not a bug, but working as designed.

Therefore if you are manually writing YAML, it is strongly advised to use entity_id’s to affect the world.

Besides, if you are human, looking at this and trying to make sense of it is nonsensical:

As opposed to this:

Why and how to avoid device_ids in automations and scripts.

In theory, what you did with ccd for device_id should have worked but it appears that Home Assistant handles it differently than cce for entity_id.

Look carefully at the value of device_id, specifically the first line. See the leading double hyphens?

That’s YAML syntax for a list containing a list of strings (as opposed to merely a list of strings). The list contains just one item and its value is a list of strings.

As an experiment, try this:

  target:
    device_id: '{{ ccd[0] }}'

Let us know what the trace reports for that template’s result.

Thanks for your reply.
I understand your point and also read the guide.

I’m my case I am using the UI editor but since I have to use a template in the action, the visual editor cannot be used and switches to yaml. As you can see in the variables section, the devices are generated by the template hence your argument about readability does not apply
In addition, using labels is great but it is not scaling at most situations with entities but is great with devices since there are less devices and as a user it is the better way / closer to what I have in my hands - a device has multiple entities and all of them belong to the lable I am attaching to it.

Reading the guide again, the most important point would be the option to filter for unavailable but this should not be a reason to treat them differently from an developer point of view. It is confusing (to me) that I have not the same options to apply a list to the target. Why should I not be able to apply a list of devices to a target by a template but I can do that with entities. And be aware that “handwriting” a list of devices is possible.

Last, I have not tried to use a list of areas or labels generated by a template to a target. I am afraid that this also might be not possible / handled different compared to entities.
This does not really make sense.

Yes, this works. I guess by using this line you prevent some internal check of the device_id property.

Both suggestions work fine and result in a proper list or single item list.

  target:
    device_id:
      - 0812835ce77e70e60c03844965660b3a
      - 7d26100c74eb9381829a56dc2a47c532
      - 255a2ded6783d3ff8ec07e51f14cbd1b
      - 8962e94f57dadf53827ce9a9cfc37e27
      - f989416a8941e4d7d7950e6360570caf
      - ccdb9ac6389e71ab09392614addb1c49
      - 2cd403863e80e27a566c27dbb1e4a9f1
      - fd375b022dec43f32157d1593e18fc4a
      - 4c8aa5317f7c3a7dfb397ddd4b89b101
      - dce120ab088a86210330527dad12dcdb
      - bfa95343f68ad3acae9c931b7308fee5
      - 785c77f29e23394d34df2d26bc0fa08e
      - 528598e69db66c02bc34b7b4f9e046c4
      - b59d91a9a81e8345c7c2d5cd41f065b7
      - 5533f71505a8ec1f951220a1d9f06019

or

  target:
    device_id:
      - 0812835ce77e70e60c03844965660b3a

For anyone running into the same problem or even just wanting to use a template generated list of entities / devices or else as a target, here are the solutions:

  1. As of now, in this special case, if you want to use a template generated device list as a target, you need to use the solution posted earlier.
target: "{{ {'device_id': ccd } }}"
  1. Since I wanted to get my automation done, I did not want to assign a lable to each entity (I rather work with devices since these are less), I filtered the devices for the entity to control. This is basically what I did.

Created a macro, but you can also just use the code inside the automation directly. This macro is not necessary for anyone not needing to exclude from the device list.

{#
  Get devices by one label and exlude the ones that devices in areas of the
  exclude list
#}
{% macro get_devices_by_label_exclude_areas(get_label, exclude_list=[]) -%}
  {% set ns = namespace(devices=[]) -%}
  {% set ns.devices = label_devices(get_label) -%}
  {% for l in exclude_list -%}
    {% set ns.devices = ns.devices|reject('in', area_devices(l)|list) -%}
  {% endfor -%}
  {{ ns.devices|join(",") }}
{% endmacro -%}

Created a variable section in the automation and used the variable climate_entity_list in the action.

  label_get: heizgruppe
  area_exclude_list:
    - ug_badezimmer
  climate_devices: >
    {%- from 'labels.jinja' import get_devices_by_label_exclude_areas -%} {{
    get_devices_by_label_exclude_areas(label_get, area_exclude_list) }}
  climate_device_list: "{{ climate_devices.split(',') }}"
  climate_entity_list: >-
    {{ climate_devices.split(',') | map('device_entities') | sum(start=[])|
    select('match', 'climate')| sort }}

If you’re using what Troon suggested, please mark Troon’s post with the Solution tag (not your own post which merely reiterates his suggestion). That’s how the Solution tag is meant to be used.

Otherwise, it looks like everyone ultimately answers/solves their own question/problem.

For more information, refer to the community’s FAQ (notably guideline #21).


FWIW, for the longest time I have thought that the discrepancy between how templated lists are handled by the entity_id and device_id options is a bug. I don’t see the reason why device_id chooses to make the template’s list a member of yet another list. It should handle it the way entity_id does.