blueprint:
  name: "Tibber Prices: Dishwasher (Smart Plug)"
  description: >
    **Companion blueprint for
    [Tibber Prices](https://my.home-assistant.io/redirect/hacs_repository/?owner=jpawlowski&repository=hass.tibber_prices&category=integration)
    (HACS integration)** · Blueprint v1.0.0

    Automatically run your dishwasher at the cheapest electricity price
    overnight using a smart plug.
    Open your
    [Tibber Prices configuration](https://my.home-assistant.io/redirect/integration/?domain=tibber_prices)
    to verify the integration is installed and set up.

    **What it does:**

    - Plans the cheapest 2-hour window overnight (every evening)

    - Starts the dishwasher automatically at the cheapest time

    - Sends a notification with the planned time and price

    - Survives Home Assistant restarts (uses `input_datetime` helper)

    **Prerequisites:**

    - [Tibber Prices integration](https://my.home-assistant.io/redirect/hacs_repository/?owner=jpawlowski&repository=hass.tibber_prices&category=integration) installed via HACS

    - One helper (created in Settings → Helpers):
      - Date & Time (`input_datetime`) — stores the planned start time

    - Smart plug switch for the dishwasher

    **How it works:**

    1. Every evening at the configured time, the blueprint finds the
       cheapest window overnight

    2. The planned start time is saved to the helper (survives restarts)

    3. At the planned time, the smart plug turns on

    4. A notification confirms the plan and the start

    **Other variants:**
    [Home Connect](https://github.com/jpawlowski/hass.tibber_prices/blob/main/custom_components/tibber_prices/blueprints/automation/tibber_prices/dishwasher_home_connect.yaml)
    ·
    [Home Connect Alt](https://github.com/jpawlowski/hass.tibber_prices/blob/main/custom_components/tibber_prices/blueprints/automation/tibber_prices/dishwasher_home_connect_alt.yaml)
  domain: automation
  author: jpawlowski
  homeassistant:
    min_version: "2024.6.0"
  source_url: https://github.com/jpawlowski/hass.tibber_prices/blob/main/custom_components/tibber_prices/blueprints/automation/tibber_prices/dishwasher.yaml
  input:
    appliance:
      name: Appliance
      icon: mdi:dishwasher
      description: Select the smart plug that controls your dishwasher.
      input:
        appliance_switch:
          name: Dishwasher Smart Plug
          description: The switch entity controlling the dishwasher.
          selector:
            entity:
              filter:
                domain: switch

    schedule:
      name: Schedule
      icon: mdi:calendar-clock
      description: Configure when to plan and the search window.
      input:
        plan_time:
          name: Planning Time
          description: >
            When to search for the cheapest window each day.
            Typically in the evening after loading the dishwasher.
          default: "20:00:00"
          selector:
            time:
        start_helper:
          name: Start Time Helper
          description: >
            An `input_datetime` helper (type: Date and Time) that stores
            the planned start time. Create in Settings → Helpers.
          selector:
            entity:
              filter:
                domain: input_datetime
        duration:
          name: Program Duration
          description: >
            Typical dishwasher program duration in minutes.
            ECO 50°C ≈ 120 min, Auto ≈ 90 min, Intensive ≈ 150 min.
          default: 120
          selector:
            number:
              min: 30
              max: 240
              step: 5
              unit_of_measurement: min
              mode: slider
        search_start:
          name: Search Window Start
          description: >
            Earliest time the dishwasher may start.
            Typically late evening after loading.
          default: "22:00:00"
          selector:
            time:
        search_end:
          name: Search Window End
          description: >
            Latest time the dishwasher must finish by.
            The program must complete before this time.
          default: "06:00:00"
          selector:
            time:

    runtime_overrides:
      name: Runtime Overrides
      icon: mdi:tune-vertical
      collapsed: true
      description: >
        Optionally connect helpers to override settings from your
        dashboard at runtime. When a helper is connected and has
        a valid value, it takes priority over the fixed default.
        Leave empty to always use the fixed defaults.
      input:
        duration_override:
          name: "Override: Program Duration"
          description: >
            `input_number` helper to change the duration from your
            dashboard without reconfiguring the blueprint.
            **Create in Settings → Helpers → Number** with the same
            min/max as the Duration slider above.
          default: ""
          selector:
            entity:
              filter:
                domain: input_number

    notifications:
      name: Notifications
      icon: mdi:bell-outline
      collapsed: true
      description: Optional mobile notifications for planning and start.
      input:
        notify_service:
          name: Notification Service
          description: >
            One or more notify services, comma-separated
            (e.g., `notify.mobile_app_yourphone` or
            `notify.mobile_app_phone, notify.mobile_app_tablet`).
            Leave empty to disable all notifications.
          default: ""
          selector:
            text:

mode: single
max_exceeded: silent

triggers:
  - trigger: time
    at: !input plan_time
    id: plan
  - trigger: time
    at: !input start_helper
    id: execute

variables:
  _blueprint_variant: "smart_plug"
  appliance_switch: !input appliance_switch
  start_helper: !input start_helper
  _duration_default: !input duration
  _duration_override: !input duration_override
  duration: >
    {% set o = _duration_override %}
    {% if o and states(o) not in ['unknown', 'unavailable'] %}
      {{ states(o) | int(_duration_default) }}
    {% else %}
      {{ _duration_default }}
    {% endif %}
  search_start: !input search_start
  search_end: !input search_end
  notify_service: !input notify_service

actions:
  # Check: Tibber Prices integration installed?
  - variables:
      _tp_entities: "{{ integration_entities('tibber_prices') | list }}"
  - if:
      - condition: template
        value_template: "{{ _tp_entities | length == 0 }}"
    then:
      - if:
          - condition: template
            value_template: "{{ notify_service | length > 0 }}"
        then:
          - repeat:
              for_each: "{{ notify_service.split(',') | map('trim') | reject('eq', '') | list }}"
              sequence:
                - action: "{{ repeat.item }}"
                  data:
                    title: "🍽️ Dishwasher — Setup Required"
                    message: >
                      The Tibber Prices integration is not installed or not
                      configured. Install it via HACS and set up your Tibber
                      account before using this blueprint.
      - stop: "Tibber Prices integration not found"

  # ════════════════════════════════════════════════════════
  # PLAN: Find cheapest window
  # ════════════════════════════════════════════════════════
  - choose:
      - conditions:
          - condition: trigger
            id: plan
        sequence:
          - action: tibber_prices.find_cheapest_block
            data:
              duration: >
                {{ '%02d:%02d:00' | format(
                  (duration | int) // 60,
                  (duration | int) % 60) }}
              search_start_time: "{{ search_start }}"
              search_end_time: "{{ search_end }}"
              search_end_day_offset: 1
            response_variable: result

          - if:
              - condition: template
                value_template: "{{ result.window_found }}"
            then:
              - action: input_datetime.set_datetime
                target:
                  entity_id: "{{ start_helper }}"
                data:
                  datetime: "{{ result.window.start }}"
              - if:
                  - condition: template
                    value_template: "{{ notify_service | length > 0 }}"
                then:
                  - repeat:
                      for_each: "{{ notify_service.split(',') | map('trim') | reject('eq', '') | list }}"
                      sequence:
                        - action: "{{ repeat.item }}"
                          data:
                            title: "🍽️ Dishwasher Planned"
                            message: >
                              Start at {{ result.window.start | as_datetime
                              | as_local | as_timestamp
                              | timestamp_custom('%H:%M') }}.
                              Avg price: {{ result.window.price_mean | round(1) }}
                              {{ result.price_unit }}/kWh.
                              {% if result.relaxation_applied | default(false) %}
                              (Filters relaxed to find window.)
                              {% endif %}
            else:
              - if:
                  - condition: template
                    value_template: "{{ notify_service | length > 0 }}"
                then:
                  - repeat:
                      for_each: "{{ notify_service.split(',') | map('trim') | reject('eq', '') | list }}"
                      sequence:
                        - action: "{{ repeat.item }}"
                          data:
                            title: "🍽️ Dishwasher"
                            message: >
                              No cheap window found overnight. Consider running
                              manually or adjusting the search window.

      # ════════════════════════════════════════════════════
      # EXECUTE: Start dishwasher
      # ════════════════════════════════════════════════════
      - conditions:
          - condition: trigger
            id: execute
        sequence:
          - action: switch.turn_on
            target:
              entity_id: "{{ appliance_switch }}"
          - if:
              - condition: template
                value_template: "{{ notify_service | length > 0 }}"
            then:
              - repeat:
                  for_each: "{{ notify_service.split(',') | map('trim') | reject('eq', '') | list }}"
                  sequence:
                    - action: "{{ repeat.item }}"
                      data:
                        title: "🍽️ Dishwasher Started"
                        message: >
                          Smart plug turned on. Program should finish in
                          ~{{ duration }} minutes.
