Last active
August 13, 2025 13:28
-
-
Save jsenecal/8ab52daaf53092cce35fd6705274d12b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: ERS Rotary Dial - Light Control (Event Entity) | |
| description: > | |
| Control light brightness, hue and color with an ERS rotary dial using event entities. | |
| Device needs to be in COMMAND mode (triple-press the button to switch modes). | |
| domain: automation | |
| input: | |
| light: | |
| name: Light | |
| description: The Light entity or Light Group entity to control | |
| selector: | |
| entity: | |
| filter: | |
| - domain: light | |
| - domain: group | |
| multiple: false | |
| dial: | |
| name: Rotary dial | |
| description: Select the rotary dial event entity | |
| selector: | |
| entity: | |
| filter: | |
| - domain: event | |
| multiple: false | |
| mode_tracker: | |
| name: Mode tracker | |
| description: An input number helper to store the current mode in (1-4) | |
| selector: | |
| entity: | |
| filter: | |
| - domain: input_number | |
| color_tracker: | |
| name: Color tracker | |
| description: An input number helper to store the current RGB value in (0-1535) | |
| selector: | |
| entity: | |
| filter: | |
| - domain: input_number | |
| hue_tracker: | |
| name: Hue tracker | |
| description: An input number helper to store the current hue in (2000-6500) | |
| selector: | |
| entity: | |
| filter: | |
| - domain: input_number | |
| brightness_tracker: | |
| name: Brightness tracker | |
| description: An input number helper to store the current brightness in (0-255) | |
| selector: | |
| entity: | |
| filter: | |
| - domain: input_number | |
| mode: queued | |
| max: 20 | |
| max_exceeded: silent | |
| trigger: | |
| - platform: state | |
| entity_id: !input dial | |
| attribute: event_type | |
| action: | |
| - variables: | |
| light: !input "light" | |
| dial: !input "dial" | |
| mode_tracker: !input "mode_tracker" | |
| hue_tracker: !input "hue_tracker" | |
| brightness_tracker: !input "brightness_tracker" | |
| color_tracker: !input "color_tracker" | |
| event_type: "{{ trigger.to_state.attributes.event_type if trigger.to_state and trigger.to_state.attributes else '' }}" | |
| direction: "{{ trigger.to_state.attributes.direction if trigger.to_state and trigger.to_state.attributes else '' }}" | |
| single_pressed: "{{ event_type == 'single' }}" | |
| double_pressed: "{{ event_type == 'double' }}" | |
| brightness_rotated: "{{ event_type == 'brightness_step' }}" | |
| temp_rotated: "{{ event_type in ['color_temperature_step_up', 'color_temperature_step_down'] }}" | |
| rotated: "{{ brightness_rotated or temp_rotated }}" | |
| positive: "{{ direction == 'up' or event_type == 'color_temperature_step_up' }}" | |
| # Fixed step size for event-based devices | |
| step_size: 20 | |
| full_rotate_step_count: "{{ 13 * 20 | int }}" | |
| current_mode: "{{ states(mode_tracker) | int(1) }}" | |
| min_mode: "{{ state_attr(mode_tracker, 'min') | int(1) }}" | |
| max_mode: "{{ state_attr(mode_tracker, 'max') | int(4) }}" | |
| next_mode: > | |
| {% set val = current_mode + 1 %} | |
| {% if val > max_mode %} | |
| {% set val = min_mode %} | |
| {% endif %} | |
| {{ val | int }} | |
| min_hue: "{{ state_attr(hue_tracker, 'min') | int(2000) }}" | |
| max_hue: "{{ state_attr(hue_tracker, 'max') | int(6500) }}" | |
| hue_steps: "{{ full_rotate_step_count * 2 | int }}" | |
| hue_delta: "{{ (step_size | float(0) / hue_steps) * (max_hue - min_hue) }}" | |
| next_hue: > | |
| {%- set val = states(hue_tracker) | float(0) -%} | |
| {%- set delta = hue_delta -%} | |
| {%- if not positive -%} | |
| {%- set delta = delta * -1 -%} | |
| {%- endif -%} | |
| {%- set val = val + delta | int -%} | |
| {%- if positive and val > max_hue -%} | |
| {%- set val = max_hue -%} | |
| {%- elif not positive and val < min_hue -%} | |
| {%- set val = min_hue -%} | |
| {%- endif -%} | |
| {{ val | int }} | |
| min_brightness: "{{ state_attr(brightness_tracker, 'min') | int(0) }}" | |
| max_brightness: "{{ state_attr(brightness_tracker, 'max') | int(255) }}" | |
| brightness_steps: "{{ full_rotate_step_count * 2 | int }}" | |
| brightness_delta: "{{ (step_size | float(0) / brightness_steps) * (max_brightness - min_brightness) }}" | |
| next_brightness: > | |
| {%- set val = states(brightness_tracker) | float(0) -%} | |
| {%- set delta = brightness_delta -%} | |
| {%- if not positive -%} | |
| {%- set delta = delta * -1 -%} | |
| {%- endif -%} | |
| {%- set val = val + delta | int -%} | |
| {%- if positive and val > max_brightness -%} | |
| {%- set val = max_brightness -%} | |
| {%- elif not positive and val < min_brightness -%} | |
| {%- set val = min_brightness -%} | |
| {%- endif -%} | |
| {{ val | int }} | |
| min_color: "{{ state_attr(color_tracker, 'min') | int(0) }}" | |
| max_color: "{{ state_attr(color_tracker, 'max') | int(1535) }}" | |
| color_steps: "{{ full_rotate_step_count * 3 | int }}" | |
| color_delta: "{{ (step_size | float(0) / color_steps) * (max_color - min_color) }}" | |
| next_color: > | |
| {%- set val = states(color_tracker) | float(0) -%} | |
| {%- set delta = color_delta -%} | |
| {%- if not positive -%} | |
| {%- set delta = delta * -1 -%} | |
| {%- endif -%} | |
| {%- set val = val + delta | int -%} | |
| {%- if positive and val > max_color -%} | |
| {%- set val = val % max_color -%} | |
| {%- elif not positive and val < min_color -%} | |
| {%- set diff = min_color - val -%} | |
| {%- set val = max_color - (diff % max_color) -%} | |
| {%- endif -%} | |
| {{ val | int }} | |
| - condition: template | |
| value_template: "{{ event_type != '' and trigger.to_state is not none }}" | |
| - choose: | |
| # If event was a dial turn | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ rotated }}" | |
| sequence: | |
| - choose: | |
| # Mode 1: Do nothing (prevent accidental changes) | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ current_mode == 1 }}" | |
| sequence: [] | |
| # Mode 2: Brightness | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ current_mode == 2 }}" | |
| sequence: | |
| - service: input_number.set_value | |
| entity_id: !input brightness_tracker | |
| data: | |
| value: "{{ next_brightness }}" | |
| - service: light.turn_on | |
| data: | |
| brightness: "{{ states(brightness_tracker) | int }}" | |
| target: | |
| entity_id: !input light | |
| # Mode 3: Color temperature | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ current_mode == 3 }}" | |
| sequence: | |
| - service: input_number.set_value | |
| entity_id: !input hue_tracker | |
| data: | |
| value: "{{ next_hue }}" | |
| - service: light.turn_on | |
| data: | |
| kelvin: "{{ states(hue_tracker) | int }}" | |
| target: | |
| entity_id: !input light | |
| # Mode 4: RGB Color | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ current_mode == 4 }}" | |
| sequence: | |
| - service: input_number.set_value | |
| entity_id: !input color_tracker | |
| data: | |
| value: "{{ next_color }}" | |
| - service: light.turn_on | |
| data: | |
| rgb_color: > | |
| {%- set r = 0 -%} | |
| {%- set g = 0 -%} | |
| {%- set b = 0 -%} | |
| {%- set index = states(color_tracker) | int -%} | |
| {%- if index > 0 and index <= 256 -%} | |
| {%- set r = 255 -%} | |
| {%- set g = index -%} | |
| {%- set b = 0 -%} | |
| {%- elif index > 256 and index <= 512 -%} | |
| {%- set r = 512 - index -%} | |
| {%- set g = 255 -%} | |
| {%- set b = 0 -%} | |
| {%- elif index > 512 and index <= 768 -%} | |
| {%- set r = 0 -%} | |
| {%- set g = 255 -%} | |
| {%- set b = index - 512 -%} | |
| {%- elif index > 768 and index <= 1024 -%} | |
| {%- set r = 0 -%} | |
| {%- set g = 1024 - index -%} | |
| {%- set b = 255 -%} | |
| {%- elif index > 1024 and index <= 1280 -%} | |
| {%- set r = index - 1024 -%} | |
| {%- set g = 0 -%} | |
| {%- set b = 255 -%} | |
| {%- elif index > 1280 and index <= 1536 -%} | |
| {%- set r = 255 -%} | |
| {%- set g = 0 -%} | |
| {%- set b = 1536 - index -%} | |
| {%- endif -%} | |
| [{{ r }}, {{ g }}, {{ b }}] | |
| target: | |
| entity_id: !input light | |
| # Single press: change mode | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ single_pressed }}" | |
| sequence: | |
| - service: input_number.set_value | |
| entity_id: !input mode_tracker | |
| data: | |
| value: "{{ next_mode }}" | |
| # Double press: toggle light | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ double_pressed }}" | |
| sequence: | |
| - service: light.toggle | |
| target: | |
| entity_id: !input light |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment