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.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -9,7 +9,8 @@ Sends customizable notifications for Dreame vacuum events. Requires the [Dreame
|
||||
- Device warning and error notifications
|
||||
- Informational alerts (e.g., action blocked by Do Not Disturb)
|
||||
- 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
|
||||
|
||||
## 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_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
|
||||
|
||||
@@ -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 |
|
||||
| **Notification Targets** | One or more `notify` entities |
|
||||
| **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 |
|
||||
|
||||
### 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
|
||||
|
||||
### 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 |
|
||||
| `{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
|
||||
|
||||
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
|
||||
|
||||
|
||||
+135
-116
@@ -96,6 +96,41 @@ blueprint:
|
||||
selector:
|
||||
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
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -158,7 +193,7 @@ blueprint:
|
||||
name: "Information Message"
|
||||
description: >
|
||||
Message sent for informational alerts.
|
||||
Variables: `{vacuum_name}`, `{information}`
|
||||
Variables: `{vacuum_name}`, `{information}`, `{code}`
|
||||
default: "ℹ️ {vacuum_name}: {information}."
|
||||
selector:
|
||||
text:
|
||||
@@ -175,7 +210,7 @@ blueprint:
|
||||
name: Enable Debug Notifications
|
||||
description: >
|
||||
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
|
||||
selector:
|
||||
boolean:
|
||||
@@ -217,6 +252,10 @@ trigger:
|
||||
# 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
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -232,6 +271,11 @@ variables:
|
||||
enable_error: !input enable_error
|
||||
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_cleaning_started_template: !input message_cleaning_started
|
||||
message_cleaning_completed_template: !input message_cleaning_completed
|
||||
@@ -244,11 +288,13 @@ variables:
|
||||
# Vacuum Info
|
||||
# ---------------------------------------------------------------------------
|
||||
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_entity_id: "{{ trigger.event.data.entity_id | default('') }}"
|
||||
event_device_id: "{{ trigger.event.data.device_id | default('') }}"
|
||||
|
||||
# Task status fields
|
||||
task_cleaning_mode: "{{ trigger.event.data.cleaning_mode | default('unknown') }}"
|
||||
@@ -270,19 +316,88 @@ variables:
|
||||
|
||||
# Information fields
|
||||
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
|
||||
# =============================================================================
|
||||
condition:
|
||||
# Only process events from the configured vacuum entity.
|
||||
# The Dreame Vacuum integration uses generate_entity_id() for the entity_id
|
||||
# in event data, which may append a numeric suffix (e.g., _2) since the
|
||||
# actual vacuum entity already occupies the base entity_id.
|
||||
# Only process events from the configured vacuum.
|
||||
# Prefer device_id matching when the event payload carries it (most
|
||||
# reliable across firmware revisions and avoids prefix collisions when
|
||||
# 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
|
||||
value_template: >
|
||||
{{ event_entity_id == vacuum_entity
|
||||
or event_entity_id.startswith(vacuum_entity ~ '_') }}
|
||||
{%- if event_device_id != '' and vacuum_device != '' -%}
|
||||
{{ 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
|
||||
@@ -297,127 +412,31 @@ action:
|
||||
- condition: template
|
||||
value_template: "{{ enable_debug_notifications }}"
|
||||
sequence:
|
||||
- service: persistent_notification.create
|
||||
- action: persistent_notification.create
|
||||
data:
|
||||
title: "Dreame Vacuum Debug"
|
||||
notification_id: "dreame_vacuum_debug_{{ vacuum_entity }}"
|
||||
title: "Dreame Vacuum Debug — {{ vacuum_name }}"
|
||||
message: >
|
||||
**Blueprint version:** {{ blueprint_version }}
|
||||
**Trigger:** {{ trigger.id }}
|
||||
**Event kind:** {{ event_kind }}
|
||||
**Enabled:** {{ event_enabled }}
|
||||
**Entity:** {{ event_entity_id }}
|
||||
**Device:** {{ event_device_id }}
|
||||
**Vacuum:** {{ vacuum_name }}
|
||||
**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:
|
||||
|
||||
# CASE 1: Cleaning Started
|
||||
- conditions:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ trigger.id == 'task_status'
|
||||
and not task_completed
|
||||
and enable_cleaning_started }}
|
||||
value_template: "{{ event_kind != 'none' and (event_enabled | bool(false)) }}"
|
||||
sequence:
|
||||
- variables:
|
||||
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
|
||||
- action: notify.send_message
|
||||
target:
|
||||
entity_id: "{{ notify_targets }}"
|
||||
data:
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2.6.4"
|
||||
"version": "2.9.1"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user