Compare commits
1
Commits
fefda42470
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08f7332b7e |
@@ -11,6 +11,8 @@ blueprint:
|
|||||||
- Set Custom Actions for Single, Double, and Long Presses on all 4 buttons.
|
- Set Custom Actions for Single, Double, and Long Presses on all 4 buttons.
|
||||||
- Automatically updates an `input_text` helper to remember the last used light.
|
- Automatically updates an `input_text` helper to remember the last used light.
|
||||||
- Rotating the dial dims the most recently interacted light smoothly.
|
- Rotating the dial dims the most recently interacted light smoothly.
|
||||||
|
- **No Dropped Clicks:** Uses `mode: parallel` and timestamping so you can press button 1, 2, 3 in rapid succession and *all* of them will register instantly without being blocked by double-click delays.
|
||||||
|
- **Native MQTT:** Connects directly to the MQTT topic (bypassing legacy Z2M action sensors).
|
||||||
- **Fallback Light**: A default light to dim if the dial is turned before any buttons are pressed.
|
- **Fallback Light**: A default light to dim if the dial is turned before any buttons are pressed.
|
||||||
|
|
||||||
**REQUIREMENT:** Create an `input_text` helper in Home Assistant (Settings > Devices & Services > Helpers) and select it below in the "Last Light Helper" input.
|
**REQUIREMENT:** Create an `input_text` helper in Home Assistant (Settings > Devices & Services > Helpers) and select it below in the "Last Light Helper" input.
|
||||||
@@ -160,9 +162,9 @@ blueprint:
|
|||||||
selector:
|
selector:
|
||||||
action: {}
|
action: {}
|
||||||
|
|
||||||
# Single mode allows our Wait For Trigger double click logic to operate natively.
|
# Parallel mode allows rapid sequential button presses across different buttons
|
||||||
mode: single
|
mode: parallel
|
||||||
max_exceeded: silent
|
max: 10
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
@@ -187,11 +189,21 @@ action:
|
|||||||
# Extract action string from MQTT payload for clean condition checks
|
# Extract action string from MQTT payload for clean condition checks
|
||||||
action_type: "{{ trigger.payload_json.action }}"
|
action_type: "{{ trigger.payload_json.action }}"
|
||||||
|
|
||||||
# Determine which light to dim (Last used helper, OR Fallback Light)
|
# Read helper memory to check for overlapping double-clicks and target lights
|
||||||
|
helper_state: "{{ states(helper_last_light) }}"
|
||||||
|
helper_parts: "{{ helper_state.split('|') if helper_state not in ['unknown', 'unavailable', 'none'] else [] }}"
|
||||||
|
|
||||||
|
prev_light: "{{ helper_parts[0] if helper_parts | length > 0 else 'none' }}"
|
||||||
|
prev_btn: "{{ helper_parts[1] if helper_parts | length > 1 else 'none' }}"
|
||||||
|
prev_time: "{{ helper_parts[2] | float(0) if helper_parts | length > 2 else 0 }}"
|
||||||
|
|
||||||
|
# Identifies if THIS trigger is the second click of an ongoing double-click window
|
||||||
|
is_double_click_secondary: "{{ action_type == prev_btn and (as_timestamp(now()) - prev_time) <= 0.5 }}"
|
||||||
|
|
||||||
|
# Determine which light to dim seamlessly
|
||||||
target_dim_light: >-
|
target_dim_light: >-
|
||||||
{% set helper_val = states(helper_last_light) %}
|
{% if prev_light not in ['none', 'unknown', 'unavailable', ''] %}
|
||||||
{% if helper_val not in ['unknown', 'unavailable', ''] and helper_val != 'none' %}
|
{{ prev_light }}
|
||||||
{{ helper_val }}
|
|
||||||
{% elif fallback_light != '' and fallback_light != none %}
|
{% elif fallback_light != '' and fallback_light != none %}
|
||||||
{{ fallback_light }}
|
{{ fallback_light }}
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -206,18 +218,21 @@ action:
|
|||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ action_type == 'button_1_press_release' }}"
|
value_template: "{{ action_type == 'button_1_press_release' }}"
|
||||||
sequence:
|
sequence:
|
||||||
# First, update the memory helper so the dial is primed immediately
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ light_1 != '' and light_1 != none }}"
|
value_template: "{{ is_double_click_secondary }}"
|
||||||
sequence:
|
sequence:
|
||||||
|
- stop: "Secondary click detected. Halting this parallel run to let the primary trace execute Double Click."
|
||||||
|
|
||||||
|
# If not stopped, this is a fresh primary click. Update memory bank.
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_1 }}"
|
value: "{{ (light_1 if light_1 != none else '') ~ '|button_1_press_release|' ~ as_timestamp(now()) }}"
|
||||||
# Await potential Double-Click directly via MQTT
|
|
||||||
|
# Await potential Double-Click via native MQTT
|
||||||
- wait_for_trigger:
|
- wait_for_trigger:
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
topic: !input mqtt_topic
|
topic: !input mqtt_topic
|
||||||
@@ -225,19 +240,18 @@ action:
|
|||||||
value_template: "{{ value_json.action | default('') }}"
|
value_template: "{{ value_json.action | default('') }}"
|
||||||
timeout: "00:00:00.500"
|
timeout: "00:00:00.500"
|
||||||
continue_on_timeout: true
|
continue_on_timeout: true
|
||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ wait.trigger is not none }}"
|
value_template: "{{ wait.trigger is not none }}"
|
||||||
sequence:
|
sequence:
|
||||||
# DOUBLE CLICK TRIGGERED
|
|
||||||
- choose: []
|
- choose: []
|
||||||
default: !input button_1_double_press
|
default: !input button_1_double_press
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ wait.trigger is none }}"
|
value_template: "{{ wait.trigger is none }}"
|
||||||
sequence:
|
sequence:
|
||||||
# SINGLE CLICK TRIGGERED
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
@@ -252,17 +266,12 @@ action:
|
|||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ action_type == 'button_1_hold' }}"
|
value_template: "{{ action_type == 'button_1_hold' }}"
|
||||||
sequence:
|
|
||||||
- choose:
|
|
||||||
- conditions:
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ light_1 != '' and light_1 != none }}"
|
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_1 }}"
|
value: "{{ (light_1 if light_1 != none else '') ~ '|button_1_hold|0' }}"
|
||||||
- choose: []
|
- choose: []
|
||||||
default: !input button_1_long_press
|
default: !input button_1_long_press
|
||||||
|
|
||||||
@@ -277,13 +286,16 @@ action:
|
|||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ light_2 != '' and light_2 != none }}"
|
value_template: "{{ is_double_click_secondary }}"
|
||||||
sequence:
|
sequence:
|
||||||
|
- stop: "Secondary click detected."
|
||||||
|
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_2 }}"
|
value: "{{ (light_2 if light_2 != none else '') ~ '|button_2_press_release|' ~ as_timestamp(now()) }}"
|
||||||
|
|
||||||
- wait_for_trigger:
|
- wait_for_trigger:
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
topic: !input mqtt_topic
|
topic: !input mqtt_topic
|
||||||
@@ -291,6 +303,7 @@ action:
|
|||||||
value_template: "{{ value_json.action | default('') }}"
|
value_template: "{{ value_json.action | default('') }}"
|
||||||
timeout: "00:00:00.500"
|
timeout: "00:00:00.500"
|
||||||
continue_on_timeout: true
|
continue_on_timeout: true
|
||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
@@ -316,17 +329,12 @@ action:
|
|||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ action_type == 'button_2_hold' }}"
|
value_template: "{{ action_type == 'button_2_hold' }}"
|
||||||
sequence:
|
|
||||||
- choose:
|
|
||||||
- conditions:
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ light_2 != '' and light_2 != none }}"
|
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_2 }}"
|
value: "{{ (light_2 if light_2 != none else '') ~ '|button_2_hold|0' }}"
|
||||||
- choose: []
|
- choose: []
|
||||||
default: !input button_2_long_press
|
default: !input button_2_long_press
|
||||||
|
|
||||||
@@ -341,13 +349,16 @@ action:
|
|||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ light_3 != '' and light_3 != none }}"
|
value_template: "{{ is_double_click_secondary }}"
|
||||||
sequence:
|
sequence:
|
||||||
|
- stop: "Secondary click detected."
|
||||||
|
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_3 }}"
|
value: "{{ (light_3 if light_3 != none else '') ~ '|button_3_press_release|' ~ as_timestamp(now()) }}"
|
||||||
|
|
||||||
- wait_for_trigger:
|
- wait_for_trigger:
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
topic: !input mqtt_topic
|
topic: !input mqtt_topic
|
||||||
@@ -355,6 +366,7 @@ action:
|
|||||||
value_template: "{{ value_json.action | default('') }}"
|
value_template: "{{ value_json.action | default('') }}"
|
||||||
timeout: "00:00:00.500"
|
timeout: "00:00:00.500"
|
||||||
continue_on_timeout: true
|
continue_on_timeout: true
|
||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
@@ -380,17 +392,12 @@ action:
|
|||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ action_type == 'button_3_hold' }}"
|
value_template: "{{ action_type == 'button_3_hold' }}"
|
||||||
sequence:
|
|
||||||
- choose:
|
|
||||||
- conditions:
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ light_3 != '' and light_3 != none }}"
|
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_3 }}"
|
value: "{{ (light_3 if light_3 != none else '') ~ '|button_3_hold|0' }}"
|
||||||
- choose: []
|
- choose: []
|
||||||
default: !input button_3_long_press
|
default: !input button_3_long_press
|
||||||
|
|
||||||
@@ -405,13 +412,16 @@ action:
|
|||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ light_4 != '' and light_4 != none }}"
|
value_template: "{{ is_double_click_secondary }}"
|
||||||
sequence:
|
sequence:
|
||||||
|
- stop: "Secondary click detected."
|
||||||
|
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_4 }}"
|
value: "{{ (light_4 if light_4 != none else '') ~ '|button_4_press_release|' ~ as_timestamp(now()) }}"
|
||||||
|
|
||||||
- wait_for_trigger:
|
- wait_for_trigger:
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
topic: !input mqtt_topic
|
topic: !input mqtt_topic
|
||||||
@@ -419,6 +429,7 @@ action:
|
|||||||
value_template: "{{ value_json.action | default('') }}"
|
value_template: "{{ value_json.action | default('') }}"
|
||||||
timeout: "00:00:00.500"
|
timeout: "00:00:00.500"
|
||||||
continue_on_timeout: true
|
continue_on_timeout: true
|
||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
@@ -444,17 +455,12 @@ action:
|
|||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ action_type == 'button_4_hold' }}"
|
value_template: "{{ action_type == 'button_4_hold' }}"
|
||||||
sequence:
|
|
||||||
- choose:
|
|
||||||
- conditions:
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ light_4 != '' and light_4 != none }}"
|
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_text.set_value
|
- service: input_text.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ helper_last_light }}"
|
entity_id: "{{ helper_last_light }}"
|
||||||
data:
|
data:
|
||||||
value: "{{ light_4 }}"
|
value: "{{ (light_4 if light_4 != none else '') ~ '|button_4_hold|0' }}"
|
||||||
- choose: []
|
- choose: []
|
||||||
default: !input button_4_long_press
|
default: !input button_4_long_press
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user