Template select to trigger scene

Hello,

after reading a lot of forum content I was finally able to get the functionality I wanted:

An input select where:

  • options are automatically populated according to a search term (in this case scenes that start with a particular name)
  • by selecting an option the associated scene is triggered
  • after a few seconds the input select state reverts to a default
  • and finally: the names shown in the input select are shorter than the actual scene names; i.e. a simple replace and then append later when the selected scene is triggered

Example: I have these scenes:
1_bn_sc_l_cw_low
1_bn_sc_l_cw_mid
1_bn_sc_l_cw_high

And the code below will make it so that they will display in the input select as:
low
mid
high

As said I solved it but it looks horrible. Is there any better way to deal with the replace before I replicate the code to all rooms?

Maybe @petro knows, who clearly is the master of simplifying expressions like this? ; )

  - select:  
      - name: "1_bn_l_scenes_cw"
        icon: "mdi:lightbulb-multiple"
        state: >
          {% set searchterm = '1_bn_sc_l_cw_' %}
          {% set reset_seconds = 1 %}
          {% set recent = states.scene | selectattr('object_id', 'search', searchterm) |
          sort(attribute='state', reverse=true) | list | first %}
          {{ recent.name.replace(searchterm,'') if recent.state | 
          as_datetime > now() - timedelta(seconds=reset_seconds) else '- please select scene -' }}
        options: >
          {% set searchterm = '1_bn_sc_l_cw_' %}
          {% set templist = ['- please select scene -'] + states.scene |
          selectattr('object_id', 'search', searchterm) | map(attribute='name') | list | sort %}
          {% set data = namespace(newlist = []) %}
          {% for t in templist %}
          {% set data.newlist = data.newlist + [t.replace(searchterm,'')] %}
          {% endfor %}
          {% set templist = data.newlist %}
          {{ templist }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{ states.scene | selectattr('name', 'eq', '1_bn_sc_l_cw_' + option)
                | map(attribute='entity_id') | first }}

Bonus question: Is there a way to set the searchterm variable in a way that I wouldnt have to repeat it for state, options and select_option?

Also I find it hard to find a proper guide on how to apply python in HA. The syntax in HA is so different in many cases or you require an odd approach for some reason - is there anything good out there to recommend?

Many thanks!!

Maybe pyscript

That can help! Thank you

While there are still a few places where using a namespace is needed, the map() filter by itself or in combination with apply() can cover a lot of cases where they have been used in the past.

This whole section:

… can be replaced with:

{{ templist | map('replace', searchterm, '') |list }}

IIRC, you can set variables at the entity level:

  - select:  
      - name: "1_bn_l_scenes_cw"
        icon: "mdi:lightbulb-multiple"
        variables:
          searchterm: "1_bn_sc_l_cw_"
          default_val: "- please select scene -"
          reset_seconds: 1
        state: >
          {% set recent = states.scene | selectattr('object_id', 'search', searchterm) |
          sort(attribute='state', reverse=true) | first %}
          {{ recent.name.replace(searchterm,'') if recent.state | 
          as_datetime > now() - timedelta(seconds=reset_seconds) else default_val }}
        options: >
          {{ [default_val] + states.scene | selectattr('object_id', 'search', searchterm) 
          | map(attribute='name') | sort | map('replace', searchterm, '') | list }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{ states.scene | selectattr('name', 'eq', searchterm + option)
                | map(attribute='entity_id') | first }}

Because these variables are only set when the integration is reloaded, this would be mainly useful for static values like the search term and default option. But that should make it easier to set up multiple Selects with minimal need for editing.

If you’re going to be using a lot of these it may be worth considering switching them to be trigger-based rather than state based so you’re not rendering the templates every second when it’s not needed. I have included a basic example of a Self-resetting, Trigger-based Template Select in the Template Select Entities cookbook article.

2 Likes

Yep, entity level is allowed now

1 Like

I knew it! One line to replace my code struggle…

Also great to see entity-level variables are a thing. Will make it much easier for this and similar constructs.

And good point on performance - I may set this up for light and cover scenes in multiple rooms. I already noticed that it must refresh quickly in the background when playing around with the code and checking results in UI as there was no refresh or anything needed. I’ll check out the cookbook : )

Many thanks!

This is the updated code based on template/select - works fine & is now easy to copy/ amend/ reuse (you just have to change name and searchterm):

  - select:
      - name: "1_bn_l_scenes_cw"
        icon: "mdi:lightbulb-multiple"
        variables:
          searchterm: "1_bn_sc_l_cw_"
          default_val: "- please select scene -"
        state: >
          {% set reset_seconds = 1 %}
          {% set recent = states.scene | selectattr('object_id', 'search', searchterm) | sort(attribute='state', reverse=true) | list | first %}
          {{ recent.name.replace(searchterm,'') if recent.state|as_datetime > now() - timedelta(seconds=reset_seconds) else default_val }}
        options: > 
          {% set templist = [default_val] + states.scene | selectattr('object_id', 'search', searchterm) | map(attribute='name') | list | sort %}
          {{ templist | map('replace', searchterm, '') |list }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{ states.scene | selectattr('name', 'eq', searchterm + option)
                | map(attribute='entity_id') | first }}

I also tried out the trigger-based variant as per the cookbook which also works fine but is a bit harder to reuse as it requires changing 4 items instead of two; but if the other one will slow down HA if used a few dozen times than thats an easy tradeoff:

  - trigger:
      - trigger: state
        entity_id: select.1_bn_l_scenes_cw
        not_to: default_val
        for: '00:00:02'
        id: default
        variables:
          searchterm: "1_bn_sc_l_cw_"
          default_val: "- please select scene -"
      - trigger: homeassistant
        event: start
        id: default
      - trigger: event
        event_type: custom_select_event
        event_data:
          entity_id: select.1_bn_l_scenes_cw
        id: selection
    select:
      - name: 1_bn_l_scenes_cw
        icon: "mdi:lightbulb-multiple"
        optimistic: true
        state: >
          {{ default_val if trigger.id == 'default' else trigger.event.data.option|default(default_val,1) }}
        options: >
          {% set templist = [default_val] + states.scene | selectattr('object_id', 'search', searchterm) | map(attribute='name') | list | sort %}
          {{ templist | map('replace', searchterm, '') |list }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{ states.scene | selectattr('name', 'eq', searchterm + option)
                | map(attribute='entity_id') | first }}

Thanks again @Didgeridrew