How to use custom tests in Jinja template?

Config: HA 0.118.2 Supervised on a PI.

I would like to call a service on a list of entities, but this list should be filtered from the states.

Reason: users create these entities with random names, but automation should handle them, so manually entering their entity_id-s is not an option.

Manual version (works, but can’t be used in production):

    - service: switch.turn_on
          - switch.schedule_e52b79
          - switch.schedule_757e44

Script version (works, bug ugly):

    - service: switch.turn_on
        entity_id: >
          {%- set vars = namespace(sep='') -%}
          {%- for state in states.switch -%}
            {%- if state.entity_id.startswith("switch.schedule_") and state.entity_id|length == 22 -%}
              {{ vars.sep }}{{ state.entity_id }}
            {% set vars.sep = ',' %}
            {%- endif -%}
          {%- endfor -%}

I’ve tried to create something better:

{{ states.switch|map(attribute='entity_id')|select("startswith???", "switch.schedule_")|list }}

But there is nothing similar to a startswith function.

QUESTION 1: How can I define a custom test function?

A general solution would be to select entities accessing their whole state, and map the filtered list’s entity_id-s. Something like:

{{ states.switch|select(???)|map(attribute='entity_id')|list }}

??? = List those switches, whose entity_id starts with “switch.schedule_” and any of it’s state.attributes[actions]'s entity is equal to given parameter (eg. “climate.living_room_thermostat”).

Sample schedule entity’s state attributes:

entries: 0DT0000T0700A0, 0DT0700T2350A1, 0DT2350T0000A0
- service: set_temperature
  entity: climate.living_room_thermostat
  hvac_mode: heat
  temperature: 18
- service: set_temperature
  entity: climate.living_room_thermostat
  hvac_mode: heat
  temperature: 22.5
next_trigger: 2020-11-22T23:50:00+01:00
friendly_name: Schedule #e52b79
icon: mdi:calendar-clock

QUESTION 2: Is this general solution possible at all???

I’m new to HA, and everything around it, but not a beginner. I’m sure I missed something simple, because it was like programming 40 years ago.

You have encountered the primary problem of using the entity’s name to store metadata: it’s messy to select entities by common metadata. Currently, there’s no easy way to select sub-strings from an entity’s name.

What I suggest is that you use custom attributes. I explained how to use them in this post:

For example, if you create a custom attribute called ‘type’ and assign it a value like ‘schedule’ then you can easily select all entities having this attribute and value using this template:

{{ states.switch | selectattr('attributes.type', 'eq', 'schedule')
   | map(attribute='entity_id') | list }}
1 Like

Elegant solution! I didn’t know, it is possible to add new attributes! :slight_smile:

Comment: In my case these entities are added by an automation, so I have to ask the integration’s developers to add custom attributes to the entities.

You can add custom attributes via Configuration > Customizations or by editing the customize.yaml file. Obviously the entity must exist for the custom attribute to take effect so that might prove to be tricky if the entity is created dynamically and you don’t its name in advance.