Templating: Use map() to apply a complex filter

I recently created a template using a technique that I haven’t seen posted in this forum (and a search produced no results). It might be useful to others so I’ll explain how I used it.

I want to show a list of open doors. Each entity’s friendly_name ends with the word “Door”. I don’t want the list of open doors to contain the word “Door” repeatedly, like this:

Front Door, Rear Door, Garage Door

I want it to look like this:

Front, Rear, Garage

That means I need to remove the last five characters from each entity’s friendly_name (one space character plus the word Door). What would be a simple way to do that?

Here’s what I did:

  - platform: template
    sensors:
      open_doors:
        friendly_name: 'Open Doors'
        value_template: >
          {{ [  states.binary_sensor.front_door,
                states.binary_sensor.rear_door,
                states.binary_sensor.garage_door,
                states.binary_sensor.side_door ]
            | selectattr('state', 'eq', 'on')
            | map(attribute='name')
            | map('replace', ' Door', '')
            | list | join(', ') }}

The technique that I haven’t seen posted here (perhaps only because the use-case is so specific) is this one:

map('replace', ' Door', '')

The map filter applies the replace filter to each item in the received generator object. I’ve used map to do things like extract a specific attribute from each item, like this:

map(attribute='name')

or to convert each item to an integer value, by applying a simple filter like this:

map('int')

but this is the first time I considered using map to apply a more complex filter that takes several arguments, like replace.

Anyway, I hope this can help others who may have a similar requirement.

15 Likes