Cycling through all scenes in the area

Hi,
I have not found any post explaining how to do the simplest thing of cycling through all the scenes contained in the area, so here is my take at it.

It could be more concise if:

  1. There would be a way to retrieve just scene entities from the area - I haven’t found such a way.
  2. If Jinja2 allowed for custom filters or tests but I think hey believe it’s a task of a backend not a frontend templating system :wink:

Steps to recreate what I have done:

  1. Create a helper text input.
  2. Create an automation triggered by whatever you need to trigger it (in my case it’s Shelly buttons in detached mode).
  3. Assign next scene name to the text input (explained below)
  4. Run the scene entity by the name from text input.

Here’s my rather convoluted template for input_text.set_value service. The first two variables up top to make it easier to copy over to other automations and change them.

{% set areaName = "area_name" %}
{% set sceneTextInputName = "input_text.input_text_name" %}
{% set ns = namespace(chooseNext=false) %}
{% set ns.found = false %}
{% set ns.fallbackScene = "" %}
{% for entity in area_entities(areaName)-%}
  {% if entity.startswith("scene.") -%}
    {% if not ns.fallbackScene -%}
      {% set ns.fallbackScene = entity -%}
    {%- endif %}
    {% if ns.chooseNext -%}
      {% set ns.chooseNext = false -%}
      {% set ns.found = true -%}
      {{entity-}}
    {% elif states(sceneTextInputName) == entity -%}
      {% set ns.chooseNext = true -%}
    {%- endif %}
  {%- endif %}
{%- endfor %}
{% if ns.found == false -%}
  {{ns.fallbackScene-}}
{%- endif %}

Eseentially this loops through all the entities in the area. For each entity checks if it stars with “scene.” (because I haven’t found a way to fetch scenes in the area).
It finds the scene which’s name is currently stored in the text input. Then it sets the next scene. I’m not sure if there’s a way to break out of the loop so I use a boolean to skip the subsequent items.

In case if the currently set scene was not found, none was set or it was the last one it “defaults” to the first found scene among entities.

Then it’s just a matter of calling scene.turn_on service:

service: scene.turn_on
target:
  entity_id: "{{states('input_text.input_text_name')}}"
data: {}

For completnes, json to set the tex value:

service: input_text.set_value
target:
  entity_id: input_text.input_text_name
data:
  value: >-
PASTE TEMPLATE HERE

Any thoughts / suggestion on how to improve this / do it more easily?

You can reduce the template to this:

{% set areaName = "area_name" %}
{% set sceneTextInputName = "input_text.input_text_name" %}
{% set scenes = area_entities(areaName) | sort | select('match', 'scene') | list %}
{% set next_index = scenes.index(states(sceneTextInputName)) + 1 %}
{{ scenes[iif(next_index < scenes|count, next_index, 0)] }}
1 Like

Template Selects see Example #3.

Oh wow, I was reading through Jinji docs and didn’t find the “match” test. Great that you can find index in a list, awesome. Thanks.

FWIW, I had considered suggesting the use of a Template Select but my impression is that it wouldn’t reduce the complexity of theadam’s current design.

In theadam’s current design:

  1. Input Text (one per area)
  2. Automation (one designed to handle multiple areas)

The automation detects a Shelly button press, uses input_text.set_value with the template to set the next scene, then turns on that scene.

Proposed design; please correct me if I got it wrong.

  1. Input Text (one per area)
  2. Template Select (one per area)
  3. Automation (one designed to handle multiple areas)

The automation detects the Shelly button press, uses select.select_next with the associated Template Select. In turn, the Template Select uses input_text.set_value with the template to set the next scene, then turns on that scene.

You’re not wrong, I was thinking more along the line that it’s an alternative that adds some UI functionality if that was something OP was considering having anyway.

One minor update - in case a scene is not set in the text input or if it got deleted or if it doesn’t exist this template fails. This is how I’ve fixed it:

{% set areaName = "kitchen" %}
{% set sceneTextInputName = "input_text.kitchencurrentscene" %}
{% set scenes = area_entities(areaName) | sort | select('match', 'scene') | list %}
{% set next_index = scenes.index(states(sceneTextInputName)) if states(sceneTextInputName) in scenes else 0 %}
{{ scenes[iif(next_index < scenes|count, next_index, 0)] }}

As for the other comment - I have both one text input and one automation per area - not sure how I could have one handle multiple areas. Since I have mostly Phillips Hue lights and use scenes mostly to set specific colours / brightness, I use Shellys in detached state and trigger automation on “powered” and “not powered” state change of a sensor. Is there a better way to go about this?

I would gladly read up on template selects too, any decent documentation on this?

That’s a lot of potential failures. Sounds like they should be mitigated upstream of this template. Because the fix you made serves to mask their presence.

Adjusted some more as the suggestions above did not work in some edge cases

                {% set areaName = "kitchen" %}
                {% set scenes = area_entities(areaName) | sort | select('match', 'scene') | list %}
                {% set current_scene = states("input_text.kitchencurrentscene")  %}
                {% if current_scene in scenes %}{% set next_index = scenes.index(current_scene) + 1  %}{% else %}{% set next_index = 0 %}{% endif %} 
                {% if(next_index< scenes|count) %}{{scenes[next_index]}}{%else%}{%endif %}

In my case I am not only cycling scenes but turning the lights off once I have looped through all scenes. After turning off I start cycling through all scenes again.

Important part of my automation to achieve that is:

          - if:
              - condition: template
                value_template: "{{ next_scene == '' }}"
            then:
              - action: light.turn_off
                metadata: {}
                data: {}
                target:
                  entity_id: light.kitchen_cooking_isle_pendants
            else:
              - action: scene.turn_on
                target:
                  entity_id: "{{ next_scene }}"