How To Cycle Through Scenes

I liked the Philips Hue scene cycling. I tried various ways to do this in Home Assistant, and this Smart Home Junkie video really helped me understand:

  • how to get a drop-down helper to store the current scene
  • how to use an automation to handle the button clicks and state changes
  • how to use run-mode = queued to cope with multiple button clicks

Then I found I could reduce the effort to set up scene cycling quite a lot using a little bit of templating. So this, below, is how my scene cycling now works. It takes a bit less work to set up and is easier to alter if I later alter my scenes.

Step 1: I create the scenes for my room. It’s important that their names all start with the same prefix, e.g. “Bedroom 1 bright” and “Bedroom 1 mid” scenes for my bedroom 1.

Step 2: I create a drop-down helper listing all the scene names. These names must match the bit after the prefix, so for “Bedroom 1 bright” the option is just “bright”.

Step 3: I add my drop-down to a dashboard with a custom:mushroom-select-card so I can use it directly if I need to.

Step 4: I create the automation that will handle my button. It must have run-mode = queued. Each trigger is given an ID and I use a choose action.

One of the triggers will be a state change on the drop-down I created and its option is the one that calls the service to turn on the scene. This is done with a template like this

service: scene.turn_on
metadata:
  transition: 1
target:
  entity_id: "{{ 'scene.bedroom1_' ~ states('input_select.bedroom_1_scenes') }}"

This shows why the consistent name prefix is important - it concatenates the string 'scene.bedroom1_' with the name of the selected scene.

Here’s an example of the whole thing:

alias: bedroom 4 button
description: ""
trigger:
  - device_id: 9c5bb1b88d0fc3a51100188be353d207
    domain: zha
    platform: device
    type: remote_button_short_press
    subtype: remote_button_short_press
    id: single press
  - platform: state
    entity_id:
      - input_select.bedroom_4_scenes
    id: selected
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - single press
        sequence:
          - service: input_select.select_next
            data:
              cycle: true
            target:
              entity_id: input_select.bedroom_4_scenes
      - conditions:
          - condition: trigger
            id:
              - selected
        sequence:
          - service: scene.turn_on
            metadata:
              transition: 1
            target:
              entity_id: >-
                {{ 'scene.bedroom4_' ~ states('input_select.bedroom_4_scenes')
                }}
mode: queued
max: 10

Notice that the first option doesn’t select a scene, it only alters the current drop-down helper value. So a button press triggers the automation a first time and this in turn causes the automation to be triggered again, which turns on the selected scene.

As a matter of preference, the state change trigger and action could instead be moved out into a different automation; I decided to keep both parts together in one automation, so I’d find them easily later. The queued run-mode is what makes this possible and cleanly handles multiple button clicks.

1 Like

If you assign your scenes to Areas, another option is to use an area-based Template Select (with an input text to store the current value):

 template:
  - select:
      - name: "Basement Scenes"
        state: "{{ states('input_text.selected_basement_scene') }}"
        options: >
          {{expand(area_entities("Basement"))
          | selectattr('domain', 'eq', 'scene')
          |map(attribute='name')
          | list }}
        select_option:
          - variables:
              entity: >
                {{ states.scene | selectattr('name', 'eq', option)
                | map(attribute='entity_id') | first }}
          - service: input_text.set_value
            target:
              entity_id: input_text.selected_basement_scene
            data:
              value: "{{ option }}"
          - service: scene.turn_on
            target:
              entity_id: "{{ entity }}"

You would still need to handle the remote button press in an automation.

1 Like

That’s pretty cool, thanks.

I haven’t found a good cook-book of techniques like this. Is there one anywhere?

Another option: Use an input number to store a scene index. That works if all the scenes you want to cycle through are named something like bedroom_lights_X.

alias: Bedroom Lights
trigger:
  ... next_scene, prev_scene, etc ...
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - next_scene
        sequence:
          - service: scene.turn_on
            metadata:
              transition: 1
            target:
              entity_id: >-
                {{ 'scene.bedroom_lights_' ~  ((cur_selected_scene + 1) %
                num_available_scenes ) }}
          - service: input_number.set_value
            target:
              entity_id: input_number.bedroom_scene_idx
            data:
              value: "{{ (cur_selected_scene + 1) % num_available_scenes  }}"
  - ... same for prev_scene (obviously s/+1/-1/) ... 
variables:
  num_available_scenes: |-
    {{ int((states.scene 
        | selectattr("name", "search", "bedroom_lights_") 
        | map(attribute='name') 
        | sort 
        | list 
        | last).split("_")[2]) + 1 }}
  cur_selected_scene: "{{ states('input_number.bedroom_scene_idx') | int }} "
1 Like

Wow, you’re solution is exactly what I’ve been looking for. THANK YOU!

One follow-up question… where exactly does one put that template select in the configuration files?

:sweat_smile: Sorry for the very noob question; this is the first time I’m finding the need to define a template select (and most all other helpers I’ve configured so far have been via the Helpers UI)

edit: For example, I was thinking I’d add template: !include templates.yaml to configuration.yaml, and then create a new templates.yaml file that would contain the following:

- select:
    - name: Office Scenes
      state: "{{ states('input_text.office_selected_scene') }}"
      options: >
        {{ expand(area_entities("Office"))
        | selectattr('domain', 'eq', 'scene')
        | map(attribute='name') | list }}
      select_option:
        - variables:
            entity: >
              {{ states.scene | selectattr('name', 'eq', option)
              |map(attribute='entity_id')|join }}
        - service: input_text.set_value
          target:
            entity_id: input_text.office_selected_scene
          data:
            value: "{{ option }}"
        - service: scene.turn_on
          target:
            entity_id: "{{ entity }}"

That YAML loads, but I’m not seeing anything in HA where I’d have that new Template Select :cry: Help? :innocent:

edit2: NEVERMIND! Doing the above totally worked. When I said I couldn’t find anything in HA, it’s because I was searching for “input_select.office_scenes” —> it’s totally just “select.office_scenes”. :sigh:

Looks like I’m all set to go. THANKS!

1 Like

This was very helpful, thank you very much.

As a new user of Home Assistant, I have to say though that this was surprisingly complex to set up - in fact it kept me busy for several evenings.

I found a way to automatically set the options of the dropdown to the available scenes in a particular area. This is useful because then you don’t need to keep them in sync manually.

Important to point out (for other beginners like me), when you create a drop-down through the UI, it creates an ‘input_select’. The second comment of this thread suggests to use a ‘select’ instead - and a ‘select’ somehow doesn’t have a ‘select_next’ service.

Therefore, for the one below, you create a dropdown via the UI. No need to populate it, this will automatically happen on every trigger.

Add the following to your configuration.yaml, then reload the automations via the UI:

automation wohnzimmer-cycle-button:
  - id: wohnzimmer-cycle-button3
    alias: wohnzimmer-cycle3
    description: ""
    trigger:
      - device_id: 394f0b4ac5b46b1ad7b5e61d114ba465
        domain: deconz
        platform: device
        type: remote_button_short_release
        subtype: dim_down  
        id: single press
      - platform: state
        entity_id:
          - input_select.wohnzimmer3
        id: selected
    condition: []
    action:
      - sequence:
          - service: input_select.set_options
            target:
              entity_id: input_select.wohnzimmer3
            data:
              options: >
                  {{expand(area_entities("Wohnzimmer"))
                  | selectattr('domain', 'eq', 'scene')
                  |map(attribute='entity_id')
                  | list }}  
          - choose:
              - conditions:
                  - condition: trigger
                    id:
                      - single press
                sequence:
                  - service: input_select.select_next
                    data:
                      cycle: true
                    target:
                      entity_id: input_select.wohnzimmer3
              - conditions:
                  - condition: trigger
                    id:
                      - selected
                sequence:
                  - service: scene.turn_on
                    metadata:
                      transition: 1
                    target:
                      entity_id: >-
                        {{ states('input_select.wohnzimmer3')
                        }}
    mode: queued
    max: 10

Let me also post the full automation that you need to mimic the behavior of the regular Hue Dimmer with four buttons:

  • turn on: Switches on lights, using the same scene as before.
  • dim up: Select the next “brigher” scene.
  • dim down: Select the next “darker” scene.
  • turn off: Switch off lights.

To switch off the lights, I use a special scene here called scene.wohnzimmer_aus that I didn’t add to the area “Wohnzimmer” (because otherwise the dimmer would also cycle through the “off” scene - that at least not what I want). All other scenes I added to the area “Wohnzimmer”. I used the name to sort them automatically (e.g., “1 dark”, “2 more lights”, “3 even brigher”, …).

Good luck. As I said, this was surprisingly difficult and I hope that a simple functionality like this becomes easier to set up in the future.

automation wohnzimmer-cycle-button:
  - id: wohnzimmer-cycle-button3
    alias: wohnzimmer-cycle3
    description: ""
    trigger:
      - device_id: 394f0b4ac5b46b1ad7b5e61d114ba465
        domain: deconz
        platform: device
        type: remote_button_short_release
        subtype: turn_on  
        id: turn on
      - device_id: 394f0b4ac5b46b1ad7b5e61d114ba465
        domain: deconz
        platform: device
        type: remote_button_short_release
        subtype: dim_up  
        id: dim up
      - device_id: 394f0b4ac5b46b1ad7b5e61d114ba465
        domain: deconz
        platform: device
        type: remote_button_short_release
        subtype: dim_down  
        id: dim down
      - device_id: 394f0b4ac5b46b1ad7b5e61d114ba465
        domain: deconz
        platform: device
        type: remote_button_short_release
        subtype: turn_off  
        id: turn off
      - platform: state
        entity_id:
          - input_select.wohnzimmer3
        id: turn on
    condition: []
    action:
      - sequence:
          - service: input_select.set_options
            target:
              entity_id: input_select.wohnzimmer3
            data:
              options: >
                  {{expand(area_entities("Wohnzimmer"))
                  | selectattr('domain', 'eq', 'scene')
                  | sort(attribute='name', reverse=true)
                  | map(attribute='entity_id')
                  | list }}  
          - choose:
              - conditions:
                  - condition: trigger
                    id:
                      - dim up
                sequence:
                  - service: input_select.select_previous
                    data:
                      cycle: false
                    target:
                      entity_id: input_select.wohnzimmer3
              - conditions:
                  - condition: trigger
                    id:
                      - dim down
                sequence:
                  - service: input_select.select_next
                    data:
                      cycle: false
                    target:
                      entity_id: input_select.wohnzimmer3
              - conditions:
                  - condition: trigger
                    id:
                      - turn off
                sequence:
                  - service: scene.turn_on
                    metadata:
                      transition: 1
                    target:
                      entity_id: scene.wohnzimmer_aus
              - conditions:
                  - condition: trigger
                    id:
                      - turn on
                sequence:
                  - service: scene.turn_on
                    metadata:
                      transition: 1
                    target:
                      entity_id: >-
                        {{ states('input_select.wohnzimmer3')
                        }}
    mode: queued
    max: 10
2 Likes

You could use the scene with the most recent date as the state value, then you don’t need the input_text.

 template:
  - select:
      - name: "Basement Scenes"
        state: >
          {% set area = "Basement" %}
          {{ 
            expand(area_entities(area))
              | selectattr('domain', 'eq', 'scene')
              | sort(attribute='state', reverse=true)
              | map(attribute='name')
              | list
              | first
          }}
        options: >
          {% set area = "Basement" %}
          {{
            expand(area_entities(area))
              | selectattr('domain', 'eq', 'scene')
              | map(attribute='name')
              | list
              | sort
          }}
        select_option:
          - service: scene.turn_on
            target:
              entity_id: >
                {{
                  states.scene
                    | selectattr('name', 'eq', option)
                    | map(attribute='entity_id')
                    | first
                }}
1 Like

I am not sure what am i doing wrong, however the template helper always got the state unknown. If i execute the state template alone i get the right scene which is currently activated.

Screenshot 2024-09-13 205430

Are the scenes added to the area in the entity settings?

The Template Select Helper creator does not seem to fully support the method proposed by TheFes, I get an error directly in the creator UI:

image

However, the helper entity is created and, like you mentioned, choosing an option does run the action properly. The state of the select entity just remains “unknown”. TheFes’ method does work fully when configured in YAML.

The method I posted in the second post of this thread works in both.

I will create some scenes and have a look (I actually don’t use scenes myself)

Me neither… I literally have three scenes, all of which I created to help answer a question someone posted a while back. :smile:

@regnets @Didgeridrew I see what the issue is, for the options I mapped the name, but for the state I accidentally used entity_id. So the the state template renders a value which is not a valid option.

I corrected it above.
Here’s how it looks when creating a helper:

And here’s the result