I have just started installing Inovelli 2-1 switches throughout the house and I wanted to be able to use the config button to rotate between scenes. I realized pretty quickly that activating scenes as you rotate through them could leave the residual effects of prior scenes still active when you get to what you want. I think I’ve come up with a solution that I like, and I figured I’d share in in case:
- It’s useful to anyone else
- There’s an easier way to do it that I’m not aware of
Automation automation.config_press_rotates_scene
:
alias: Config Press Rotates Scene
description: ""
trigger:
- platform: event
event_type: zha_event
event_data:
command: button_3_press
condition: []
action:
- service: script.rotate_scene
data:
device_id: "{{ trigger.event.data.device_id }}"
mode: single
Script script.rotate_scene
:
alias: Rotate Scene
sequence:
- alias: Define variables
variables:
room: "{{ area_id(device_id) }}"
snapshot_scene: "{{ area_id(device_id) ~ '_snapshot' }}"
scenes: |
{{ area_entities(area_id(device_id))
|select('search', '^scene\.')
|sort
|list }}
- alias: Abort if there are no scenes in this area
if:
- condition: template
value_template: "{{ scenes|length == 0 }}"
then:
- stop: There are no scenes in this area
- alias: Define snapshot entities
variables:
snapshot_entities: |
{{ scenes|map('state_attr', 'entity_id')|sum(start=[]) }}
- alias: >-
Create individualized snapshot scenes (to restore entities affected by
other scenes in rotation)
repeat:
for_each: "{{ scenes }}"
sequence:
- alias: Create a snapshot using entities from other scenes in rotation
service: scene.create
data:
scene_id: >-
{{ snapshot_scene ~ '_' ~ repeat.item|regex_replace('^scene\.', '')|regex_replace('^' ~ room ~ '_', '') }}
snapshot_entities: >
{% set scene = repeat.item %}
{% set entities = state_attr(scene, 'entity_id') %}
{{ snapshot_entities|reject('in', entities)|list }}
- alias: Create an overall snapshot scene
service: scene.create
data:
scene_id: "{{ snapshot_scene }}"
snapshot_entities: "{{ snapshot_entities }}"
- alias: Continue allowing scene rotation until a timeout
repeat:
sequence:
- parallel:
- alias: Restore snapshot state
service: scene.turn_on
target:
entity_id: >-
scene.{{ snapshot_scene ~ '_' ~ (scenes[(repeat.index - 1) % scenes|length])|regex_replace('^scene\.', '')|regex_replace('^' ~ room ~ '_', '') }}
data:
transition: 0.25
- alias: Apply the scene
service: scene.turn_on
target:
entity_id: "{{ scenes[(repeat.index - 1) % scenes|length] }}"
data:
transition: 0.25
- wait_for_trigger:
- platform: event
event_type: zha_event
event_data:
command: button_3_press
id: rotate
- platform: event
event_type: zha_event
event_data:
command: button_1_press
device_id: "{{ device_id }}"
id: cancel
timeout: "0:00:10"
until:
- condition: template
value_template: |
{{ (wait.trigger is none) or
(wait.trigger.id == 'cancel') or
(wait.trigger.id == 'rotate' and wait.trigger.event.data.device_id != device_id) }}
- alias: >-
Restore the original snapshot if the paddle was pressed down or a
different config button was pressed
if:
- condition: template
value_template: |
{{ (wait.trigger.id == 'cancel') or
(wait.trigger.id == 'rotate' and wait.trigger.event.data.device_id != device_id) }}
then:
- alias: Restore starting state
service: scene.turn_on
target:
entity_id: scene.{{ snapshot_scene }}
data:
transition: 0.25
- alias: Re-invoke with the new device if a different config button was pressed
if:
- condition: template
value_template: >
{{ (wait.trigger.id == 'rotate' and wait.trigger.event.data.device_id
!= device_id) }}
then:
- alias: >-
Start the new rotation (synchronously which prevents a new automation
starting this script)
service: script.rotate_scene
data:
device_id: "{{ wait.trigger.event.data.device_id }}"
mode: parallel
icon: mdi:palette
max: 10
This basically does the following:
- Find all scenes in the area.
- Create an individualized scene snapshot that will be applied alongside each scene in rotation. This contains any entities from other scenes that will be rotated through.
- Create an overall scene snapshot of the state of entities used by any scene in rotation.
- Apply the next scene each time the config button is pressed & at the same time restore using the snapshot that’s specifically associated with this scene.
- Allow a quick abort of pressing down on the paddle to restore the original state or to use a different switch (opps, wrong one—let me try the other one).
This also leaves the residual scenes that are created, but it could add a scene.reload
service call at the end to clean up if one so desired.
I’ve just finished it a little while ago, so it hasn’t been used extensively. There may be issues, but it’s working in my limited testing. Comments & criticism welcome!