Files
haos-blueprints/Common/Washing Machine.yaml

676 lines
28 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# Washing Machine / Dryer Notifications Blueprint for Home Assistant
# =============================================================================
# This blueprint monitors washing machine or dryer appliances and sends
# notifications for various events throughout the wash/dry cycle.
#
# Features:
# - Start notification with cycle duration and mode details
# - Completion notification (reminder to unload clothes)
# - "Almost done" notification (configurable minutes before end)
# - Error message notifications
# - Preparation mode notification (e.g., for dryer prep)
# - Tub/drum cleaning reminder based on wash counter
# - Fully customizable notification messages (i18n support)
#
# State Machine:
# The automation tracks the appliance through these states:
# 1. IDLE: Waiting for cycle to start
# 2. RUNNING: Cycle in progress (start notification sent)
# 3. FINISHING: Near completion (time-to-end notification sent)
# 4. COMPLETED: Cycle done (completion notification sent, state reset)
#
# Persistent State Keys:
# - nass: Notification About Start Sent
# - nart: Notification About Remaining Time Sent
# - naps: Notification About Preparation Sent
#
# Message Template Variables:
# All message templates support Jinja2 templating with these variables:
# - {{ device_name }} - Device name (e.g., "Washing Machine")
# - {{ remaining }} - Remaining time as string (e.g., "01:30:00")
# - {{ minutes }} - Remaining minutes as number (e.g., 90)
# - {{ error }} - Error message text (only in error notification)
# - {{ tub_count }} - Tub clean counter value (only in tub clean notification)
# - {{ tub_threshold }}- Tub clean threshold (only in tub clean notification)
# - {{ details }} - Startup details from sensors (only in start notification)
#
# Requirements:
# - Sensors for: remaining time, run state, error messages
# - input_text entity for persistent state storage
# - Notification service entity
#
# Note: Default messages are in Russian for LG ThinQ integration.
# Customize messages in the "Messages" section for your language.
#
# Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
# =============================================================================
blueprint:
name: "Custom: Washing Machine Notifications"
description: >
Sends notifications when washing starts (with mode details),
when errors occur, and when run completes.
domain: automation
# ===========================================================================
# INPUT CONFIGURATION
# ===========================================================================
input:
# -------------------------------------------------------------------------
# Time & State Sensors
# -------------------------------------------------------------------------
# Core sensors for tracking the appliance cycle state
time_group:
name: "Time"
collapsed: false
input:
remaining_time_sensor:
name: Remaining Time Sensor
description: >
Sensor that contains remaining time in format `hh:mm:ss`.
Note: `-`, 'unknown' values mean remaining time is not available.
selector:
entity:
domain: sensor
run_state_sensor:
name: Run State Sensor
description: "Sensor that reports the run state of the device"
selector:
entity:
domain: sensor
run_state_completion_id:
name: Run State Completion ID
description: "Identifier of run state that indicates that the cycle is completed"
default: 'Цикл завершен.'
selector:
text:
notify_time_to_end:
name: Notify Time-to-End (minutes)
description: "Send notification when cycle is about to finish (minutes remaining)"
default: 10
selector:
number:
min: 1
max: 60
unit_of_measurement: minutes
mode: slider
# -------------------------------------------------------------------------
# Persistent State Configuration
# -------------------------------------------------------------------------
# Stores automation state between triggers to track notification history
persistent_state:
name: "Persistent State"
collapsed: false
input:
automation_state_entity:
name: Automation state entity
description: >
`input_text` entity that stores the automation state in JSON format.
Required for all features to function properly.
Doesn't require specific initial state - values can be empty.
selector:
entity:
domain: input_text
automation_state_placeholder_key:
name: Automation state placeholder key
description: >
Overrides key for persistent storage if not empty.
By default uses the remaining time sensor entity ID.
Don't override if you don't understand the meaning.
default: ''
selector:
text:
# -------------------------------------------------------------------------
# Notification Settings
# -------------------------------------------------------------------------
notification_group:
name: "Notification"
collapsed: false
input:
input_device_name:
name: "Device Name"
description: "Device name used in notification messages (available as {{ device_name }} in templates)"
default: "Стиральная машина"
selector:
text:
notify_target:
name: Notification Target
description: "Notification service entity to send messages to"
selector:
entity:
domain: notify
# -------------------------------------------------------------------------
# Message Templates (Customizable Notifications)
# -------------------------------------------------------------------------
# All messages support Jinja2 templates. Available variables depend on
# the notification type - see header comments for full list.
messages_group:
name: "Messages"
collapsed: true
input:
message_start:
name: "Start Message"
description: >
Message sent when cycle starts.
Variables: {{ device_name }}, {{ remaining }}, {{ details }}
default: "🧺 {{ device_name }}: старт. Длительность: `{{ remaining }}`.{{ details }}"
selector:
text:
multiline: true
message_completed:
name: "Completed Message"
description: >
Message sent when cycle completes.
Variables: {{ device_name }}
default: "🟢 {{ device_name }}: завершено. Не забудьте достать вещи!"
selector:
text:
multiline: true
message_almost_done:
name: "Almost Done Message"
description: >
Message sent when cycle is about to finish.
Variables: {{ device_name }}, {{ minutes }}
default: "🟢 {{ device_name }}: завершение через {{ minutes }} минут."
selector:
text:
multiline: true
message_preparation:
name: "Preparation Message"
description: >
Message sent when device enters preparation mode.
Variables: {{ device_name }}
default: "⚙️ {{ device_name }}: подготовка активирована!"
selector:
text:
multiline: true
message_error:
name: "Error Message"
description: >
Message sent when an error occurs.
Variables: {{ device_name }}, {{ error }}
default: "⚠️ {{ device_name }}: ошибка. Детали: {{ error }}. Для более подробной информации обратитесь к приложению LG ThinQ."
selector:
text:
multiline: true
message_tub_clean:
name: "Tub Clean Reminder Message"
description: >
Message sent when tub cleaning is needed.
Variables: {{ device_name }}, {{ tub_count }}, {{ tub_threshold }}
default: "⚠️ {{ device_name }}: внимание. Необходима чистка барабана. Число стирок: {{ tub_count }}. Допустимый предел: {{ tub_threshold }}."
selector:
text:
multiline: true
# -------------------------------------------------------------------------
# Device Information Sensors
# -------------------------------------------------------------------------
info_group:
name: "Info"
collapsed: false
input:
non_running_state_ids:
name: Non Running State ID(s)
description: >
List of run state ID(s) that indicate the device is not actively
running a cycle (e.g., 'Pause', 'Standby', 'Ready')
default: []
selector:
text:
multiple: true
preparation_state_id:
name: Preparation Mode State ID (optional)
description: >
Optional run state ID that indicates the device is preparing
(e.g., dryer heating up before starting)
default: 'Подготовка к сушке'
selector:
text:
error_message_sensor:
name: Error Message Sensor
description: "Sensor that reports error messages from the device"
selector:
entity:
domain: sensor
tub_clean_counter_sensor:
name: Tub Clean Counter Sensor (optional)
description: "Sensor that reports the number of cycles since last tub cleaning"
selector:
entity:
domain:
- sensor
- input_number
tub_clean_counter_threshold:
name: Tub Clean Counter Threshold
description: >
Number of cycles after which a tub cleaning reminder is sent.
Set to 0 to disable tub cleaning notifications.
default: 30
selector:
number:
min: 0
max: 100
mode: slider
# -------------------------------------------------------------------------
# Startup Details (optional additional info in start notification)
# -------------------------------------------------------------------------
details_group:
name: "Details"
collapsed: false
input:
startup_info_sensors:
name: Startup Info Sensors (optional)
description: >
List of sensors with additional details to include in the
startup notification (e.g., temperature, spin speed, program)
default: []
selector:
entity:
domain:
- sensor
- binary_sensor
multiple: true
startup_info_texts:
name: Startup Info Texts
description: >
Labels for each sensor in `Startup Info Sensors` list.
Must have the same number of entries as sensors.
default: []
selector:
text:
multiple: true
# =============================================================================
# AUTOMATION MODE
# =============================================================================
# Restart mode ensures new triggers interrupt any running automation
# (useful for rapid state changes)
mode: restart
# =============================================================================
# TRIGGERS
# =============================================================================
# Monitor all relevant sensors for state changes
trigger:
# Remaining time changes (tracks cycle progress)
- platform: state
entity_id: !input remaining_time_sensor
# Error message appears
- platform: state
entity_id: !input error_message_sensor
# Run state changes (start, stop, pause, etc.)
- platform: state
entity_id: !input run_state_sensor
# Tub clean counter changed
- platform: state
entity_id: !input tub_clean_counter_sensor
# =============================================================================
# CONDITIONS
# =============================================================================
# No global conditions - individual cases handle their own logic
condition: []
# =============================================================================
# VARIABLES
# =============================================================================
variables:
# ---------------------------------------------------------------------------
# Persistent State Keys
# ---------------------------------------------------------------------------
# Short keys to minimize JSON storage size in input_text entity
state_notification_about_remaining_time_sent: 'nart' # "Almost done" notification sent
state_notification_about_start_sent: 'nass' # Start notification sent
state_notification_about_preparation_sent: 'naps' # Preparation notification sent
# ---------------------------------------------------------------------------
# Input Variables
# ---------------------------------------------------------------------------
run_state_sensor: !input run_state_sensor
non_running_state_ids: !input non_running_state_ids
preparation_state_id: !input preparation_state_id
error_message_sensor: !input error_message_sensor
remaining_time_sensor: !input remaining_time_sensor
notify_target: !input notify_target
notify_time_to_end: !input notify_time_to_end
input_device_name: !input input_device_name
tub_clean_counter_sensor: !input tub_clean_counter_sensor
tub_clean_counter_threshold: !input tub_clean_counter_threshold
run_state_completion_id: !input run_state_completion_id
# ---------------------------------------------------------------------------
# Message Templates
# ---------------------------------------------------------------------------
message_start_template: !input message_start
message_completed_template: !input message_completed
message_almost_done_template: !input message_almost_done
message_preparation_template: !input message_preparation
message_error_template: !input message_error
message_tub_clean_template: !input message_tub_clean
# ---------------------------------------------------------------------------
# Computed State Values
# ---------------------------------------------------------------------------
remaining: "{{ states(remaining_time_sensor) }}"
device_name: "{{ input_device_name }}"
run_state: "{{ states(run_state_sensor) }}"
# Determine if the appliance is actively running a cycle
# Excludes: unknown states, non-running states, preparation, and completion
is_running: >
{{ run_state not in ['unknown', 'unavailable', 'waiting', '-']
and run_state not in non_running_state_ids
and run_state != preparation_state_id
and run_state != run_state_completion_id
and remaining not in ['unknown', 'unavailable'] }}
# Parse remaining time string (hh:mm:ss) to total minutes
remaining_time_in_minutes: >
{% if remaining not in ['unknown', 'unavailable', '-'] %}
{% set parts = remaining.split(':') %}
{% if parts | length >= 2 %}
{% set total = parts[0]|int * 60 + parts[1]|int %}
{{ total }}
{% else %}
{{ 0 }}
{% endif %}
{% else %}
{{ 0 }}
{% endif %}
# ---------------------------------------------------------------------------
# Persistent State Management
# ---------------------------------------------------------------------------
automation_state_entity: !input automation_state_entity
# Parse global state JSON from input_text entity
automation_state_global: >
{% set text = states(automation_state_entity) | string %}
{% if text in ['unknown','unavailable','none',''] %}
{{ dict() }}
{% else %}
{{ text | from_json }}
{% endif %}
automation_state_placeholder_key: !input automation_state_placeholder_key
# Determine the key for this automation's state
automation_state_key: >
{% if automation_state_placeholder_key != '' %}
{{ automation_state_placeholder_key }}
{% else %}
{{ remaining_time_sensor }}
{% endif %}
# Get this automation's state from global state
automation_state: "{{ automation_state_global.get(automation_state_key, dict()) }}"
# ---------------------------------------------------------------------------
# Debug Flag
# ---------------------------------------------------------------------------
is_debug: false
# =============================================================================
# ACTIONS
# =============================================================================
action:
# ---------------------------------------------------------------------------
# DEBUG: Log current state (enable by setting is_debug: true)
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
title: "Debug Info - Washing Machine"
message: >
run_state = {{ run_state }},
non_running_state_ids = {{ non_running_state_ids }},
remaining_time = {{ states(remaining_time_sensor) }},
is_running = {{ is_running }},
start_notification_sent = {{ automation_state.get(state_notification_about_start_sent, false) }}
# ===========================================================================
# MAIN STATE MACHINE - Handle different cycle events
# ===========================================================================
- choose:
# -----------------------------------------------------------------------
# CASE 1: Cycle Started
# -----------------------------------------------------------------------
# Triggered when: Device starts running and start notification not yet sent
# Action: Send start notification with duration and optional details
- conditions:
- condition: template
value_template: >
{{ not automation_state.get(state_notification_about_start_sent, false)
and is_running }}
sequence:
- variables:
startup_info_sensors: !input startup_info_sensors
startup_info_texts: !input startup_info_texts
# Build sensor details string for the {{ details }} placeholder
details: >
{% set ns = namespace(text = '') %}
{% for i in range(startup_info_sensors | count) %}
{% set ns.text = ns.text ~ ' ' ~ startup_info_texts[i] ~ ': [' ~ states(startup_info_sensors[i]) ~ '].' %}
{% endfor %}
{{ ns.text }}
# Render the message template with available variables
message: >
{% set tpl = message_start_template %}
{{ tpl | replace('{{ device_name }}', device_name)
| replace('{{ remaining }}', remaining)
| replace('{{ details }}', details) }}
# Send start notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# Mark start notification as sent
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_notification_about_start_sent: true })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# -----------------------------------------------------------------------
# CASE 2: Cycle Completed
# -----------------------------------------------------------------------
# Triggered when: Device stops running after cycle was started
# Action: Send completion notification and reset all state flags
- conditions:
- condition: template
value_template: >
{{ not is_running
and automation_state.get(state_notification_about_start_sent, false)
and (states(run_state_sensor) in [run_state_completion_id, 'unknown', '-'] or states(remaining_time_sensor) in ['unknown', '-']) }}
sequence:
- variables:
# Render the message template with available variables
message: >
{% set tpl = message_completed_template %}
{{ tpl | replace('{{ device_name }}', device_name) }}
# Send completion notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# Reset all notification flags for next cycle
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({
state_notification_about_remaining_time_sent: false,
state_notification_about_start_sent: false,
state_notification_about_preparation_sent: false
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# -----------------------------------------------------------------------
# CASE 3: Preparation Mode Started
# -----------------------------------------------------------------------
# Triggered when: Device enters preparation state (e.g., dryer heating)
# Action: Send preparation notification
- conditions:
- condition: template
value_template: >
{{ preparation_state_id != ''
and states(run_state_sensor) == preparation_state_id
and not automation_state.get(state_notification_about_preparation_sent, false) }}
sequence:
# Mark preparation notification as sent (before sending to prevent duplicates)
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_notification_about_preparation_sent: true })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
- variables:
# Render the message template with available variables
message: >
{% set tpl = message_preparation_template %}
{{ tpl | replace('{{ device_name }}', device_name) }}
# Send preparation notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# -----------------------------------------------------------------------
# CASE 4: Error Occurred
# -----------------------------------------------------------------------
# Triggered when: Error message sensor changes to non-empty value
# Action: Send error notification with details
- conditions:
- condition: template
value_template: >
{{ trigger.entity_id == error_message_sensor
and states(error_message_sensor) not in ['', 'unknown', 'unavailable', 'none', '-']
and states(error_message_sensor) | length > 0 }}
sequence:
- variables:
error: "{{ states(error_message_sensor) }}"
# Render the message template with available variables
message: >
{% set tpl = message_error_template %}
{{ tpl | replace('{{ device_name }}', device_name)
| replace('{{ error }}', error) }}
# Send error notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# -----------------------------------------------------------------------
# CASE 5: Almost Done (Time-to-End Notification)
# -----------------------------------------------------------------------
# Triggered when: Remaining time drops below threshold
# Action: Send "almost done" notification
- conditions:
- condition: template
value_template: >
{{ not automation_state.get(state_notification_about_remaining_time_sent, false)
and is_running
and remaining_time_in_minutes <= notify_time_to_end
and remaining_time_in_minutes > 0 }}
sequence:
# Mark time-to-end notification as sent
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_notification_about_remaining_time_sent: true })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
- variables:
# Calculate minutes for the template
minutes: "{{ remaining.split(':')[1] | int }}"
# Render the message template with available variables
message: >
{% set tpl = message_almost_done_template %}
{{ tpl | replace('{{ device_name }}', device_name)
| replace('{{ minutes }}', minutes | string) }}
# Send "almost done" notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# -----------------------------------------------------------------------
# CASE 6: Tub Cleaning Reminder
# -----------------------------------------------------------------------
# Triggered when: Tub clean counter exceeds threshold
# Action: Send tub cleaning reminder
- conditions:
- condition: template
value_template: >
{{ trigger.entity_id == tub_clean_counter_sensor
and tub_clean_counter_threshold != 0
and (states(tub_clean_counter_sensor) | int(0)) > tub_clean_counter_threshold }}
sequence:
- variables:
tub_count: "{{ states(tub_clean_counter_sensor) | int }}"
tub_threshold: "{{ tub_clean_counter_threshold }}"
# Render the message template with available variables
message: >
{% set tpl = message_tub_clean_template %}
{{ tpl | replace('{{ device_name }}', device_name)
| replace('{{ tub_count }}', tub_count | string)
| replace('{{ tub_threshold }}', tub_threshold | string) }}
# Send tub cleaning reminder
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"