Template produces error: expected int for dictionary value @ data['segments']

I’m trying to run a template script but somehow the output produces an error that I cannot fix:

I have a set of input_boolean helpers that store, which room needs to be cleaned. In a script I would like to call a service to have the vacuum clean these rooms. The input_boolean are kept in a group and I use the following template:

{% set rooms = expand(['group.cleaning_rooms']) | selectattr('state','eq','on') | map(attribute='entity_id') | list %}
{%  set mapper = {
  'input_boolean.clean_dining_area' : 20,
  'input_boolean.clean_bedroom' : 17,
  'input_boolean.clean_master_bath' : 16,
  'input_boolean.clean_living_room' : 18,
  'input_boolean.clean_kids_room' : 21,
  'input_boolean.clean_study' : 19,
  'input_boolean.clean_corridor' : 22,
  'input_boolean.clean_guest_toilet' : 4
  } %}
{% for room in rooms if room in mapper %}
  - {{ mapper[room] }}
{% endfor %}

I have set the bedroom to be cleaned, and in the developer tools, this produces the following output:

  - 17

Now I’ve put this into a script:

alias: Start vacuum room cleaning
sequence:
  - service: xiaomi_miio.vacuum_clean_segment
    data_template:
      entity_id: vacuum.xiaomi_vacuum_cleaner
      segments: >
        {% set rooms = expand(['group.cleaning_rooms']) | selectattr('state','eq','on') | map(attribute='entity_id') | list %}
        {%  set mapper = {
          'input_boolean.clean_dining_area' : 20,
          'input_boolean.clean_bedroom' : 17,
          'input_boolean.clean_master_bath' : 16,
          'input_boolean.clean_living_room' : 18,
          'input_boolean.clean_kids_room' : 21,
          'input_boolean.clean_study' : 19,
          'input_boolean.clean_corridor' : 22,
          'input_boolean.clean_guest_toilet' : 4
        } %}
        {% for room in rooms if room in mapper %}
        - {{ mapper[room] }}
        {% endfor %}      
mode: single
icon: 'mdi:play'

Now I get the following error:

Failed to call service script/start_vacuum_room_cleaning. expected int for dictionary value @ data[‘segments’]

When I call the service in the developer tools with data like this, it works:

entity_id: vacuum.xiaomi_vacuum_cleaner
segments:
  - 17

Any hints what I’m doing wrong?

One other observation: toggeling in the interface from UI to YAML mode changes the formatting drastically. Is this really the same?

alias: Start vacuum room cleaning
sequence:
  - service: xiaomi_miio.vacuum_clean_segment
    data_template:
      entity_id: vacuum.xiaomi_vacuum_cleaner
      segments: |
        {% set rooms = expand(['group.cleaning_rooms']) |
         selectattr('state','eq','on') | map(attribute='entity_id') | list %} {%
         set mapper = {
           'input_boolean.clean_dining_area' : 20,
           'input_boolean.clean_bedroom' : 17,
           'input_boolean.clean_master_bath' : 16,
           'input_boolean.clean_living_room' : 18,
           'input_boolean.clean_kids_room' : 21,
           'input_boolean.clean_study' : 19,
           'input_boolean.clean_corridor' : 22,
           'input_boolean.clean_guest_toilet' : 4
         } %} {% for room in rooms if room in mapper %} - {{ mapper[room] }} {%
         endfor %}      
mode: single
icon: 'mdi:play'

Try this version:

alias: Start vacuum room cleaning
sequence:
  - service: xiaomi_miio.vacuum_clean_segment
    data:
      entity_id: vacuum.xiaomi_vacuum_cleaner
      segments: >
        {% set rooms = expand('group.cleaning_rooms')
            | selectattr('state','eq','on')
            | map(attribute='object_id') | list %}
        {%  set mapper = {
          'clean_dining_area': 20,
          'clean_bedroom': 17,
          'clean_master_bath': 16,
          'clean_living_room': 18,
          'clean_kids_room': 21,
          'clean_study': 19,
          'clean_corridor': 22,
          'clean_guest_toilet': 4 } %}
        {% set ns = namespace(segments=[]) %}
        {% for room in rooms if room in mapper %}
          {% set ns.segments = ns.segments + [mapper[room]] %}
        {% endfor %}
        {{ ns.segments }}    
mode: single
icon: 'mdi:play'

The template generates a list. In other words, the end-result looks something like this (for two segments):

      segments: [ 20, 18 ]

It conforms to the example shown in the documentation for multiple segments.

2 Likes

Thank you so much, that does indeed work. I’m still not sure what the problem with my first attempt was, but with you elegant suggestion I’ve got it running now. Cheers.

1 Like

Your script generated a list in YAML format:

- 20
- 18
- 21

That would work if the Jinja2 interpreter evaluated the template first and then the YAML processor converted it to a list [20, 18, 21]. However, that’s not the order of processing; YAML processing takes place first and then Jinja2 processing. In other words, your template must produce output that doesn’t require conversion from YAML.

Oh, thanks, I wasn’t aware of that. So the Jinja2 is not supposed to produce the same output that I would normally write when configuring YAML, but rather the condensed version. That’s good to know - and once you know it, it’s pretty clear :slight_smile: