Compare commits

3 Commits

Author SHA1 Message Date
alexei.dolgolyov a52cffa062 fix: remove notification title from Dreame Vacuum to avoid duplicated device name
The `notification_title` input defaulted to `{vacuum_name}`, which caused the
device name to appear twice (once in the title, once in the message body that
already starts with `{vacuum_name}`). Drop the title input and revert to
message-only notifications, matching the original behavior.
2026-05-07 22:11:21 +03:00
alexei.dolgolyov 3e98e14882 Add debug mode and harden notify flow in Alarm Notification
- Add `debug_enabled` input that surfaces per-stage persistent
  notifications ([1/4] trigger, [1.5/4] conditions, [2/4] message,
  [2.25/4]/[2.75/4] around the service call, [3/4] result,
  [3.5/4] post-branch checkpoint, [4/4] alarm control).
- Include a `blueprint_version` stamp in [1/4] so it's obvious
  when a stale cached copy is still running.
- Gate the notify branch on `trigger.id == 'sensor_on'` so clearing
  a sensor no longer fires a stray notification when another sensor
  is still active.
- Replace `binary_sensors.index()` (sandbox-restricted) with a
  namespace loop and drop the `sensor_index.__class__` reference
  that broke the [2/4] render.
- Drop `response_variable` from the notify call — it could abort
  the script past `continue_on_error` when the service didn't
  declare response support.
- Add `continue_on_error` on notify and alarm service calls so one
  misconfigured step doesn't cancel the whole automation.
- Tighten `has_notify_target`/`has_alarm_switch` to also reject
  whitespace, '[]', and 'None' string forms.

Version bumped 2.5.2 → 2.6.4.
2026-04-23 20:34:13 +03:00
alexei.dolgolyov 24f89e57b8 Replace deprecated target with chat_id in Telegram bot service calls
Fixes deprecation warning for HA 2026.9.0 where telegram_bot.send_message
`target` parameter is being removed in favor of `chat_id`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 00:46:17 +03:00
7 changed files with 459 additions and 156 deletions
+44 -1
View File
@@ -8,7 +8,50 @@ This blueprint monitors multiple binary sensors and triggers push notifications
- Debounce timer to prevent false alarms from brief sensor triggers - Debounce timer to prevent false alarms from brief sensor triggers
- Optional melody and volume selection for alarm devices - Optional melody and volume selection for alarm devices
- Automatic alarm turn-off when all sensors clear - Automatic alarm turn-off when all sensors clear
- Notifications are only sent on sensor ON (not on clear)
- Built-in debug mode that creates persistent notifications at each stage
## Debug Mode
Enable the **Debug****Enable Debug Logging** toggle to create persistent
notifications at each execution stage. Use this when notifications are not
reaching the target device:
1. **[1/4] Trigger Received** — shows trigger ID, entity, state transition,
which sensors are currently on, the resolved notify target, and whether
it is considered "usable" by the condition check.
2. **[2/4] Sending Notification** — shows the target entity, sensor index,
and the exact message that will be sent.
3. **[3/4] Notification Sent** — shown after the `notify.send_message` call.
Contains a troubleshooting checklist if the notification never arrives.
4. **[4/4] Alarm Control Done** — shows which alarm switch action was taken.
Additionally, stage info is written to the HA system log under the
`blueprint.alarm_notification` logger.
### Common causes of "no notification delivered"
- The notify integration is offline or the target device has notifications
disabled.
- `notify_target` is not actually a notify **entity**. Test from Developer
Tools → Actions → `notify.send_message` with the same target and
message; if that fails there, it will fail in the blueprint too.
- The sensor state change was shorter than the debounce duration and the
`sensor_on` trigger never fired. Temporarily set debounce to `0` to rule
this out.
- The notify integration rejects the message (e.g., Telegram bot with an
invalid `chat_id` in its configuration). Check the HA log for the
failing service call.
### Implementation note: notify via `notify.send_message`
The blueprint uses `action: notify.send_message` with
`target.entity_id: "{{ notify_target }}"`. This is the canonical modern HA
pattern and requires `notify_target` to be a notify **entity** (visible in
Developer Tools → States). Integrations that only register a `notify.<name>`
service but no entity are not supported by this blueprint directly — create
a notify entity for them or adapt the blueprint.
## Author ## Author
Alexei Dolgolyov (dolgolyov.alexei@gmail.com) Alexei Dolgolyov (<dolgolyov.alexei@gmail.com>)
+255 -31
View File
@@ -1,5 +1,5 @@
# Multi-Sensor Alarm & Notification Blueprint # Multi-Sensor Alarm & Notification Blueprint
# Monitors sensors and triggers notifications and alarms when activated. # Monitors sensors and triggers notifications and alarm actions when activated.
# See README.md for detailed documentation. # See README.md for detailed documentation.
blueprint: blueprint:
@@ -119,6 +119,23 @@ blueprint:
selector: selector:
text: text:
# -------------------------------------------------------------------------
# Debug Configuration
# -------------------------------------------------------------------------
debug_group:
name: "Debug"
collapsed: true
input:
debug_enabled:
name: Enable Debug Logging
description: >
When enabled, creates persistent notifications at each stage of execution:
trigger received, notification attempt, notification result, alarm control.
Use to troubleshoot why notifications aren't reaching the target.
default: false
selector:
boolean:
# Restart mode ensures rapid sensor changes are handled cleanly # Restart mode ensures rapid sensor changes are handled cleanly
mode: restart mode: restart
@@ -153,23 +170,31 @@ variables:
melody_id: !input melody_id melody_id: !input melody_id
volume_select: !input volume_select volume_select: !input volume_select
volume_id: !input volume_id volume_id: !input volume_id
is_debug: !input debug_enabled
# Computed state values # Computed state values
enabled_sensors: "{{ binary_sensors | select('is_state', 'on') | list }}" enabled_sensors: "{{ binary_sensors | select('is_state', 'on') | list }}"
is_any_sensor_on: "{{ enabled_sensors | length > 0 }}" is_any_sensor_on: "{{ (binary_sensors | select('is_state', 'on') | list | length) > 0 }}"
# Whether a usable notify target is configured
has_notify_target: "{{ notify_target is not none and (notify_target | string | trim) not in ['', '[]', 'None'] }}"
# Whether alarm control is configured
has_alarm_switch: "{{ alarm_switch is not none and (alarm_switch | string | trim) not in ['', '[]', 'None'] }}"
# Small delay between setting melody/volume to ensure device processes each command # Small delay between setting melody/volume to ensure device processes each command
delay_between_commands_ms: 100 delay_between_commands_ms: 100
# Debug flag - set to true to enable persistent notifications for troubleshooting # Version stamp so debug output can confirm which blueprint revision is live.
is_debug: false # Bump this whenever debug/flow logic changes.
blueprint_version: "2.6.4 (notify.send_message + entity_id)"
# ============================================================================= # =============================================================================
# Actions # Actions
# ============================================================================= # =============================================================================
action: action:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Debug Logging (optional) # Debug Stage 1: Trigger Received
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
- choose: - choose:
- conditions: - conditions:
@@ -178,45 +203,222 @@ action:
sequence: sequence:
- service: persistent_notification.create - service: persistent_notification.create
data: data:
title: "Alarm Notification Debug" notification_id: "alarm_debug_trigger"
title: "Alarm Debug [1/4]: Trigger Received"
message: > message: >
Trigger: {{ trigger.id }} Blueprint version: {{ blueprint_version }}
Trigger ID: {{ trigger.id }}
Entity: {{ trigger.entity_id }} Entity: {{ trigger.entity_id }}
Sensors: {{ binary_sensors }} From: {{ trigger.from_state.state if trigger.from_state is not none else 'n/a' }}
Active: {{ enabled_sensors }} → To: {{ trigger.to_state.state if trigger.to_state is not none else 'n/a' }}
Any On: {{ is_any_sensor_on }}
All monitored sensors: {{ binary_sensors }}
Currently active (on): {{ enabled_sensors }}
Any sensor on: {{ is_any_sensor_on }}
Notify target: {{ notify_target }}
Has notify target: {{ has_notify_target }}
Alarm switch: {{ alarm_switch }}
Has alarm switch: {{ has_alarm_switch }}
- service: system_log.write
data:
level: info
logger: blueprint.alarm_notification
message: >-
Trigger '{{ trigger.id }}' from {{ trigger.entity_id }};
active={{ enabled_sensors }};
notify_target={{ notify_target }};
has_notify_target={{ has_notify_target }}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Send Notification (when sensor turns ON) # Debug Stage 1.5: What the notification-branch conditions evaluate to
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
- choose: - choose:
- conditions: - conditions:
- condition: template - condition: template
# Only notify if a sensor is on and notification target is configured value_template: "{{ is_debug }}"
value_template: "{{ is_any_sensor_on and notify_target is not none }}" sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_pre_notify"
title: "Alarm Debug [1.5/4]: Evaluating notify conditions"
message: >
trigger.id = {{ trigger.id }}
trigger.id == 'sensor_on': {{ trigger.id == 'sensor_on' }}
has_notify_target: {{ has_notify_target }}
Combined (should be True to enter notify branch):
{{ trigger.id == 'sensor_on' and has_notify_target }}
# ---------------------------------------------------------------------------
# Send Notification (only on sensor_on, when target configured)
# ---------------------------------------------------------------------------
- choose:
- conditions:
# Single template condition avoids any quirks with condition: trigger
# inside a choose block.
- condition: template
value_template: "{{ trigger.id == 'sensor_on' and has_notify_target }}"
sequence: sequence:
- variables: - variables:
# Get the sensor that triggered this automation # The sensor that fired this trigger
sensor: "{{ trigger.entity_id }}" sensor: "{{ trigger.entity_id }}"
# Find index of this sensor in the list # Namespace-loop avoids Jinja sandbox restrictions on list.index()
sensor_index: > sensor_index: >-
{% set idx = binary_sensors | list %} {%- set ns = namespace(idx=-1) -%}
{{ idx.index(sensor) if sensor in idx else -1 }} {%- for s in binary_sensors -%}
# Get custom message or use default {%- if s == sensor -%}{%- set ns.idx = loop.index0 -%}{%- endif -%}
message: > {%- endfor -%}
{% set messages = notify_texts | list %} {{ ns.idx }}
{% if sensor_index >= 0 and sensor_index < messages | length %} # Resolve message (strip whitespace to keep notifications clean)
{{ messages[sensor_index] }} message: >-
{% else %} {%- set messages = notify_texts | list -%}
Alarm: {{ state_attr(sensor, 'friendly_name') | default(sensor) }} triggered {%- set idx = sensor_index | int(-1) -%}
{% endif %} {%- if idx >= 0 and idx < messages | length -%}
{{ messages[idx] }}
{%- else -%}
Alarm: {{ state_attr(sensor, 'friendly_name') or sensor }} triggered
{%- endif -%}
- service: notify.send_message # Debug Stage 2: Variables computed, about to send
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_notify_attempt"
title: "Alarm Debug [2/4]: Sending Notification"
message: >
Target: {{ notify_target }}
Sensor: {{ sensor }}
Sensor index (raw): "{{ sensor_index }}"
Messages defined: {{ notify_texts | length }}
Resolved message: "{{ message }}"
# Debug Stage 2.25: About to invoke service
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_pre_service"
title: "Alarm Debug [2.25/4]: Before notify.send_message"
message: >
Blueprint version: {{ blueprint_version }}
About to call: action notify.send_message
with target.entity_id: {{ notify_target }}
and data.message: "{{ message }}"
# Send via notify.send_message targeting the notify entity.
# This matches the canonical HA pattern used by working automations.
# continue_on_error ensures the alarm-control stage still runs
# if the notify integration is misconfigured.
- action: notify.send_message
metadata: {}
target: target:
entity_id: "{{ notify_target }}" entity_id: "{{ notify_target }}"
data: data:
message: "{{ message }}" message: "{{ message }}"
continue_on_error: true
# Debug Stage 2.75: Service call returned (success or caught error)
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_post_service"
title: "Alarm Debug [2.75/4]: After notify.send_message"
message: >
notify.send_message to {{ notify_target }} returned
(either success or continue_on_error caught it).
If this notification is missing but [2.25/4] is
present, the call raised an error that
continue_on_error did NOT catch. Check the HA log
and verify {{ notify_target }} is a notify entity
(Developer Tools → States should list it).
# Debug Stage 3: Notification result
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_notify_result"
title: "Alarm Debug [3/4]: Notification Sent"
message: >
notify.send_message dispatched to {{ notify_target }}
with message: "{{ message }}".
If nothing arrived on the device, check:
1) HA log for errors from the notify integration
2) That the underlying integration (Telegram bot,
mobile app, etc.) is online
3) Test from Developer Tools → Actions:
notify.send_message with target {{ notify_target }}
- service: system_log.write
data:
level: info
logger: blueprint.alarm_notification
message: >-
Notification attempted to {{ notify_target }};
sensor={{ sensor }}; message='{{ message }}'
# ---------------------------------------------------------------------------
# Debug Stage 3.5: Unconditional checkpoint so we can tell whether the
# notification branch silently aborted the script above. If this appears
# but [2/4] or [3/4] don't, the variables block or notify.send_message
# errored silently.
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_after_notify"
title: "Alarm Debug [3.5/4]: After notify branch"
message: >
Execution reached this point. trigger.id = {{ trigger.id }}.
If [2/4] and [3/4] did NOT appear above, the notify branch
either did not enter (check [1.5/4]), or errored silently
in the variables / notify.send_message step.
Check Home Assistant log for Jinja or service errors.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Alarm Device Control # Alarm Device Control
@@ -224,20 +426,20 @@ action:
- choose: - choose:
- conditions: - conditions:
- condition: template - condition: template
# Only control alarm if alarm switch is configured value_template: "{{ has_alarm_switch }}"
value_template: "{{ alarm_switch | length > 0 }}"
sequence: sequence:
# Set melody (if configured) # Set melody (if configured)
- choose: - choose:
- conditions: - conditions:
- condition: template - condition: template
value_template: "{{ melody_select | length > 0 and melody_id | length > 0 }}" value_template: "{{ melody_select is not none and (melody_select | string | trim) not in ['', '[]', 'None'] and (melody_id | string | length) > 0 }}"
sequence: sequence:
- service: select.select_option - service: select.select_option
target: target:
entity_id: "{{ melody_select }}" entity_id: "{{ melody_select }}"
data: data:
option: "{{ melody_id }}" option: "{{ melody_id }}"
continue_on_error: true
- delay: - delay:
milliseconds: "{{ delay_between_commands_ms }}" milliseconds: "{{ delay_between_commands_ms }}"
@@ -245,13 +447,14 @@ action:
- choose: - choose:
- conditions: - conditions:
- condition: template - condition: template
value_template: "{{ volume_select | length > 0 and volume_id | length > 0 }}" value_template: "{{ volume_select is not none and (volume_select | string | trim) not in ['', '[]', 'None'] and (volume_id | string | length) > 0 }}"
sequence: sequence:
- service: select.select_option - service: select.select_option
target: target:
entity_id: "{{ volume_select }}" entity_id: "{{ volume_select }}"
data: data:
option: "{{ volume_id }}" option: "{{ volume_id }}"
continue_on_error: true
- delay: - delay:
milliseconds: "{{ delay_between_commands_ms }}" milliseconds: "{{ delay_between_commands_ms }}"
@@ -265,9 +468,30 @@ action:
- service: switch.turn_on - service: switch.turn_on
target: target:
entity_id: "{{ alarm_switch }}" entity_id: "{{ alarm_switch }}"
continue_on_error: true
# All sensors clear -> turn alarm OFF # All sensors clear -> turn alarm OFF
default: default:
- service: switch.turn_off - service: switch.turn_off
target: target:
entity_id: "{{ alarm_switch }}" entity_id: "{{ alarm_switch }}"
continue_on_error: true
# Debug Stage 4: Alarm control done
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
notification_id: "alarm_debug_alarm_control"
title: "Alarm Debug [4/4]: Alarm Control Done"
message: >
Alarm switch: {{ alarm_switch }}
Action: {{ 'turn_on' if is_any_sensor_on else 'turn_off' }}
Melody: {{ melody_id }} → {{ melody_select }}
Volume: {{ volume_id }} → {{ volume_select }}
+21 -4
View File
@@ -1,6 +1,6 @@
# Dreame Vacuum Notifications # Dreame Vacuum Notifications
Sends customizable notifications for Dreame vacuum events. Requires the [Dreame Vacuum](https://github.com/Tasshack/dreame-vacuum) integration. Sends customizable notifications for Dreame vacuum events. Requires the [Dreame Vacuum](https://github.com/Tasshack/dreame-vacuum) integration and Home Assistant 2024.7+ (`notify.send_message` action).
## Features ## Features
@@ -9,7 +9,8 @@ Sends customizable notifications for Dreame vacuum events. Requires the [Dreame
- Device warning and error notifications - Device warning and error notifications
- Informational alerts (e.g., action blocked by Do Not Disturb) - Informational alerts (e.g., action blocked by Do Not Disturb)
- Individual toggle for each event type - Individual toggle for each event type
- Customizable message templates with variable substitution - Per-code filter lists for silencing routine warnings, errors, or info messages
- Customizable message templates
- Multiple notification targets - Multiple notification targets
## How It Works ## How It Works
@@ -24,7 +25,12 @@ The blueprint listens to events fired by the Dreame Vacuum integration:
| `dreame_vacuum_error` | Device fault | | `dreame_vacuum_error` | Device fault |
| `dreame_vacuum_information` | Action blocked by user settings | | `dreame_vacuum_information` | Action blocked by user settings |
Events are filtered by the configured vacuum entity, so only the selected vacuum triggers notifications. Events are filtered by the configured vacuum:
1. If the event payload includes `device_id`, it must match the device of the configured vacuum entity. This is the most reliable match.
2. Otherwise the entity_id in the event must equal the configured one, or equal it followed by a purely numeric suffix (e.g., `vacuum.dreame_x10_2`). The integration uses `generate_entity_id()`, so a numeric suffix can appear when the base entity_id is taken.
This avoids false positives when two vacuums share an entity_id prefix (e.g., `vacuum.dreame_x10` vs. `vacuum.dreame_x10_pro`).
## Configuration ## Configuration
@@ -33,8 +39,13 @@ Events are filtered by the configured vacuum entity, so only the selected vacuum
| **Vacuum Entity** | The Dreame vacuum entity to monitor | | **Vacuum Entity** | The Dreame vacuum entity to monitor |
| **Notification Targets** | One or more `notify` entities | | **Notification Targets** | One or more `notify` entities |
| **Event Toggles** | Enable/disable each event type independently | | **Event Toggles** | Enable/disable each event type independently |
| **Filtering** | Lists of warning/error/information codes to silence |
| **Message Templates** | Customizable message for each event type | | **Message Templates** | Customizable message for each event type |
### Filtering
Each filter input is a list of codes (as strings) that should not produce a notification. The blueprint compares the event's `code` field (cast to string) against the list. Use this to suppress noisy routine events while keeping critical ones.
## Message Template Variables ## Message Template Variables
### Cleaning Started ### Cleaning Started
@@ -84,10 +95,16 @@ Events are filtered by the configured vacuum entity, so only the selected vacuum
| --- | --- | | --- | --- |
| `{vacuum_name}` | Friendly name of the vacuum | | `{vacuum_name}` | Friendly name of the vacuum |
| `{information}` | Information message (e.g., Dust Collection, Cleaning Paused) | | `{information}` | Information message (e.g., Dust Collection, Cleaning Paused) |
| `{code}` | Information code |
## Notes
- The default messages contain emojis. Most modern notify integrations (Mobile App, Telegram, Discord) render them correctly; legacy SMS-based integrations may not.
- `notify.send_message` requires Home Assistant 2024.7 or newer.
## Debug Mode ## Debug Mode
Enable **Debug Notifications** in the Debug section to send persistent notifications with raw event data for troubleshooting. Enable **Debug Notifications** in the Debug section to send a persistent notification for every trigger. Each debug notification includes the blueprint version, dispatched event kind, and the enable decision — useful for confirming filters are doing what you expect. The notification is keyed per vacuum so debug entries from multiple vacuums do not overwrite each other.
## Author ## Author
+135 -116
View File
@@ -96,6 +96,41 @@ blueprint:
selector: selector:
boolean: boolean:
# -------------------------------------------------------------------------
# Filtering
# -------------------------------------------------------------------------
filters_group:
name: "Filtering"
collapsed: true
input:
warning_codes_ignore:
name: Warning Codes to Ignore
description: >
List of warning codes to silence (one entry per code, as text).
Useful for suppressing routine warnings while keeping critical ones.
default: []
selector:
text:
multiple: true
error_codes_ignore:
name: Error Codes to Ignore
description: >
List of error codes to silence (one entry per code, as text).
default: []
selector:
text:
multiple: true
information_codes_ignore:
name: Information Codes to Ignore
description: >
List of information codes to silence (one entry per code, as text).
default: []
selector:
text:
multiple: true
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Message Templates # Message Templates
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@@ -158,7 +193,7 @@ blueprint:
name: "Information Message" name: "Information Message"
description: > description: >
Message sent for informational alerts. Message sent for informational alerts.
Variables: `{vacuum_name}`, `{information}` Variables: `{vacuum_name}`, `{information}`, `{code}`
default: "️ {vacuum_name}: {information}." default: "️ {vacuum_name}: {information}."
selector: selector:
text: text:
@@ -175,7 +210,7 @@ blueprint:
name: Enable Debug Notifications name: Enable Debug Notifications
description: > description: >
Send persistent notifications for debugging automation behavior. Send persistent notifications for debugging automation behavior.
Shows raw event data and filtering decisions. Shows raw event data, dispatched event kind, and the enable decision.
default: false default: false
selector: selector:
boolean: boolean:
@@ -217,6 +252,10 @@ trigger:
# VARIABLES # VARIABLES
# ============================================================================= # =============================================================================
variables: variables:
# Bumped whenever event-handling logic changes; surfaced in debug output
# so users can confirm which revision is running.
blueprint_version: "1.1.1"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Input References # Input References
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -232,6 +271,11 @@ variables:
enable_error: !input enable_error enable_error: !input enable_error
enable_information: !input enable_information enable_information: !input enable_information
# Filter lists (lists of strings)
warning_codes_ignore: !input warning_codes_ignore
error_codes_ignore: !input error_codes_ignore
information_codes_ignore: !input information_codes_ignore
# Message templates # Message templates
message_cleaning_started_template: !input message_cleaning_started message_cleaning_started_template: !input message_cleaning_started
message_cleaning_completed_template: !input message_cleaning_completed message_cleaning_completed_template: !input message_cleaning_completed
@@ -244,11 +288,13 @@ variables:
# Vacuum Info # Vacuum Info
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
vacuum_name: "{{ state_attr(vacuum_entity, 'friendly_name') | default(vacuum_entity) }}" vacuum_name: "{{ state_attr(vacuum_entity, 'friendly_name') | default(vacuum_entity) }}"
vacuum_device: "{{ device_id(vacuum_entity) | default('', true) }}"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Event Data (flat structure — fields are directly on trigger.event.data) # Event Data (flat structure — fields are directly on trigger.event.data)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
event_entity_id: "{{ trigger.event.data.entity_id | default('') }}" event_entity_id: "{{ trigger.event.data.entity_id | default('') }}"
event_device_id: "{{ trigger.event.data.device_id | default('') }}"
# Task status fields # Task status fields
task_cleaning_mode: "{{ trigger.event.data.cleaning_mode | default('unknown') }}" task_cleaning_mode: "{{ trigger.event.data.cleaning_mode | default('unknown') }}"
@@ -270,19 +316,88 @@ variables:
# Information fields # Information fields
information_description: "{{ (trigger.event.data.information | default('unknown')) | replace('_', ' ') | title }}" information_description: "{{ (trigger.event.data.information | default('unknown')) | replace('_', ' ') | title }}"
information_code: "{{ trigger.event.data.code | default('') }}"
# ---------------------------------------------------------------------------
# Event Dispatch
# ---------------------------------------------------------------------------
# Map the raw trigger to a single logical event kind. Keeping this in one
# place avoids the duplicated condition logic that the old multi-branch
# `choose` had.
event_kind: >
{%- if trigger.id == 'task_status' and not task_completed -%}cleaning_started
{%- elif trigger.id == 'task_status' and task_completed -%}cleaning_completed
{%- elif trigger.id == 'consumable' -%}consumable
{%- elif trigger.id == 'warning' -%}warning
{%- elif trigger.id == 'error' -%}error
{%- elif trigger.id == 'information' -%}information
{%- else -%}none
{%- endif -%}
# Whether this event should produce a notification, given user toggles
# and any per-code filter lists. Coerce with `| bool(false)` at the
# consumer because folded scalars can render as the string "True"/"False".
event_enabled: >
{%- if event_kind == 'cleaning_started' -%}{{ enable_cleaning_started }}
{%- elif event_kind == 'cleaning_completed' -%}{{ enable_cleaning_completed }}
{%- elif event_kind == 'consumable' -%}{{ enable_consumable }}
{%- elif event_kind == 'warning' -%}{{ enable_warning and (warning_code | string) not in warning_codes_ignore }}
{%- elif event_kind == 'error' -%}{{ enable_error and (error_code | string) not in error_codes_ignore }}
{%- elif event_kind == 'information' -%}{{ enable_information and (information_code | string) not in information_codes_ignore }}
{%- else -%}False
{%- endif -%}
# Pick the per-event message template.
message_template: >
{%- if event_kind == 'cleaning_started' -%}{{ message_cleaning_started_template }}
{%- elif event_kind == 'cleaning_completed' -%}{{ message_cleaning_completed_template }}
{%- elif event_kind == 'consumable' -%}{{ message_consumable_template }}
{%- elif event_kind == 'warning' -%}{{ message_warning_template }}
{%- elif event_kind == 'error' -%}{{ message_error_template }}
{%- elif event_kind == 'information' -%}{{ message_information_template }}
{%- else -%}{%- endif -%}
# Render the message. Placeholders that don't apply to this event are
# absent from the chosen template, so `replace()` is a no-op for them.
message: >
{%- set code_for_event = warning_code if event_kind == 'warning'
else (error_code if event_kind == 'error'
else (information_code if event_kind == 'information' else '')) -%}
{{ message_template
| replace('{vacuum_name}', vacuum_name)
| replace('{cleaning_mode}', task_cleaning_mode)
| replace('{status}', task_status_value)
| replace('{cleaned_area}', task_cleaned_area | string)
| replace('{cleaning_time}', task_cleaning_time | string)
| replace('{consumable}', consumable_name)
| replace('{warning}', warning_description)
| replace('{error}', error_description)
| replace('{information}', information_description)
| replace('{code}', code_for_event | string) }}
# ============================================================================= # =============================================================================
# CONDITIONS # CONDITIONS
# ============================================================================= # =============================================================================
condition: condition:
# Only process events from the configured vacuum entity. # Only process events from the configured vacuum.
# The Dreame Vacuum integration uses generate_entity_id() for the entity_id # Prefer device_id matching when the event payload carries it (most
# in event data, which may append a numeric suffix (e.g., _2) since the # reliable across firmware revisions and avoids prefix collisions when
# actual vacuum entity already occupies the base entity_id. # multiple Dreame vacuums share an entity_id stem).
# Fall back to entity_id matching: the integration uses generate_entity_id(),
# which may append a numeric suffix (e.g., `_2`) when the base entity_id
# is taken — so we accept the configured entity_id with an optional
# purely numeric suffix and reject non-numeric suffixes (e.g., `_pro`).
- condition: template - condition: template
value_template: > value_template: >
{{ event_entity_id == vacuum_entity {%- if event_device_id != '' and vacuum_device != '' -%}
or event_entity_id.startswith(vacuum_entity ~ '_') }} {{ event_device_id == vacuum_device }}
{%- elif event_entity_id == vacuum_entity -%}
true
{%- elif event_entity_id.startswith(vacuum_entity ~ '_') -%}
{{ event_entity_id[(vacuum_entity | length) + 1:].isdigit() }}
{%- else -%}
false
{%- endif -%}
# ============================================================================= # =============================================================================
# ACTIONS # ACTIONS
@@ -297,127 +412,31 @@ action:
- condition: template - condition: template
value_template: "{{ enable_debug_notifications }}" value_template: "{{ enable_debug_notifications }}"
sequence: sequence:
- service: persistent_notification.create - action: persistent_notification.create
data: data:
title: "Dreame Vacuum Debug" notification_id: "dreame_vacuum_debug_{{ vacuum_entity }}"
title: "Dreame Vacuum Debug — {{ vacuum_name }}"
message: > message: >
**Blueprint version:** {{ blueprint_version }}
**Trigger:** {{ trigger.id }} **Trigger:** {{ trigger.id }}
**Event kind:** {{ event_kind }}
**Enabled:** {{ event_enabled }}
**Entity:** {{ event_entity_id }} **Entity:** {{ event_entity_id }}
**Device:** {{ event_device_id }}
**Vacuum:** {{ vacuum_name }} **Vacuum:** {{ vacuum_name }}
**Event Data:** {{ trigger.event.data }} **Event Data:** {{ trigger.event.data }}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Send Notification Based on Event Type # Send Notification
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Single dispatch — message and the enable decision are computed in the
# variables block above. We just gate on the resolved flags here.
- choose: - choose:
# CASE 1: Cleaning Started
- conditions: - conditions:
- condition: template - condition: template
value_template: > value_template: "{{ event_kind != 'none' and (event_enabled | bool(false)) }}"
{{ trigger.id == 'task_status'
and not task_completed
and enable_cleaning_started }}
sequence: sequence:
- variables: - action: notify.send_message
message: >
{% set tpl = message_cleaning_started_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{cleaning_mode}', task_cleaning_mode)
| replace('{status}', task_status_value) }}
- service: notify.send_message
target:
entity_id: "{{ notify_targets }}"
data:
message: "{{ message }}"
# CASE 2: Cleaning Completed
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'task_status'
and task_completed
and enable_cleaning_completed }}
sequence:
- variables:
message: >
{% set tpl = message_cleaning_completed_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{cleaning_mode}', task_cleaning_mode)
| replace('{status}', task_status_value)
| replace('{cleaned_area}', task_cleaned_area | string)
| replace('{cleaning_time}', task_cleaning_time | string) }}
- service: notify.send_message
target:
entity_id: "{{ notify_targets }}"
data:
message: "{{ message }}"
# CASE 3: Consumable Depleted
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'consumable' and enable_consumable }}
sequence:
- variables:
message: >
{% set tpl = message_consumable_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{consumable}', consumable_name) }}
- service: notify.send_message
target:
entity_id: "{{ notify_targets }}"
data:
message: "{{ message }}"
# CASE 4: Warning
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'warning' and enable_warning }}
sequence:
- variables:
message: >
{% set tpl = message_warning_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{warning}', warning_description)
| replace('{code}', warning_code | string) }}
- service: notify.send_message
target:
entity_id: "{{ notify_targets }}"
data:
message: "{{ message }}"
# CASE 5: Error
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'error' and enable_error }}
sequence:
- variables:
message: >
{% set tpl = message_error_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{error}', error_description)
| replace('{code}', error_code | string) }}
- service: notify.send_message
target:
entity_id: "{{ notify_targets }}"
data:
message: "{{ message }}"
# CASE 6: Information
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'information' and enable_information }}
sequence:
- variables:
message: >
{% set tpl = message_information_template %}
{{ tpl | replace('{vacuum_name}', vacuum_name)
| replace('{information}', information_description) }}
- service: notify.send_message
target: target:
entity_id: "{{ notify_targets }}" entity_id: "{{ notify_targets }}"
data: data:
+1 -1
View File
@@ -242,5 +242,5 @@ action:
sequence: sequence:
- service: telegram_bot.send_message - service: telegram_bot.send_message
data: data:
target: "{{ chat_id }}" chat_id: "{{ chat_id }}"
message: "{{ reply_message }}" message: "{{ reply_message }}"
+2 -2
View File
@@ -286,7 +286,7 @@ action:
sequence: sequence:
- service: telegram_bot.send_message - service: telegram_bot.send_message
data: data:
target: "{{ chat_id }}" chat_id: "{{ chat_id }}"
message: "{{ answers[button_index] }}" message: "{{ answers[button_index] }}"
# Reply to original message unless we're deleting it # Reply to original message unless we're deleting it
reply_to_message_id: > reply_to_message_id: >
@@ -397,7 +397,7 @@ action:
# Send the message with keyboard # Send the message with keyboard
- service: telegram_bot.send_message - service: telegram_bot.send_message
data: data:
target: "{{ result_chat_ids }}" chat_id: "{{ result_chat_ids }}"
message: "{{ message_text }}" message: "{{ message_text }}"
inline_keyboard: "{{ inline_keyboard }}" inline_keyboard: "{{ inline_keyboard }}"
config_entry_id: > config_entry_id: >
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"version": "2.5.2" "version": "2.9.1"
} }