e3b9b123f2
The Dreame integration names the vacuum entity ' <device name>' (leading space), so HA composes the entity friendly_name as the device name twice (e.g. 'Z10 Pro Z10 Pro'). Derive vacuum_name from the device's name_by_user/name instead, falling back to friendly_name then entity_id. Bump blueprint_version to 1.2.1 and manifest to 2.14.2.
573 lines
24 KiB
YAML
573 lines
24 KiB
YAML
# Dreame Vacuum Notifications
|
||
# Sends notifications for Dreame vacuum events (cleaning, errors, consumables).
|
||
# See README.md for detailed documentation.
|
||
#
|
||
# Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
|
||
|
||
blueprint:
|
||
name: "Custom: Dreame Vacuum Notifications"
|
||
description: >
|
||
Sends customizable notifications for Dreame vacuum events including
|
||
cleaning status, consumable alerts, warnings, and errors.
|
||
Requires the Dreame Vacuum integration (github.com/Tasshack/dreame-vacuum).
|
||
domain: automation
|
||
|
||
# ===========================================================================
|
||
# INPUT CONFIGURATION
|
||
# ===========================================================================
|
||
input:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Vacuum Configuration
|
||
# -------------------------------------------------------------------------
|
||
vacuum_group:
|
||
name: "Vacuum"
|
||
collapsed: false
|
||
input:
|
||
vacuum_entity:
|
||
name: Vacuum Entity
|
||
description: "The Dreame vacuum entity to monitor."
|
||
selector:
|
||
entity:
|
||
integration: dreame_vacuum
|
||
domain: vacuum
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Notification Configuration
|
||
# -------------------------------------------------------------------------
|
||
notification_group:
|
||
name: "Notification"
|
||
collapsed: false
|
||
input:
|
||
notify_targets:
|
||
name: Notification Targets
|
||
description: "Notification service entities to send messages to (select one or more)."
|
||
selector:
|
||
entity:
|
||
domain: notify
|
||
multiple: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Event Toggles
|
||
# -------------------------------------------------------------------------
|
||
toggles_group:
|
||
name: "Event Toggles"
|
||
collapsed: false
|
||
input:
|
||
enable_cleaning_started:
|
||
name: Cleaning Started
|
||
description: "Send notification when the vacuum starts cleaning."
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
enable_cleaning_completed:
|
||
name: Cleaning Completed
|
||
description: "Send notification when the vacuum finishes cleaning."
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
enable_consumable:
|
||
name: Consumable Depleted
|
||
description: "Send notification when a consumable reaches end-of-life."
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
enable_warning:
|
||
name: Warning
|
||
description: "Send notification for device warnings."
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
enable_error:
|
||
name: Error
|
||
description: "Send notification for device errors."
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
enable_information:
|
||
name: Information
|
||
description: "Send notification for informational alerts (e.g., blocked by DND)."
|
||
default: true
|
||
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 Types to Ignore
|
||
description: >
|
||
List of information message types to silence (one entry per type).
|
||
Information events carry a type id, not a numeric code.
|
||
Valid values: dust_collection, cleaning_paused.
|
||
default: []
|
||
selector:
|
||
text:
|
||
multiple: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Message Templates
|
||
# -------------------------------------------------------------------------
|
||
messages_group:
|
||
name: "Message Templates"
|
||
collapsed: true
|
||
input:
|
||
message_cleaning_started:
|
||
name: "Cleaning Started Message"
|
||
description: >
|
||
Message sent when the vacuum starts cleaning.
|
||
Variables: `{vacuum_name}`, `{cleaning_mode}`, `{status}`
|
||
default: "🧹 {vacuum_name} started cleaning ({cleaning_mode})."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_cleaning_completed:
|
||
name: "Cleaning Completed Message"
|
||
description: >
|
||
Message sent when the vacuum finishes cleaning.
|
||
Variables: `{vacuum_name}`, `{cleaning_mode}`, `{status}`,
|
||
`{cleaned_area}`, `{cleaning_time}`
|
||
default: "✅ {vacuum_name} finished cleaning. Area: {cleaned_area} m², time: {cleaning_time} min."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_consumable:
|
||
name: "Consumable Depleted Message"
|
||
description: >
|
||
Message sent when a consumable reaches end-of-life.
|
||
Variables: `{vacuum_name}`, `{consumable}`
|
||
default: "🔧 {vacuum_name}: {consumable} needs replacement."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_warning:
|
||
name: "Warning Message"
|
||
description: >
|
||
Message sent for device warnings.
|
||
Variables: `{vacuum_name}`, `{warning}`, `{code}`, `{code_name}`
|
||
default: "⚠️ {vacuum_name} warning: {warning} (code: {code})."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_error:
|
||
name: "Error Message"
|
||
description: >
|
||
Message sent for device errors.
|
||
Variables: `{vacuum_name}`, `{error}`, `{code}`, `{code_name}`
|
||
default: "❌ {vacuum_name} error: {error} (code: {code})."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_information:
|
||
name: "Information Message"
|
||
description: >
|
||
Message sent for informational alerts.
|
||
Variables: `{vacuum_name}`, `{information}`
|
||
default: "ℹ️ {vacuum_name}: {information}."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Localization / Label Overrides
|
||
# -------------------------------------------------------------------------
|
||
localization_group:
|
||
name: "Localization"
|
||
collapsed: true
|
||
input:
|
||
label_overrides:
|
||
name: "Label Overrides"
|
||
description: >
|
||
Optional translation/relabel table for dynamic values, as YAML
|
||
key/value pairs. Keys are the raw values the integration emits
|
||
(cleaning mode / status are UPPER_SNAKE enum names; consumable /
|
||
information are lower-case ids); values are your preferred text in
|
||
any language. Applied to {cleaning_mode}, {status}, {consumable}
|
||
and {information}. Example:
|
||
SWEEPING_AND_MOPPING: Подметание и мытьё
|
||
CLEANING: Уборка
|
||
BACK_HOME: Возврат на базу
|
||
dust_collection: Очистка контейнера
|
||
default: {}
|
||
selector:
|
||
object:
|
||
|
||
code_label_overrides:
|
||
name: "Warning/Error Code Labels"
|
||
description: >
|
||
Optional table mapping a numeric warning/error code to a short
|
||
label, exposed as the {code_name} placeholder. Leave empty to omit
|
||
{code_name}. Use unquoted numbers as keys. Example:
|
||
68: Снять швабру
|
||
47: Робот застрял
|
||
default: {}
|
||
selector:
|
||
object:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Debug
|
||
# -------------------------------------------------------------------------
|
||
debug:
|
||
name: "Debug"
|
||
collapsed: true
|
||
input:
|
||
enable_debug_notifications:
|
||
name: Enable Debug Notifications
|
||
description: >
|
||
Send persistent notifications for debugging automation behavior.
|
||
Shows raw event data, dispatched event kind, and the enable decision.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
# Queued mode to avoid dropping rapid events. A single cleanup-completion pass
|
||
# can fire up to 8 events (1 task_status + 7 consumables), so queue up to 10.
|
||
mode: queued
|
||
max: 10
|
||
|
||
# =============================================================================
|
||
# TRIGGERS
|
||
# =============================================================================
|
||
trigger:
|
||
# Cleaning job started or completed
|
||
- platform: event
|
||
event_type: dreame_vacuum_task_status
|
||
id: "task_status"
|
||
|
||
# Consumable reached end-of-life
|
||
- platform: event
|
||
event_type: dreame_vacuum_consumable
|
||
id: "consumable"
|
||
|
||
# Informational alert (job blocked by user settings)
|
||
- platform: event
|
||
event_type: dreame_vacuum_information
|
||
id: "information"
|
||
|
||
# Dismissible device warning
|
||
- platform: event
|
||
event_type: dreame_vacuum_warning
|
||
id: "warning"
|
||
|
||
# Device fault
|
||
- platform: event
|
||
event_type: dreame_vacuum_error
|
||
id: "error"
|
||
|
||
# =============================================================================
|
||
# VARIABLES
|
||
# =============================================================================
|
||
variables:
|
||
# Bumped whenever event-handling logic changes; surfaced in debug output
|
||
# so users can confirm which revision is running.
|
||
blueprint_version: "1.2.1"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Input References
|
||
# ---------------------------------------------------------------------------
|
||
vacuum_entity: !input vacuum_entity
|
||
enable_debug_notifications: !input enable_debug_notifications
|
||
|
||
# Event toggles
|
||
enable_cleaning_started: !input enable_cleaning_started
|
||
enable_cleaning_completed: !input enable_cleaning_completed
|
||
enable_consumable: !input enable_consumable
|
||
enable_warning: !input enable_warning
|
||
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
|
||
message_consumable_template: !input message_consumable
|
||
message_warning_template: !input message_warning
|
||
message_error_template: !input message_error
|
||
message_information_template: !input message_information
|
||
|
||
# Localization overrides (dicts; default to empty mappings)
|
||
label_overrides: !input label_overrides
|
||
code_label_overrides: !input code_label_overrides
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Vacuum Info
|
||
# ---------------------------------------------------------------------------
|
||
# Prefer the device name (clean, single) over the entity's friendly_name.
|
||
# The Dreame integration names the vacuum entity " <device name>" (leading
|
||
# space) which Home Assistant composes into the friendly_name, so
|
||
# friendly_name renders the device name twice (e.g. "Z10 Pro Z10 Pro").
|
||
# Use the device's user-set/original name; fall back to friendly_name, then
|
||
# the entity_id.
|
||
vacuum_name: >
|
||
{%- set did = device_id(vacuum_entity) -%}
|
||
{%- set dname = (device_attr(did, 'name_by_user') or device_attr(did, 'name')) if did else none -%}
|
||
{{ dname if dname else (state_attr(vacuum_entity, 'friendly_name') | default(vacuum_entity, true)) }}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Event Data (flat structure — fields are directly on trigger.event.data)
|
||
# ---------------------------------------------------------------------------
|
||
event_entity_id: "{{ trigger.event.data.entity_id | default('') }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Friendly label maps
|
||
# ---------------------------------------------------------------------------
|
||
# The integration emits cleaning_mode and status as raw UPPER_SNAKE enum
|
||
# names (e.g. SWEEPING_AND_MOPPING, SEGMENT_CLEANING). These maps translate
|
||
# them to readable text. Lookup order at the call site is:
|
||
# user label_overrides -> built-in map below -> generic humanizer.
|
||
cleaning_mode_labels:
|
||
UNKNOWN: "Unknown"
|
||
SWEEPING: "Sweeping"
|
||
MOPPING: "Mopping"
|
||
SWEEPING_AND_MOPPING: "Sweeping & Mopping"
|
||
status_labels:
|
||
UNKNOWN: "Unknown"
|
||
IDLE: "Idle"
|
||
PAUSED: "Paused"
|
||
CLEANING: "Cleaning"
|
||
BACK_HOME: "Returning to dock"
|
||
PART_CLEANING: "Spot cleaning"
|
||
FOLLOW_WALL: "Following wall"
|
||
CHARGING: "Charging"
|
||
OTA: "Updating firmware"
|
||
FCT: "Factory check"
|
||
WIFI_SET: "Wi-Fi setup"
|
||
POWER_OFF: "Powered off"
|
||
FACTORY: "Factory mode"
|
||
ERROR: "Error"
|
||
REMOTE_CONTROL: "Remote control"
|
||
SLEEPING: "Sleeping"
|
||
SELF_TEST: "Self test"
|
||
FACTORY_FUNCION_TEST: "Factory function test"
|
||
STANDBY: "Standby"
|
||
SEGMENT_CLEANING: "Room cleaning"
|
||
ZONE_CLEANING: "Zone cleaning"
|
||
SPOT_CLEANING: "Spot cleaning"
|
||
FAST_MAPPING: "Mapping"
|
||
MONITOR_CRUISE: "Patrolling"
|
||
MONITOR_SPOT: "Spot monitoring"
|
||
SUMMON_CLEAN: "Summon clean"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Task status fields
|
||
# ---------------------------------------------------------------------------
|
||
# Raw enum names as fired by the integration.
|
||
task_cleaning_mode_raw: "{{ trigger.event.data.cleaning_mode | default('UNKNOWN') }}"
|
||
task_status_raw: "{{ trigger.event.data.status | default('UNKNOWN') }}"
|
||
# Friendly values: override -> built-in map -> generic humanizer fallback.
|
||
task_cleaning_mode: "{{ (label_overrides or {}).get(task_cleaning_mode_raw, cleaning_mode_labels.get(task_cleaning_mode_raw, task_cleaning_mode_raw | replace('_', ' ') | title)) }}"
|
||
task_status_value: "{{ (label_overrides or {}).get(task_status_raw, status_labels.get(task_status_raw, task_status_raw | replace('_', ' ') | title)) }}"
|
||
# Coerce to a real bool so the started/completed dispatch stays correct.
|
||
task_completed: "{{ trigger.event.data.completed | default(false) | bool(false) }}"
|
||
task_cleaned_area: "{{ trigger.event.data.cleaned_area | default(0) }}"
|
||
task_cleaning_time: "{{ trigger.event.data.cleaning_time | default(0) }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Consumable fields
|
||
# ---------------------------------------------------------------------------
|
||
consumable_name: "{{ (label_overrides or {}).get(trigger.event.data.consumable | default('unknown'), (trigger.event.data.consumable | default('unknown')) | replace('_', ' ') | title) }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Warning fields
|
||
# ---------------------------------------------------------------------------
|
||
# Most warnings carry a short English description; the temporary-map events
|
||
# instead carry a bare snake id or a markdown blob. Humanize a bare id (and
|
||
# honor overrides) while leaving descriptive text / markdown untouched.
|
||
warning_description: >
|
||
{%- set w = trigger.event.data.warning | default('unknown') -%}
|
||
{%- if w and ' ' not in w and '#' not in w -%}{{ (label_overrides or {}).get(w, w | replace('_', ' ') | title) }}{%- else -%}{{ w }}{%- endif -%}
|
||
warning_code: "{{ trigger.event.data.code | default('') }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Error fields
|
||
# ---------------------------------------------------------------------------
|
||
error_description: "{{ trigger.event.data.error | default('unknown') }}"
|
||
error_code: "{{ trigger.event.data.code | default('') }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Code label (optional, localized)
|
||
# ---------------------------------------------------------------------------
|
||
# Numeric warning/error code as fired (empty for code-less events). code_name
|
||
# is the localized label for that code, exposed as {code_name}: a user override
|
||
# if present, otherwise the integration's own English description, otherwise
|
||
# empty. No built-in numeric code table is shipped, so there is no risk of
|
||
# stale labels across integration versions.
|
||
event_code: "{{ trigger.event.data.code | default('') }}"
|
||
code_name: >
|
||
{%- set lbl = (code_label_overrides or {}).get(event_code, (code_label_overrides or {}).get(event_code | string, '')) -%}
|
||
{%- if lbl -%}{{ lbl }}
|
||
{%- elif trigger.id == 'warning' -%}{{ warning_description }}
|
||
{%- elif trigger.id == 'error' -%}{{ error_description }}
|
||
{%- endif -%}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Information fields
|
||
# ---------------------------------------------------------------------------
|
||
information_description: "{{ (label_overrides or {}).get(trigger.event.data.information | default('unknown'), (trigger.event.data.information | default('unknown')) | replace('_', ' ') | title) }}"
|
||
# Information events carry a type id (e.g. dust_collection), never a numeric
|
||
# code — this raw id drives the Information ignore filter.
|
||
information_code: "{{ trigger.event.data.information | 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".
|
||
# The warning branch also drops the integration's spurious "replace_temporary_map"
|
||
# clear event (fired with no code, including on every restart).
|
||
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 (trigger.event.data.warning | default('')) != 'replace_temporary_map' 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.
|
||
# {vacuum_name} is substituted last (it is the only user-controlled value)
|
||
# so a friendly name containing a literal token cannot be re-expanded. The
|
||
# final regex strips an empty "(label: )" parenthetical in any language left
|
||
# by a code-less event, e.g. "(code: )" or "(код предупреждения: )".
|
||
message: >
|
||
{%- set code_for_event = warning_code if event_kind == 'warning'
|
||
else (error_code if event_kind == 'error' else '') -%}
|
||
{%- set rendered = message_template
|
||
| 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_name}', code_name)
|
||
| replace('{code}', code_for_event | string)
|
||
| replace('{vacuum_name}', vacuum_name) -%}
|
||
{{ rendered | regex_replace('\\s*\\(\\s*[^():]*:\\s*\\)', '') }}
|
||
|
||
# =============================================================================
|
||
# CONDITIONS
|
||
# =============================================================================
|
||
condition:
|
||
# Only process events from the configured vacuum. The integration fires every
|
||
# event with an `entity_id` derived from the device NAME via generate_entity_id()
|
||
# — events never carry a `device_id`, so matching is entity_id based.
|
||
# generate_entity_id() may append a purely numeric suffix (e.g. `_2`) when the
|
||
# base id is already taken, so we accept the configured entity_id exactly, or
|
||
# followed by a purely-numeric suffix, and reject non-numeric suffixes (e.g. `_pro`).
|
||
- condition: template
|
||
value_template: >
|
||
{%- if event_entity_id == '' -%}
|
||
false
|
||
{%- 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
|
||
# =============================================================================
|
||
action:
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Debug Logging
|
||
# ---------------------------------------------------------------------------
|
||
- if:
|
||
- condition: template
|
||
value_template: "{{ enable_debug_notifications }}"
|
||
then:
|
||
- action: persistent_notification.create
|
||
data:
|
||
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 }}
|
||
**Vacuum:** {{ vacuum_name }}
|
||
**Event Data:** {{ trigger.event.data }}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Send Notification
|
||
# ---------------------------------------------------------------------------
|
||
# Single dispatch — message and the enable decision are computed in the
|
||
# variables block above. We just gate on the resolved flags here.
|
||
- if:
|
||
- condition: template
|
||
value_template: "{{ event_kind != 'none' and (event_enabled | bool(false)) }}"
|
||
then:
|
||
- action: notify.send_message
|
||
target:
|
||
entity_id: !input notify_targets
|
||
data:
|
||
message: "{{ message }}"
|