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>
This commit is contained in:
2026-02-01 02:38:52 +03:00
parent 26019b1c0c
commit 7b00899903
38 changed files with 843 additions and 615 deletions

View File

@@ -0,0 +1,975 @@
# 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 }}