blueprint:
  name: Daily voice summary button
  description: >-
    When the Home Assistant Voice PE button is long-pressed (~2 seconds), the
    speaker reads a friendly summary of the day, time, and today's calendar
    events. Designed for elderly parents — calm, plain-English wording, no
    screens.


    The single press of the Voice PE button is hardwired to the voice
    assistant pipeline at the firmware level and cannot be intercepted.
    Long-press fires an event that this automation listens for. Configure the
    default voice pipeline to one with no STT/TTS so the single press does
    nothing noticeable.


    Recommended hardware: Home Assistant Green + Home Assistant Voice PE.
    Recommended TTS: Google Cloud TTS (en-GB-Neural2-A) for a natural British
    voice — falls back fine to Piper for a fully local setup.

  domain: automation
  source_url: https://remindmevoice.com/blueprints/daily-voice-summary.yaml

  input:
    person_name:
      name: Person's name
      description: First name used in the greeting (e.g. "Hello Ruth.").
      selector:
        text:

    button_event:
      name: Voice PE button event entity
      description: >-
        The "button press" event entity for the Voice PE. Find it under
        Settings → Devices & Services → ESPHome → your Voice PE device.
        It looks like event.home_assistant_voice_XXXXXX_button_press.
      selector:
        entity:
          domain: event

    media_player:
      name: Voice PE speaker (media player)
      description: >-
        The Voice PE's media player entity, used to play the spoken summary.
        Looks like media_player.home_assistant_voice_XXXXXX_media_player.
      selector:
        entity:
          domain: media_player

    led_ring:
      name: Voice PE LED ring
      description: >-
        The Voice PE's LED ring, lit warm-amber while speaking and dimmed back
        afterwards. Looks like light.home_assistant_voice_XXXXXX_led_ring.
      selector:
        entity:
          domain: light

    tts_engine:
      name: Text-to-speech engine
      description: >-
        Which TTS engine speaks the summary. Google Cloud TTS
        (tts.google_cloud) sounds the most natural; Piper (tts.piper) works
        fully locally with no cloud dependency.
      selector:
        entity:
          domain: tts

    calendar_entity:
      name: Calendar
      description: >-
        The calendar to read today's events from. Typically a shared Google
        Calendar that family members update remotely.
      selector:
        entity:
          domain: calendar

mode: single
max_exceeded: silent

variables:
  person_name: !input person_name
  button_entity: !input button_event
  media_entity: !input media_player
  cal_entity: !input calendar_entity

trigger:
  - platform: state
    entity_id: !input button_event

condition:
  # Filter to long-press only (state attribute, not trigger filter, because
  # the event_type doesn't change between consecutive long-presses).
  - condition: template
    value_template: >-
      {{ state_attr(button_entity, 'event_type') == 'long_press' }}
  # Ignore if speaker is unavailable (e.g. during boot/reconnect).
  - condition: template
    value_template: >-
      {{ not is_state(media_entity, 'unavailable') }}

action:

  # 1. Light up LED ring during speech (warm amber).
  - service: light.turn_on
    target:
      entity_id: !input led_ring
    data:
      rgb_color: [255, 180, 50]
      brightness: 255

  # 2. Fetch next 15 days of calendar events (for countdown items).
  - service: calendar.get_events
    target:
      entity_id: !input calendar_entity
    data:
      duration:
        hours: 360
    response_variable: agenda

  # 3. Speak the summary through the Voice PE speaker.
  - service: tts.speak
    target:
      entity_id: !input tts_engine
    data:
      media_player_entity_id: !input media_player
      message: >-
        {% set hour = now().hour %}
        {% set day_name = now().strftime('%A') %}

        {# Compute natural time rounded to nearest 5 minutes #}
        {% set rm = (((now().minute + 2.5) / 5) | int) * 5 %}
        {% set th = now().hour %}{% if rm >= 60 %}{% set rm = 0 %}{% set th = th + 1 %}{% endif %}
        {% set th12 = th % 12 %}{% if th12 == 0 %}{% set th12 = 12 %}{% endif %}
        {% set hn = ['twelve','one','two','three','four','five','six','seven','eight','nine','ten','eleven','twelve'] %}
        {% set nh = (th12 % 12) + 1 %}
        {% if rm == 0 %}{% set natural_time = hn[th12] ~ " o'clock" %}
        {% elif rm == 5 %}{% set natural_time = 'five past ' ~ hn[th12] %}
        {% elif rm == 10 %}{% set natural_time = 'ten past ' ~ hn[th12] %}
        {% elif rm == 15 %}{% set natural_time = 'quarter past ' ~ hn[th12] %}
        {% elif rm == 20 %}{% set natural_time = 'twenty past ' ~ hn[th12] %}
        {% elif rm == 25 %}{% set natural_time = 'twenty five past ' ~ hn[th12] %}
        {% elif rm == 30 %}{% set natural_time = 'half past ' ~ hn[th12] %}
        {% elif rm == 35 %}{% set natural_time = 'twenty five to ' ~ hn[nh] %}
        {% elif rm == 40 %}{% set natural_time = 'twenty to ' ~ hn[nh] %}
        {% elif rm == 45 %}{% set natural_time = 'quarter to ' ~ hn[nh] %}
        {% elif rm == 50 %}{% set natural_time = 'ten to ' ~ hn[nh] %}
        {% elif rm == 55 %}{% set natural_time = 'five to ' ~ hn[nh] %}
        {% endif %}

        Hello {{ person_name }}.
        {% if 6 <= hour < 9 %}
          It's early morning.
        {% elif 9 <= hour < 12 %}
          It's late morning.
        {% elif hour == 12 %}
          It's noon.
        {% elif 13 <= hour < 15 %}
          It's early afternoon.
        {% elif 15 <= hour < 18 %}
          It's late afternoon.
        {% elif 18 <= hour < 21 %}
          It's evening.
        {% else %}
          It's nighttime.
        {% endif %}

        {% if hour >= 6 and hour < 21 %}
        Today is {{ day_name }}.
        {% endif %}

        {% if 6 <= hour < 12 %}
          The time is {{ natural_time }} in the morning.
        {% elif 12 <= hour < 18 %}
          The time is {{ natural_time }} in the afternoon.
        {% elif 18 <= hour < 21 %}
          The time is {{ natural_time }} in the evening.
        {% else %}
          The time is {{ natural_time }} at night.
        {% endif %}

        {% if hour >= 21 or hour < 6 %}
          {% set hours_until = (6 - hour) % 24 %}
          {% if hours_until <= 1 %}
            It will be morning very soon. Try to get some rest.
          {% elif hours_until <= 3 %}
            Morning is only a couple of hours away. Try to get some rest.
          {% else %}
            There are about {{ hours_until }} hours until morning.
            Try to get some rest.
          {% endif %}
        {% else %}
          {% set all_events = agenda[cal_entity].events %}
          {% set today_str = now().strftime('%Y-%m-%d') %}
          {# Use parallel lists instead of dict literals (HA Jinja compat) #}
          {% set ns = namespace(current=[], upcoming=[], allday=[], ongoing_names=[], ongoing_days=[], countdown_names=[], countdown_days=[]) %}
          {% for event in all_events %}
            {% set start_str = event.start | string %}
            {% set end_str = event.end | string %}
            {% set event_date = start_str[:10] %}
            {% if event_date == today_str %}
              {% if 'T' not in start_str %}
                {% set ns.allday = ns.allday + [event] %}
              {% else %}
                {% set start_ts = as_timestamp(event.start) %}
                {% set end_ts = as_timestamp(event.end) %}
                {% set now_ts = as_timestamp(now()) %}
                {% if start_ts <= now_ts < end_ts %}
                  {% set ns.current = ns.current + [event] %}
                {% elif start_ts > now_ts %}
                  {% set ns.upcoming = ns.upcoming + [event] %}
                {% endif %}
              {% endif %}
            {% else %}
              {% set days_until = ((as_timestamp(event_date) - as_timestamp(today_str)) / 86400) | round(0) | int %}
              {% if days_until > 0 %}
                {# Future event — check for [N] countdown #}
                {% set name = event.summary %}
                {% if name.startswith('[') and '] ' in name %}
                  {% set parts = name.split('] ', 1) %}
                  {% set lookahead = parts[0][1:] | int(0) %}
                  {% set clean_name = parts[1] %}
                  {% if lookahead > 0 and days_until <= lookahead %}
                    {% set ns.countdown_names = ns.countdown_names + [clean_name] %}
                    {% set ns.countdown_days = ns.countdown_days + [days_until] %}
                  {% endif %}
                {% endif %}
              {% elif days_until < 0 and 'T' not in start_str %}
                {# Multi-day all-day event that started before today — check if still ongoing #}
                {% set end_date = end_str[:10] %}
                {% set days_remaining = ((as_timestamp(end_date) - as_timestamp(today_str)) / 86400) | round(0) | int - 1 %}
                {% if days_remaining >= 0 %}
                  {% set name = event.summary %}
                  {% if name.startswith('[') and '] ' in name %}
                    {% set clean_name = name.split('] ', 1)[1] %}
                  {% else %}
                    {% set clean_name = name %}
                  {% endif %}
                  {% if days_remaining == 0 %}
                    {% set ns.ongoing_names = ns.ongoing_names + [clean_name ~ ', last day today'] %}
                  {% elif days_remaining == 1 %}
                    {% set ns.ongoing_names = ns.ongoing_names + [clean_name ~ ' for 1 more day'] %}
                  {% else %}
                    {% set ns.ongoing_names = ns.ongoing_names + [clean_name ~ ' for ' ~ days_remaining ~ ' more days'] %}
                  {% endif %}
                {% endif %}
              {% endif %}
            {% endif %}
          {% endfor %}

          {# All-day events (strip [N] prefix if present, show duration for multi-day) #}
          {% for event in ns.allday %}
            {% set name = event.summary %}
            {% set end_date = (event.end | string)[:10] %}
            {% set total_days = ((as_timestamp(end_date) - as_timestamp(today_str)) / 86400) | round(0) | int %}
            {% if name.startswith('[') and '] ' in name %}
              {% set clean = name.split('] ', 1)[1] %}
            {% else %}
              {% set clean = name %}
            {% endif %}
            {% if total_days > 1 %}
              {{ clean }} for {{ total_days }} days.
            {% elif name.startswith('[') and '] ' in name %}
              {{ clean }}, today!
            {% else %}
              {{ clean }}, all day.
            {% endif %}
          {% endfor %}

          {# Events happening right now #}
          {% for event in ns.current %}
            {{ event.summary }}, around now.
          {% endfor %}

          {# Upcoming timed events — first one gets natural time + "in about X" #}
          {% if ns.upcoming | length > 0 %}
            {% set first = ns.upcoming[0] %}
            {# Convert event start time to natural language #}
            {% set e_hour = as_timestamp(first.start) | timestamp_custom('%H') | int %}
            {% set e_min = as_timestamp(first.start) | timestamp_custom('%M') | int %}
            {% set erm = (((e_min + 2.5) / 5) | int) * 5 %}
            {% set eth = e_hour %}{% if erm >= 60 %}{% set erm = 0 %}{% set eth = eth + 1 %}{% endif %}
            {% set eth12 = eth % 12 %}{% if eth12 == 0 %}{% set eth12 = 12 %}{% endif %}
            {% set enh = (eth12 % 12) + 1 %}
            {% if erm == 0 %}{% set event_time = hn[eth12] ~ " o'clock" %}
            {% elif erm == 5 %}{% set event_time = 'five past ' ~ hn[eth12] %}
            {% elif erm == 10 %}{% set event_time = 'ten past ' ~ hn[eth12] %}
            {% elif erm == 15 %}{% set event_time = 'quarter past ' ~ hn[eth12] %}
            {% elif erm == 20 %}{% set event_time = 'twenty past ' ~ hn[eth12] %}
            {% elif erm == 25 %}{% set event_time = 'twenty five past ' ~ hn[eth12] %}
            {% elif erm == 30 %}{% set event_time = 'half past ' ~ hn[eth12] %}
            {% elif erm == 35 %}{% set event_time = 'twenty five to ' ~ hn[enh] %}
            {% elif erm == 40 %}{% set event_time = 'twenty to ' ~ hn[enh] %}
            {% elif erm == 45 %}{% set event_time = 'quarter to ' ~ hn[enh] %}
            {% elif erm == 50 %}{% set event_time = 'ten to ' ~ hn[enh] %}
            {% elif erm == 55 %}{% set event_time = 'five to ' ~ hn[enh] %}
            {% endif %}
            {# Add time-of-day suffix if event is in a different period than now #}
            {% set now_period = 'morning' if 6 <= hour < 12 else ('afternoon' if 12 <= hour < 18 else ('evening' if 18 <= hour < 21 else 'night')) %}
            {% set evt_period = 'morning' if 6 <= eth < 12 else ('afternoon' if 12 <= eth < 18 else ('evening' if 18 <= eth < 21 else 'night')) %}
            {% if now_period != evt_period %}
              {% set event_time = event_time ~ ' in the ' ~ evt_period %}
            {% endif %}
            {% set mins = ((as_timestamp(first.start) - as_timestamp(now())) / 60) | round(0) | int %}
            {% if mins < 60 %}
              {{ first.summary }} at {{ event_time }}, in about {{ mins }} minutes.
            {% else %}
              {% set hrs = (mins / 60) | round(0) | int %}
              {{ first.summary }} at {{ event_time }}, in about {{ hrs }} hour{{ 's' if hrs != 1 }}.
            {% endif %}
            {% if ns.upcoming | length > 1 %}
              {% if ns.upcoming | length == 2 %}
                There's also {{ ns.upcoming[1].summary }} later.
              {% else %}
                There are also {{ ns.upcoming | length - 1 }} more things happening later.
              {% endif %}
            {% endif %}
          {% endif %}

          {% if ns.allday | length == 0 and ns.current | length == 0 and ns.upcoming | length == 0 %}
            {% if hour < 12 %}
              You have nothing planned today. It's a nice relaxed day!
            {% elif hour < 19 %}
              Nothing else planned today.
            {% endif %}
          {% endif %}

          {# Ongoing multi-day events #}
          {% for name in ns.ongoing_names %}
            {{ name }}.
          {% endfor %}

          {# Countdown events from future days (e.g. "[5] Michael is away") #}
          {% if ns.countdown_names | length > 0 and (ns.allday | length > 0 or ns.current | length > 0 or ns.upcoming | length > 0 or ns.ongoing_names | length > 0) %}
            Also,
          {% endif %}
          {% for i in range(ns.countdown_names | length) %}
            {% if ns.countdown_days[i] == 1 %}
              Tomorrow, {{ ns.countdown_names[i] }}.
            {% elif ns.countdown_days[i] == 2 %}
              The day after tomorrow, {{ ns.countdown_names[i] }}.
            {% else %}
              In {{ ns.countdown_days[i] }} days, {{ ns.countdown_names[i] }}.
            {% endif %}
          {% endfor %}

          {# Gentle bedtime nudge in the evening #}
          {% if 19 <= hour < 20 %}
            Bed time in a couple of hours.
          {% elif 20 <= hour < 21 %}
            Bed time soon.
          {% endif %}
        {% endif %}

  # 4. Wait for speech to finish, then restore ambient dim glow.
  - delay:
      seconds: 20
  - service: light.turn_on
    target:
      entity_id: !input led_ring
    data:
      brightness: 80
      rgb_color: [255, 180, 100]
