# 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 }}