Files
haos-blueprints/Common/Washing Machine/blueprint.yaml
alexei.dolgolyov 7b00899903 Restructure repository: organize blueprints into folders
Each blueprint now has its own folder containing:
- blueprint.yaml: The automation code with a short header
- README.md: Detailed documentation extracted from headers

Updated CLAUDE.md with repository structure guidelines.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 02:38:52 +03:00

976 lines
39 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
# Monitors appliance cycles and sends notifications for start, completion,
# errors, and more. See README.md for detailed documentation.
#
# 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
show_estimated_end_time:
name: Show Estimated End Time
description: Include estimated completion time in start notification
default: true
selector:
boolean:
# -------------------------------------------------------------------------
# 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 `{appliance_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: `{appliance_name}`, `{remaining}`, `{details}`, `{estimated_end}`
default: "🧺 {appliance_name}: старт. Длительность: `{remaining}`. Завершение: ~{estimated_end}.{details}"
selector:
text:
multiline: true
message_completed:
name: "Completed Message"
description: >
Message sent when cycle completes.
Variables: `{appliance_name}`
default: "🟢 {appliance_name}: завершено. Не забудьте достать вещи!"
selector:
text:
multiline: true
message_almost_done:
name: "Almost Done Message"
description: >
Message sent when cycle is about to finish.
Variables: `{appliance_name}`, `{minutes}`
default: "🟢 {appliance_name}: завершение через {minutes} минут."
selector:
text:
multiline: true
message_preparation:
name: "Preparation Message"
description: >
Message sent when device enters preparation mode.
Variables: `{appliance_name}`
default: "⚙️ {appliance_name}: подготовка активирована!"
selector:
text:
multiline: true
message_error:
name: "Error Message"
description: >
Message sent when an error occurs.
Variables: `{appliance_name}`, `{error}`
default: "⚠️ {appliance_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: `{appliance_name}`, `{tub_count}`, `{tub_threshold}`
default: "⚠️ {appliance_name}: внимание. Необходима чистка барабана. Число стирок: {tub_count}. Допустимый предел: {tub_threshold}."
selector:
text:
multiline: true
message_paused:
name: "Paused Message"
description: >
Message sent when cycle is paused.
Variables: `{appliance_name}`, `{remaining}`
default: "⏸️ {appliance_name}: пауза. Осталось: {remaining}."
selector:
text:
multiline: true
message_resumed:
name: "Resumed Message"
description: >
Message sent when cycle resumes.
Variables: `{appliance_name}`, `{remaining}`
default: "▶️ {appliance_name}: продолжение. Осталось: {remaining}."
selector:
text:
multiline: true
message_energy_report:
name: "Energy Report Message"
description: >
Appended to completion message with energy stats.
Variables: `{energy_kwh}`, `{energy_cost}`
default: " Потребление: {energy_kwh} kWh."
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
pause_state_ids:
name: Pause State ID(s)
description: >
List of run state ID(s) that indicate the device is paused
(e.g., 'Пауза', 'Pause'). Used for pause/resume notifications.
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
# -------------------------------------------------------------------------
# Power Monitoring
# -------------------------------------------------------------------------
power_monitoring:
name: "Power Monitoring"
collapsed: true
input:
power_sensor:
name: Power Sensor (optional)
description: >
Sensor that reports current power consumption in watts.
Used to track energy usage per cycle.
default: []
selector:
entity:
domain: sensor
device_class: power
multiple: true
energy_cost_per_kwh:
name: Energy Cost per kWh
description: >
Cost per kilowatt-hour for energy calculations.
Set to 0 to disable cost display.
default: 0
selector:
number:
min: 0
max: 100
step: 0.01
unit_of_measurement: "currency/kWh"
# -------------------------------------------------------------------------
# Debug
# -------------------------------------------------------------------------
debug:
name: "Debug"
collapsed: true
input:
enable_debug_notifications:
name: Enable Debug Notifications
description: >
Send persistent notifications for debugging automation behavior.
Shows state changes, trigger details, and variable values.
default: false
selector:
boolean:
# =============================================================================
# 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
# Power sensor updates (for energy tracking)
# Note: Uses multiple selector, so empty list means trigger is skipped
- platform: state
entity_id: !input power_sensor
id: "power_update"
# =============================================================================
# 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
state_notification_about_pause_sent: 'napas' # Pause notification sent
state_was_paused: 'wasp' # Track if cycle was paused
state_cycle_start_time: 'cst' # Cycle start timestamp
state_energy_samples: 'esmp' # Energy sample accumulator (Wh)
state_last_sample_time: 'lst' # Last power sample timestamp
# ---------------------------------------------------------------------------
# Input Variables
# ---------------------------------------------------------------------------
run_state_sensor: !input run_state_sensor
non_running_state_ids: !input non_running_state_ids
pause_state_ids: !input pause_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
show_estimated_end_time: !input show_estimated_end_time
power_sensor: !input power_sensor
energy_cost_per_kwh: !input energy_cost_per_kwh
enable_debug_notifications: !input enable_debug_notifications
# ---------------------------------------------------------------------------
# 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
message_paused_template: !input message_paused
message_resumed_template: !input message_resumed
message_energy_report_template: !input message_energy_report
# ---------------------------------------------------------------------------
# Computed State Values
# ---------------------------------------------------------------------------
remaining: "{{ states(remaining_time_sensor) }}"
# Note: Using 'appliance_name' instead of 'device_name' to avoid conflict
# with Home Assistant's internal DeviceExtension.device_name function
appliance_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 %}
# Calculate estimated end time from remaining time
estimated_end_time: >
{% if remaining not in ['unknown', 'unavailable', '-'] %}
{% set parts = remaining.split(':') %}
{% if parts | length >= 2 %}
{% set hours = parts[0] | int %}
{% set minutes = parts[1] | int %}
{% set end_time = now() + timedelta(hours=hours, minutes=minutes) %}
{{ end_time.strftime('%H:%M') }}
{% else %}
{{ 'N/A' }}
{% endif %}
{% else %}
{{ 'N/A' }}
{% endif %}
# Check if device is paused
is_paused: >
{{ run_state in pause_state_ids }}
# Get current power consumption (power_sensor is a list, use first item if available)
current_power: >
{% if power_sensor | length > 0 %}
{{ states(power_sensor[0]) | float(0) }}
{% 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 (now controlled by input)
# ---------------------------------------------------------------------------
# enable_debug_notifications is loaded from input above
# =============================================================================
# ACTIONS
# =============================================================================
action:
# ---------------------------------------------------------------------------
# DEBUG: Log current state (enabled via Debug input section)
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Debug - {appliance_name}"
message: >
Trigger: {{ trigger.entity_id }}
Run State: {{ run_state }}
Is Running: {{ is_running }}
Is Paused: {{ is_paused }}
Remaining: {remaining}
Remaining Minutes: {{ remaining_time_in_minutes }}
Power: {{ current_power }} W
Start Sent: {{ automation_state.get(state_notification_about_start_sent, false) }}
Time-to-End Sent: {{ automation_state.get(state_notification_about_remaining_time_sent, false) }}
Pause Sent: {{ automation_state.get(state_notification_about_pause_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 }}
# Get estimated end time string
est_end: "{{ estimated_end_time if show_estimated_end_time else '' }}"
# Render the message template with available variables
message: >
{% set tpl = message_start_template %}
{{ tpl | replace('{appliance_name}', appliance_name)
| replace('{remaining}', remaining)
| replace('{estimated_end}', est_end)
| replace('{details}', details) }}
# Send start notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# Mark start notification as sent and initialize energy tracking
- 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,
state_cycle_start_time: now().isoformat(),
state_energy_samples: 0,
state_last_sample_time: now().isoformat()
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Debug notification for start
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "{appliance_name} - START"
message: >
Action: CYCLE STARTED
Time: {{ now().strftime('%H:%M:%S') }}
Duration: {remaining}
Estimated End: {{ estimated_end_time }}
# -----------------------------------------------------------------------
# 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:
# Calculate energy consumption
energy_wh: "{{ automation_state.get(state_energy_samples, 0) | float }}"
energy_kwh: "{{ (energy_wh / 1000) | round(3) }}"
energy_cost: >
{% if energy_cost_per_kwh > 0 %}
{{ (energy_kwh * energy_cost_per_kwh) | round(2) }}
{% else %}
{{ 0 }}
{% endif %}
# Build energy report string (power_sensor is a list)
energy_report: >
{% if power_sensor | length > 0 and energy_kwh > 0 %}
{% set tpl = message_energy_report_template %}
{{ tpl | replace('{energy_kwh}', energy_kwh | string)
| replace('{energy_cost}', energy_cost | string) }}
{% else %}
{{ '' }}
{% endif %}
# Render the message template with available variables
message: >
{% set tpl = message_completed_template %}
{{ tpl | replace('{appliance_name}', appliance_name)
}}{{ energy_report }}
# 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,
state_notification_about_pause_sent: false,
state_was_paused: false,
state_energy_samples: 0
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Debug notification for completion
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "{appliance_name} - COMPLETE"
message: >
Action: CYCLE COMPLETED
Time: {{ now().strftime('%H:%M:%S') }}
Energy Used: {energy_kwh} kWh
# -----------------------------------------------------------------------
# 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('{appliance_name}', appliance_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('{appliance_name}', appliance_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('{appliance_name}', appliance_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('{appliance_name}', appliance_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 }}"
# -----------------------------------------------------------------------
# CASE 7: Cycle Paused
# -----------------------------------------------------------------------
# Triggered when: Device enters paused state during a cycle
# Action: Send pause notification
- conditions:
- condition: template
value_template: >
{{ pause_state_ids | length > 0
and is_paused
and automation_state.get(state_notification_about_start_sent, false)
and not automation_state.get(state_notification_about_pause_sent, false) }}
sequence:
# Mark pause 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_pause_sent: true,
state_was_paused: true
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
- variables:
# Render the message template with available variables
message: >
{% set tpl = message_paused_template %}
{{ tpl | replace('{appliance_name}', appliance_name)
| replace('{remaining}', remaining) }}
# Send pause notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# Debug notification for pause
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "{appliance_name} - PAUSED"
message: >
Action: CYCLE PAUSED
Time: {{ now().strftime('%H:%M:%S') }}
Remaining: {remaining}
# -----------------------------------------------------------------------
# CASE 8: Cycle Resumed
# -----------------------------------------------------------------------
# Triggered when: Device resumes after being paused
# Action: Send resume notification
- conditions:
- condition: template
value_template: >
{{ is_running
and automation_state.get(state_was_paused, false)
and automation_state.get(state_notification_about_pause_sent, false) }}
sequence:
# Reset pause notification flag (keep was_paused for tracking)
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({
state_notification_about_pause_sent: false
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
- variables:
# Render the message template with available variables
message: >
{% set tpl = message_resumed_template %}
{{ tpl | replace('{appliance_name}', appliance_name)
| replace('{remaining}', remaining) }}
# Send resume notification
- service: notify.send_message
target:
entity_id: !input notify_target
data:
message: "{{ message }}"
# Debug notification for resume
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "{appliance_name} - RESUMED"
message: >
Action: CYCLE RESUMED
Time: {{ now().strftime('%H:%M:%S') }}
Remaining: {remaining}
# -----------------------------------------------------------------------
# CASE 9: Power Sample (Accumulate Energy)
# -----------------------------------------------------------------------
# Triggered when: Power sensor updates during running cycle
# Action: Accumulate energy consumption
- conditions:
- condition: template
value_template: >
{{ trigger.id == 'power_update'
and power_sensor | length > 0
and automation_state.get(state_notification_about_start_sent, false)
and is_running }}
sequence:
- variables:
last_sample: "{{ automation_state.get(state_last_sample_time, now().isoformat()) }}"
time_diff_hours: >
{% set last = last_sample | as_datetime %}
{% if last is not none %}
{{ ((now() - last).total_seconds() / 3600) | float }}
{% else %}
{{ 0 }}
{% endif %}
energy_increment: "{{ (current_power * time_diff_hours) | round(4) }}"
accumulated_energy: "{{ (automation_state.get(state_energy_samples, 0) | float + energy_increment) | round(4) }}"
# Update accumulated energy
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({
state_energy_samples: accumulated_energy,
state_last_sample_time: now().isoformat()
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}