feat: add debug mode and clarify docs in MQTT Button Control

- Add optional debug notifications for trigger and light-branch decisions
- Document index-based action/entity mapping and two-topic support
- Add configuration reference table and debug-mode section to README
This commit is contained in:
2026-05-27 13:09:59 +03:00
parent ad6f30ce3c
commit 3d15f481a0
2 changed files with 177 additions and 63 deletions
+144 -53
View File
@@ -6,10 +6,13 @@
blueprint:
name: "Custom: MQTT Button Control"
description: Control a Zigbee2MQTT device with multiple actions, that allows to toggle lights and switches and store entity identifier of last interacted switch/light.
description: >
Control a Zigbee2MQTT device with multiple actions: toggle lights,
switches and input_booleans, and optionally remember the entity that
was last interacted with in an input_text helper.
domain: automation
input:
mqtt_group:
name: "MQTT"
collapsed: false
@@ -19,7 +22,7 @@ blueprint:
description: The MQTT topic for your Zigbee button (e.g., zigbee2mqtt/my_button1).
selector:
text:
mqtt_topic2:
name: MQTT Topic 2 (Optional)
description: >
@@ -28,7 +31,7 @@ blueprint:
default: "blueprint/disabled/mqtt_button_control"
selector:
text:
devices:
name: "Primary"
collapsed: false
@@ -40,19 +43,19 @@ blueprint:
selector:
text:
multiple: true
switches:
name: Switches
description: "The list of switches to control. Next types are supported: `light`, `switch`, `input_boolean`"
default: []
selector:
entity:
domain:
domain:
- light
- switch
- input_boolean
multiple: true
multiple: true
outputs:
name: "Outputs"
collapsed: false
@@ -64,7 +67,7 @@ blueprint:
selector:
entity:
domain: input_text
common:
name: "Common"
collapsed: false
@@ -78,8 +81,8 @@ blueprint:
min: 0
max: 100
step: 1
unit_of_measurement: "s"
unit_of_measurement: "s"
blink_count:
name: Count of blinks
description: "Count of blinks to indicate active light"
@@ -88,8 +91,8 @@ blueprint:
number:
min: 0
max: 5
step: 1
step: 1
blink_interval:
name: Interval between blinks
description: "Interval between indicator blinks (in ms)"
@@ -98,18 +101,36 @@ blueprint:
number:
min: 0
max: 1000
step: 50
unit_of_measurement: "ms"
step: 50
unit_of_measurement: "ms"
# -------------------------------------------------------------------------
# Debug
# -------------------------------------------------------------------------
debug_group:
name: "Debug"
collapsed: true
input:
enable_debug_notifications:
name: Enable Debug Notifications
description: >
Send persistent notifications for debugging automation behavior.
Shows received action, resolved target entity and blink decision.
default: false
selector:
boolean:
trigger:
- platform: mqtt
topic: !input mqtt_topic
id: button_1
- platform: mqtt
topic: !input mqtt_topic2
enabled: "{{ mqtt_topic2 != '' }}"
id: button_2
enabled: "{{ mqtt_topic2 not in ['', 'blueprint/disabled/mqtt_button_control'] }}"
mode: restart
condition:
- condition: template
value_template: "{{ 'action' in trigger.payload_json }}"
@@ -117,21 +138,59 @@ condition:
action:
- variables:
action_id: "{{ trigger.payload_json.action }}"
switches: !input switches
action_ids: !input action_ids
target_index: >
{% if action_id in action_ids %}
{{ action_ids.index(action_id) }}
{% else %}
-1
{% endif %}
target_entity: "{{ switches[target_index] if target_index != -1 else none }}"
last_interacted_text: !input last_interacted_text
is_debug: false
is_debug: !input enable_debug_notifications
# Resolve action_id → switch index. Whitespace-controlled and coerced
# to int so subscripting `switches[target_index]` is safe.
target_index: >-
{%- if action_id in action_ids -%}
{{ action_ids.index(action_id) }}
{%- else -%}
-1
{%- endif -%}
# Bounds-check the index: action_ids may have more entries than switches.
target_entity: >-
{%- set idx = target_index | int(-1) -%}
{%- if idx >= 0 and idx < (switches | length) -%}
{{ switches[idx] }}
{%- else -%}
{{ none }}
{%- endif -%}
has_last_interacted_text: "{{ last_interacted_text is string and last_interacted_text | trim != '' }}"
# ---------------------------------------------------------------------------
# Debug: trigger received
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "mqtt_button_control_debug"
title: "MQTT Button Control Debug"
message: >
Trigger: {{ trigger.id }}
Topic: {{ trigger.topic }}
action_id: {{ action_id }}
action_ids: {{ action_ids }}
switches: {{ switches }}
target_index: {{ target_index | int(-1) }}
target_entity: {{ target_entity if target_entity is not none else 'none' }}
has_last_interacted_text: {{ has_last_interacted_text }}
- choose:
- conditions:
- condition: template
@@ -139,12 +198,18 @@ action:
sequence:
- variables:
entity_type: "{{ target_entity.split('.')[0] }}"
- service: input_text.set_value
data:
entity_id: "{{ last_interacted_text }}"
value: "{{ target_entity }}"
# Persist last interacted entity only when a helper is configured.
- choose:
- conditions:
- condition: template
value_template: "{{ has_last_interacted_text }}"
sequence:
- service: input_text.set_value
data:
entity_id: "{{ last_interacted_text }}"
value: "{{ target_entity }}"
- choose:
# Light
- conditions:
@@ -153,14 +218,29 @@ action:
sequence:
- variables:
timeout_for_indication_blink: !input timeout_for_indication_blink
seconds_elapsed: >
{{ (as_timestamp(now()) - as_timestamp(states[target_entity].last_changed)) | int }}
should_blink: "{{ timeout_for_indication_blink != 0 and seconds_elapsed > timeout_for_indication_blink }}"
blink_count: !input blink_count
blink_timeout: !input blink_interval
is_light_on: "{{ is_state(target_entity, 'on') }}"
# Debug
# Inline state access — HA stringifies State objects when
# stored in `variables:`, so `.last_changed` must be read
# within a single template render.
seconds_elapsed: >-
{%- set s = states[target_entity] -%}
{%- if s is not none -%}
{{ (as_timestamp(now()) - as_timestamp(s.last_changed)) | int(0) }}
{%- else -%}
0
{%- endif -%}
# Blink only when both the idle timeout AND a positive
# blink count are configured; otherwise fall through to a
# plain toggle (a 0 count would otherwise run an empty
# repeat and leave the light untouched).
should_blink: >-
{{ timeout_for_indication_blink != 0
and (blink_count | int(0)) > 0
and (seconds_elapsed | int(0)) > timeout_for_indication_blink }}
# Debug: light branch state
- choose:
- conditions:
- condition: template
@@ -168,13 +248,25 @@ action:
sequence:
- service: persistent_notification.create
data:
title: "Debug Info"
notification_id: "mqtt_button_control_debug_light"
title: "MQTT Button Control Debug (light)"
message: >
seconds_elapsed = {{ seconds_elapsed }},
should_blink = {{ should_blink }}
target_entity: {{ target_entity }}
is_light_on: {{ is_light_on }}
seconds_elapsed: {{ seconds_elapsed }}
timeout_for_indication_blink: {{ timeout_for_indication_blink }}
should_blink: {{ should_blink }}
blink_count: {{ blink_count }}
blink_timeout (ms): {{ blink_timeout }}
- choose:
# Blink
# Blink (indicate light is already on after idle timeout)
- conditions:
- condition: template
value_template: "{{ should_blink and is_light_on }}"
@@ -182,7 +274,6 @@ action:
- repeat:
count: "{{ blink_count }}"
sequence:
- service: light.turn_off
target:
entity_id: "{{ target_entity }}"
@@ -190,7 +281,7 @@ action:
transition: 0
- delay:
milliseconds: "{{ blink_timeout }}"
- service: light.turn_on
target:
entity_id: "{{ target_entity }}"
@@ -198,13 +289,13 @@ action:
transition: 0
- delay:
milliseconds: "{{ blink_timeout }}"
# Actually toggle
# Actually toggle
default:
- service: light.toggle
target:
entity_id: "{{ target_entity }}"
# Switch
- conditions:
- condition: template
@@ -213,7 +304,7 @@ action:
- service: switch.toggle
target:
entity_id: "{{ target_entity }}"
# Input Boolean
- conditions:
- condition: template
@@ -221,4 +312,4 @@ action:
sequence:
- service: input_boolean.toggle
target:
entity_id: "{{ target_entity }}"
entity_id: "{{ target_entity }}"