Using a Dictionary on a List in a Script

Hi all,

I am trying to create a script to allow users to select from a list of rooms to send my vacuum to clean.

I am trying to use the script fields “select” to allow for a custom list of rooms. The issue is that the rooms are mapped to an integer. I am struggling to convert the list of room names to a list of integers.

I have tried using the select selector’s label/value pair, but get an error when trying to use integers as the value eg:

options:
  - label: Kitchen
    value: 8

I then tried using a dictionary to convert keys a few different ways, but have not been able to get that to work.
Dictionary:

sequence:
  - variables:
      room_dict:
        Kitchen: 11
        Dining Room: 8
        Living Room: 4
        Entry: 7
        Master Bedroom: 6
        Guest Bedroom: 3
        Hallway: 10
        Bathroom: 5
        Closet: 9
        Office One: 1
        Office Two: 2

I have tried:

  - variables:
      room_ints: "{{ room_dict.room_names }}"

→ Returns empty list

  - variables:
        room_ints:
        "{% for room in room_names %}"
          - "{{ room_dict.room }}"
        "{% endfor %}"

→ Doesn’t save and doesn’t work when manually put into yaml.

I need the final service call to look similar to this:

  - service: vacuum.send_command
    data:
      command: roomClean
      params:
        roomIds:
          - 1
          - 8
        count: 1
    target:
      entity_id: vacuum.eufy_vac

What is the correct way to apply a dictionary to a list of strings? Or, how can I convert my strings to the corresponding integers? I’m not opposed to using the label/value combo, but I don’t think I can supply my vacuum with numbers formatted as strings. (I have not tried).

Full yaml:

alias: Vacuum Rooms
sequence:
  - variables:
      room_dict:
        Kitchen: 11
        Dining Room: 8
        Living Room: 4
        Entry: 7
        Master Bedroom: 6
        Guest Bedroom: 3
        Hallway: 10
        Bathroom: 5
        Closet: 9
        Office One: 1
        Office Two: 2
  - variables:
      room_ints: "{{ room_dict.room_names }}"
  - service: vacuum.send_command
    metadata: {}
    data:
      command: roomClean
      params:
        roomIds: "{{ room_ints }}"
        count: 1
    target:
      device_id: 32052100aa9681a3f547b08f1f292448
mode: single
icon: mdi:robot-vacuum
fields:
  room_names:
    selector:
      select:
        multiple: true
        options:
          - Kitchen
          - Dining Room
          - Living Room
          - Entry
          - Master Bedroom
          - Guest Bedroom
          - Hallway
          - Bathroom
          - Closet
          - Office One
          - Office Two
    name: Rooms
    required: true
    default:
      - Kitchen
      - Dining Room
    description: Text based list of rooms to vacuum

For one selected room name you can use either of the following two examples.

      room_ints: "{{ room_dict[room_names] }}"

Or

      room_ints: "{{ room_dict.get(room_names, 1) }}"

The second version returns 1 if the value of room_names doesn’t exist as a key in the room_dict dictionary.

Neither of the two examples will work if the user picks more than one room (because then room_names isn’t a string but a list of strings). A dictionary lookup is designed to find a single key. Given a list of multiple room names, you’ll have to iterate through it and lookup each one individually.

      room_ints:  >
        {% set ns = namespace(room_ints=[]) %}
        {% for room in room_names %}
          {% set room_int = room_dict.get(room, 1) %}
          {% set ns.room_ints = ns.room_ints + [room_int] %}
        {% endfor %}
        {{ ns.room_ints }}

ns.room_ints will contain a list. If you need to a comma separated string, use {{ ns.room_ints | join(', ') }}


On a separate note, have you confirmed that roomIds supports templates?

I had suspected the dictionary lookup would only work for 1 value.

Your loop worked for me. Could you explain what the namespace is doing, and maybe why my loop wasn’t working? I thought I tried using the > to denote my code, but none of my loops worked. (I’m completely new to Jinja.)

Glad to hear it worked. Please consider marking my post with the Solution tag, given that it’s the one that provides the actual solution.

Within a for-loop, a Jinja variable’s value is limited to the for-loop. That means outside the for-loop, the variable’s value will not be what it was inside the for-loop. If the variable was defined in the for-loop (not before the for-loop), it will be undefined outside the for-loop. The use of namespace lets you define variables whose value is preserved when changed inside a for-loop.

Your for-loop attempted to generate a YAML list using a Jinja template. That’s not possible in Home Assistant because it processes YAML first and Jinja second.

In addition, it has incorrect syntax (three separate lines, each wrapped in double-quotes). Use a line continuation character (like >) after the option to indicate that the Jinja template starts on the next line (and then don’t wrap each template line in any quotes).

Reference

Important Templating Rules