- Improve calculations for ZHA ERS light dial (remove double-click power)

- Add Z2M port of ERS light dial
This commit is contained in:
nwithan8 2023-08-15 22:22:57 -06:00
parent 39c31c6463
commit 6c24516184
2 changed files with 300 additions and 26 deletions

View File

@ -1,9 +1,11 @@
# Instructions: https://community.home-assistant.io/t/zha-control-light-color-hue-brightness-with-ers-dial/595002
# Instructions: https://community.home-assistant.io/t/zha-z2m-control-light-color-hue-brightness-with-ers-dial/595002
blueprint:
name: ERS Rotary Dial - Light Control
name: ERS Rotary Dial - Light Control (Z2M) - EVENT mode
description: Control light brightness, hue and color with an ERS rotary dial
source_url: https://raw.githubusercontent.com/nwithan8/configs/main/home_assistant/blueprints/automations/ers_rotary_dial_light_control_z2m.yaml
domain: automation
input:
@ -71,7 +73,17 @@ variables:
hue_tracker: !input "hue_tracker"
brightness_tracker: !input "brightness_tracker"
color_tracker: !input "color_tracker"
positive: "{{ trigger.event.data.command == 'step' and trigger.event.data.params.step_mode == 0 }}"
command: "{{ trigger.to_state.state }}"
single_pressed: "{{ command == 'single' }}"
double_pressed: "{{ command == 'double' }}"
rotated: "{{ command in ['rotate_right', 'rotate_left'] }}"
positive: "{{ command == 'rotate_right' }}"
step_size: >
{% if rotated %}
{{ trigger.to_state.attributes.action_step_size | int }}
{% else %}
{{ 0 }}
{% endif %}
# How many steps to go full rotation (min 13 per step * 20 steps per full rotation)
full_rotate_step_count: "{{ 13 * 20 | int }}"
current_mode: "{{ states(mode_tracker) | int }}"
@ -88,12 +100,7 @@ variables:
max_hue: "{{ state_attr(hue_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
hue_steps: "{{ full_rotate_step_count * 2 | int }}"
hue_delta: >
{% if trigger.event.data.command != 'step' %}
{{ 0 }}
{% else %}
{{ (trigger.event.data.params.step_size | float(0) / hue_steps) * (max_hue - min_hue) }}
{% endif %}
hue_delta: "{{ (step_size | float(0) / hue_steps) * (max_hue - min_hue) }}"
# don't loop when reached max or min
next_hue: >
{%- set val = states(hue_tracker) | float(0) -%}
@ -112,12 +119,7 @@ variables:
max_brightness: "{{ state_attr(brightness_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
brightness_steps: "{{ full_rotate_step_count * 2 | int }}"
brightness_delta: >
{% if trigger.event.data.command != 'step' %}
{{ 0 }}
{% else %}
{{ (trigger.event.data.params.step_size | float(0) / brightness_steps) * (max_brightness - min_brightness) }}
{% endif %}
brightness_delta: "{{ (step_size | float(0) / brightness_steps) * (max_brightness - min_brightness) }}"
# don't loop when reached max or min
next_brightness: >
{%- set val = states(brightness_tracker) | float(0) -%}
@ -136,12 +138,7 @@ variables:
max_color: "{{ state_attr(color_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
color_steps: "{{ full_rotate_step_count * 3 | int }}"
color_delta: >
{% if trigger.event.data.command != 'step' %}
{{ 0 }}
{% else %}
{{ (trigger.event.data.params.step_size | float(0) / color_steps) * (max_color - min_color) }}
{% endif %}
color_delta: "{{ (step_size | float(0) / color_steps) * (max_color - min_color) }}"
# loop when reached max or min
next_color: >
{%- set val = states(color_tracker) | float(0) -%}
@ -170,7 +167,7 @@ action:
# If event was a dial turn
- conditions:
- condition: template
value_template: "{{ trigger.event.data.command == 'step' }}"
value_template: "{{ rotated }}"
alias: Dial turned (0 for right, 1 for left)
sequence:
# Process different actions based on current mode
@ -270,7 +267,7 @@ action:
# If event was a dial button short push
- conditions:
- condition: template
value_template: "{{ trigger.event.data.command == 'toggle' }}"
value_template: "{{ single_pressed }}"
sequence:
# Change mode (cycling back if reached the end)
- service: input_number.set_value
@ -281,7 +278,7 @@ action:
# If event was a dial button long press
- conditions:
- condition: template
value_template: "{{ trigger.event.data.command == 'move_saturation' }}" # dumb: https://github.com/zigpy/zha-device-handlers/blob/92c9fbc6d01a5d86f78d64183302b906aa7d8215/zhaquirks/tuya/ts004f.py#L146C37-L146C37
value_template: "{{ double_pressed }}"
sequence:
# Toggle light power
- service: light.toggle

View File

@ -0,0 +1,277 @@
# Instructions: https://community.home-assistant.io/t/zha-z2m-control-light-color-hue-brightness-with-ers-dial/595002
blueprint:
name: ERS Rotary Dial - Light Control (ZHA) - COMMAND mode
description: Control light brightness, hue and color with an ERS rotary dial
source_url: https://raw.githubusercontent.com/nwithan8/configs/main/home_assistant/blueprints/automations/ers_rotary_dial_light_control_zha.yaml
domain: automation
input:
light:
name: Light
description: The Light entity or Light Group entity to control
selector:
entity:
filter:
- domain:
- light
- group
multiple: false
dial:
name: Rotary dial
description: Select the rotary dial you wish to use to control the light
selector:
device:
filter:
integration: zha
model: TS004F
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
# Queued, to ignore non-matched events but capture existing ones
mode: queued
max: 20
max_exceeded: silent
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"
command: "{{ trigger.event.data.command }}"
single_pressed: "{{ command == 'toggle' }}"
# double_pressed: "{{ command == 'move_saturation' }}" # dumb: https://github.com/zigpy/zha-device-handlers/blob/92c9fbc6d01a5d86f78d64183302b906aa7d8215/zhaquirks/tuya/ts004f.py#L146C37-L146C37
rotated: "{{ command == 'step' }}"
positive: "{{ rotated and trigger.event.data.params.step_mode == 0 }}"
step_size: >
{% if rotated %}
{{ trigger.event.data.params.step_size | float(0) }}
{% else %}
{{ 0 }}
{% endif %}
# How many steps to go full rotation (min 13 per step * 20 steps per full rotation)
full_rotate_step_count: "{{ 13 * 20 | int }}"
current_mode: "{{ states(mode_tracker) | int }}"
min_mode: "{{ state_attr(mode_tracker, 'min') | int }}"
max_mode: "{{ state_attr(mode_tracker, 'max') | int }}"
# always increment, looping
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 }}"
max_hue: "{{ state_attr(hue_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
hue_steps: "{{ full_rotate_step_count * 2 | int }}"
hue_delta: "{{ (step_size | float(0) / hue_steps) * (max_hue - min_hue) }}"
# don't loop when reached max or min
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 }}"
max_brightness: "{{ state_attr(brightness_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
brightness_steps: "{{ full_rotate_step_count * 2 | int }}"
brightness_delta: "{{ (step_size | float(0) / brightness_steps) * (max_brightness - min_brightness) }}"
# don't loop when reached max or min
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 }}"
max_color: "{{ state_attr(color_tracker, 'max') | int }}"
# How many steps to go full min-max spectrum
color_steps: "{{ full_rotate_step_count * 3 | int }}"
color_delta: "{{ (step_size | float(0) / color_steps) * (max_color - min_color) }}"
# loop when reached max or min
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 }}
trigger:
- platform: event
event_type: zha_event
event_data:
device_id: !input dial
action:
# Process current event
- choose:
# If event was a dial turn
- conditions:
- condition: template
value_template: "{{ rotated }}"
alias: Dial turned (0 for right, 1 for left)
sequence:
# Process different actions based on current mode
- choose:
# In Mode 1 (don't do anything; prevent accidental knob rotation)
- conditions:
- condition: template
value_template: "{{ current_mode == 1 }}"
alias: In Mode 1 (Power)
sequence: [ ]
# In Mode 2 (Brightness)
- conditions:
- condition: template
value_template: "{{ current_mode == 2 }}"
alias: In Mode 2 (Brightness)
sequence:
- service: input_number.set_value
entity_id: !input brightness_tracker
data:
value: "{{ next_brightness }}"
alias: Update brightness tracker
- service: light.turn_on
data:
brightness: "{{ states(brightness_tracker) | int }}"
target:
entity_id: !input light
alias: Change light brightness
# In Mode 3 (Hue)
- conditions:
- condition: template
value_template: "{{ current_mode == 3 }}"
alias: In Mode 3 (Hue)
sequence:
- service: input_number.set_value
entity_id: !input hue_tracker
data:
value: "{{ next_hue }}"
alias: Update hue tracker
- service: light.turn_on
data:
kelvin: "{{ states(hue_tracker) | int }}"
target:
entity_id: !input light
alias: Change light hue
# In Mode 4 (Color)
- conditions:
- condition: template
value_template: "{{ current_mode == 4 }}"
alias: In Mode 4 (Color)
sequence:
- service: input_number.set_value
entity_id: !input color_tracker
data:
value: "{{ next_color }}"
alias: Update color tracker
- service: light.turn_on
data:
# Calculate RGB codes based on 0-1535 index (max 2 channels, one always off)
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 -%}
{%- set r = r | string -%}
{%- set g = g | string -%}
{%- set b = b | string -%}
{{ r + "," + g + "," + b }}
target:
entity_id: !input light
alias: Change light color
alias: Determine action based on mode
# If event was a dial button short push
- conditions:
- condition: template
value_template: "{{ single_pressed }}"
sequence:
# Change mode (cycling back if reached the end)
- service: input_number.set_value
entity_id: !input mode_tracker
data:
value: "{{ next_mode }}"
alias: Switch to next mode