- id: dishwasher_plan_cheapest_night_run alias: Opvaskemaskine - plan billigste natkørsel mode: single trigger: - platform: state entity_id: sensor.energi_data_service - platform: time at: "13:10:00" variables: best_start_ts: > {% set raw = (state_attr('sensor.energi_data_service', 'raw_today') or []) + (state_attr('sensor.energi_data_service', 'raw_tomorrow') or []) %} {% set ns = namespace(prices=[], candidates=[]) %} {% set fallback_ts = as_timestamp(today_at('23:50')) | int %} {% for item in raw %} {% set dt_source = item.start if item.start is defined else item.hour if item.hour is defined else item.time if item.time is defined else none %} {% if dt_source %} {% if item.price is defined %} {% set price = item.price | float(999) %} {% elif item.value is defined %} {% set price = item.value | float(999) %} {% else %} {% set price = 999 %} {% endif %} {% set ns.prices = ns.prices + [{'ts': as_timestamp(as_datetime(dt_source)) | int, 'price': price}] %} {% endif %} {% endfor %} {% set tomorrow_midnight = (as_timestamp(today_at('00:00')) | int) + 86400 %} {% set candidate_starts = [ as_timestamp(today_at('21:00')) | int, as_timestamp(today_at('22:00')) | int, as_timestamp(today_at('23:00')) | int, tomorrow_midnight, tomorrow_midnight + 3600, tomorrow_midnight + 7200 ] %} {% for base in candidate_starts %} {% set total = namespace(value=0, missing=false) %} {% for offset in range(4) %} {% set target = base + (offset * 3600) %} {% set matches = ns.prices | selectattr('ts', 'eq', target) | list %} {% if matches | count > 0 %} {% set total.value = total.value + (matches[0].price | float(999)) %} {% else %} {% set total.missing = true %} {% endif %} {% endfor %} {% if not total.missing %} {% set ns.candidates = ns.candidates + [{'ts': base, 'total': total.value}] %} {% endif %} {% endfor %} {% set sorted = ns.candidates | sort(attribute='total') %} {{ (sorted | first).ts if (sorted | count) > 0 else fallback_ts }} action: - service: input_datetime.set_datetime target: entity_id: input_datetime.dishwasher_next_start data: timestamp: "{{ best_start_ts | int }}" - id: dishwasher_start_planned_night_run alias: Opvaskemaskine - start planlagt natkørsel mode: single trigger: - platform: time at: input_datetime.dishwasher_next_start condition: - condition: template value_template: "{{ is_state('sensor.dishwasher_status_2', 'Off') }}" action: - choose: - conditions: - condition: state entity_id: binary_sensor.dishwasher_fjernbetjening state: "on" sequence: - service: button.press target: entity_id: button.dishwasher_start default: - service: notify.mobile_app_claus_iphone_15pro data: title: "Opvaskemaskine venter på remote control" message: "Planlagt natkørsel kunne ikke startes, fordi fjernbetjening ikke er slået til." - id: dishwasher_remote_control_hourly_reminder alias: Opvaskemaskine - påmindelse om remote control mode: single trigger: - platform: time_pattern minutes: "/15" condition: - condition: template value_template: "{{ now().hour >= 19 and now().hour <= 21 }}" - condition: state entity_id: input_boolean.dishwasher_reminder_snoozed state: "off" - condition: template value_template: "{{ is_state('sensor.dishwasher_status_2', 'Off') }}" - condition: or conditions: - condition: state entity_id: binary_sensor.dishwasher_fjernbetjening state: "off" - condition: template value_template: "{{ not is_state('binary_sensor.dishwasher_dor', 'off') }}" - condition: template value_template: "{{ is_state('binary_sensor.dishwasher_info_2', 'on') }}" - condition: template value_template: "{{ is_state('binary_sensor.dishwasher_svigt', 'on') }}" - condition: template value_template: "{{ states('sensor.dishwasher_salt_level') | float(999) < 20 }}" - condition: template value_template: "{{ states('sensor.dishwasher_rinse_aid_level') | float(999) < 20 }}" - condition: template value_template: "{{ states('sensor.dishwasher_powerdisk_level') | float(999) < 20 }}" action: - variables: reminder_time: "{{ now().strftime('%H:%M') }}" remote_off: "{{ is_state('binary_sensor.dishwasher_fjernbetjening', 'off') }}" door_not_closed: "{{ not is_state('binary_sensor.dishwasher_dor', 'off') }}" low_salt: "{{ states('sensor.dishwasher_salt_level') | float(999) < 20 }}" low_rinse: "{{ states('sensor.dishwasher_rinse_aid_level') | float(999) < 20 }}" low_powerdisk: "{{ states('sensor.dishwasher_powerdisk_level') | float(999) < 20 }}" info_on: "{{ is_state('binary_sensor.dishwasher_info_2', 'on') }}" svigt: "{{ is_state('binary_sensor.dishwasher_svigt', 'on') }}" issue_text: > {% set issues = [] %} {% if remote_off %}{% set issues = issues + ['remote control er ikke slået til'] %}{% endif %} {% if door_not_closed %}{% set issues = issues + ['døren er ikke lukket'] %}{% endif %} {% if low_salt %}{% set issues = issues + ['salt er lavt (' ~ states('sensor.dishwasher_salt_level') ~ '%)'] %}{% endif %} {% if low_rinse %}{% set issues = issues + ['afspændingsmiddel er lavt (' ~ states('sensor.dishwasher_rinse_aid_level') ~ '%)'] %}{% endif %} {% if low_powerdisk %}{% set issues = issues + ['powerdisk er lav (' ~ states('sensor.dishwasher_powerdisk_level') ~ '%)'] %}{% endif %} {% if info_on %}{% set issues = issues + ['info-advarsel aktiv'] %}{% endif %} {% if svigt %}{% set issues = issues + ['maskinsvigt'] %}{% endif %} {{ issues | join(', ') }} - service: notify.mobile_app_claus_iphone_15pro data: title: "⚠️ Opvaskemaskine - tjek inden natkørsel" message: "[{{ reminder_time }}] {{ issue_text | capitalize }}." data: actions: - action: "DISHWASHER_DONE" title: "✅ Gjort det" - action: "DISHWASHER_IGNORE" title: "🔕 Ignorer i aften" - id: dishwasher_reminder_action_ignore alias: Opvaskemaskine - ignorer påmindelser i aften mode: single trigger: - platform: event event_type: mobile_app_notification_action event_data: action: DISHWASHER_IGNORE action: - service: input_boolean.turn_on target: entity_id: input_boolean.dishwasher_reminder_snoozed - id: dishwasher_reminder_snooze_reset alias: Opvaskemaskine - nulstil snooze ved midnat mode: single trigger: - platform: time at: "00:00:00" action: - service: input_boolean.turn_off target: entity_id: input_boolean.dishwasher_reminder_snoozed