Reminders - Create and List Tasks with Conversational Commands

Reminders via Assist - Create and List Tasks with Conversational Commands

Hi everyone! :blush:

I’m super excited to give back to the Home Assistant community – after benefiting from so many shared resources, I can finally contribute something of my own. This blueprint has been a fun project, and I hope it helps improve your Home Assistant setup!

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Don’t forget to expose the automation to Assist too! It will help the new Fallback LLM handle edge cases :slight_smile:

NOTE: the blueprint mode is set to “single” for now because “queued” seems to cause a bug where the conversation response no longer works correctly. This isn’t ideal, but I’ll keep it like this for now until the bug is fixed.

What does this blueprint do?

This automation aims to replicate the behaviour of Google Assistant’s reminders via voice. You can set reminders and fetch a list of your pending tasks using conversational commands. It supports both relative and exact time inputs and even tries to deduce whether you meant 2 AM or 2 PM based on the context.

Inspiration

I was originally inspired by this post on local voice reminders. After trying it out, I wanted to create a slimmer version of the same idea that worked entirely within a single automation and didn’t require any additional YAML tweaking. Doing it this way also made it easy to share as a blueprint—something I was keen on!

Features:

  • Add reminders with commands like:
    • “Remind me to water the plants tomorrow.”
    • “Set a reminder to call mom at 3 PM.”
  • Fetch your task list by saying:
    • “What’s on my reminder list?”
    • “Show me my tasks.”
  • Customizable to work with your preferred to-do list entity and voice commands.
  • Tailor the voice commands to your liking

How to use:

  1. Import blueprint file into your Home Assistant instance.
  2. Reload automation (this may not be required, but when I was testing this import, some issues cropped up if I didn’t reload).

Reminders YAML

blueprint:
  name: Reminders - Create and List
  description: "Effortlessly set reminders and fetch tasks using conversational commands. This automation supports relative and exact time inputs, intelligently deducing 2 AM or 2 PM based on context for a seamless experience."
  domain: automation
  input:
    todo_entity:
      name: Reminder Entity
      description: The entity ID of the todo list to store reminders.
      selector:
        entity:
          domain: todo
    add_reminder_commands:
      name: Add Reminder Commands
      description: List of conversational commands for adding reminders.
      default:
        - Remind me to {reminder} [at] {datetime}
        - I need to remember to {reminder} [at] {datetime}
        - Set a reminder [to] {reminder} {datetime}
        - Can you remind me about {reminder} at {datetime}
        - Remind me in {datetime} to {reminder}
        - In {datetime} remind me to {reminder}
        - Add {reminder} to my (tasks|reminders|to do list) for {datetime}
        - Add [a] reminder [to] {reminder} {datetime}
        - Remind me tomorrow [to] {reminder}
        - Please remind me next week to {reminder}
        - Remind me to {reminder} in {datetime}
        - Schedule {reminder} {datetime}
    fetch_reminder_commands:
      name: Fetch Reminder Commands
      description: List of conversational commands for fetching reminders.
      default:
        - What tasks (are left|remain|are incomplete)
        - Whats on (the|my) reminder list
        - >-
          (What are|Tell me|Read|List|Show me) [(my|the)] [pending]
          (reminders|tasks|to-do list)

trigger:
  - platform: conversation
    command: !input add_reminder_commands
    id: add_reminder

  - platform: conversation
    command: !input fetch_reminder_commands
    id: fetch_reminders

condition: []

action:
  - choose:
      - conditions:
          - condition: trigger
            id: add_reminder
        sequence:
          - variables:
              reminder: >
                {% set slots = trigger.slots | default({}) %}
                {{ slots.reminder if slots.reminder else "No reminder specified" }}
              raw_datetime: >
                {% set slots = trigger.slots | default({}) %}
                {{ slots.datetime if slots.datetime else "none" }}
          - variables:
              due_date_str: >
                {% set raw_datetime = raw_datetime | string %}
                {% if raw_datetime == 'none' %}
                  {{ now().strftime('%Y-%m-%d %H:%M:%S') }}
                {% elif 'minute' in raw_datetime or 'hour' in raw_datetime %}
                  {{ (now() + timedelta(seconds=raw_datetime | regex_replace(find='[^0-9]', replace='') | int * 60)).strftime('%Y-%m-%d %H:%M:%S') }}
                {% elif ':' in raw_datetime and ('AM' in raw_datetime or 'PM' in raw_datetime) %}
                  {% set time_24h = strptime(raw_datetime, '%I:%M %p').strftime('%H:%M') %}
                  {{ as_timestamp(now().strftime('%Y-%m-%d') + ' ' + time_24h) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
                {% elif ':' in raw_datetime %}
                  {% set time_object = strptime(raw_datetime, '%H:%M') %}
                  {% set now_time = now().replace(second=0, microsecond=0) %}
                  {% set parsed_time = now().replace(hour=time_object.hour, minute=time_object.minute, second=0, microsecond=0) %}
                  {% if parsed_time < now_time %}
                    {% set parsed_time = parsed_time + timedelta(days=1) %}
                  {% endif %}
                  {{ parsed_time.strftime('%Y-%m-%d %H:%M:%S') }}
                {% elif 'AM' in raw_datetime or 'PM' in raw_datetime %}
                  {% set time_24h = strptime(raw_datetime, '%I %p').strftime('%H:%M') %}
                  {{ as_timestamp(now().strftime('%Y-%m-%d') + ' ' + time_24h) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
                {% elif raw_datetime.isdigit() %}
                  {% set hour = raw_datetime | int %}
                  {% set am_time = now().replace(hour=hour, minute=0, second=0, microsecond=0) %}
                  {% set pm_time = now().replace(hour=(hour + 12) % 24, minute=0, second=0, microsecond=0) %}
                  {% if am_time < now() %}
                    {% set am_time = am_time + timedelta(days=1) %}
                  {% endif %}
                  {% if pm_time < now() %}
                    {% set pm_time = pm_time + timedelta(days=1) %}
                  {% endif %}
                  {% set parsed_time = am_time if am_time < pm_time else pm_time %}
                  {{ parsed_time.strftime('%Y-%m-%d %H:%M:%S') }}
                {% else %}
                  {{ as_timestamp(raw_datetime) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
                {% endif %}
          - service: todo.add_item
            data:
              item: "{{ reminder }}"
              due_datetime: "{{ due_date_str }}"
              description: >-
                Created by voice command on {{ now() }}. Original request was
                '{{ trigger.user_input.text }}'.
            target:
              entity_id: !input todo_entity
          - delay:
              hours: 0
              minutes: 0
              seconds: 2
          - set_conversation_response: "Done, I will remind you to {{ reminder }} on {{ due_date_str }}."

      - conditions:
          - condition: trigger
            id: fetch_reminders
        sequence:
          - service: todo.get_items
            data:
              status: [needs_action]
            target:
              entity_id: !input todo_entity
            response_variable: tasks
          - set_conversation_response: >-
              {% if tasks['!input todo_entity']['items'] | length == 0 %}
                You have no outstanding tasks.
              {% else %}
                You have {{ tasks['!input todo_entity']['items'] | length }} tasks pending. Here are your tasks:
                {% for task in tasks['!input todo_entity']['items'] %}
                  - {{ task['summary'] }}
                    {% if task['due'] is defined and task['due'] | as_timestamp(default=None) is not none %}
                      (Due at: {{
                        task['due'] | as_timestamp | timestamp_custom("%-d %B at %-I:%M %p", true)
                      }})
                    {% endif %}
                {% endfor %}
              {% endif %}
mode: single

Configurable inputs:

  • Reminder Entity: Set this to the to-do list where you want tasks to be stored.
  • Command Lists: Customise the phrases for adding and fetching tasks.

I’d love to hear how it works for you or if you have suggestions for improving it. Thanks for checking it out, and I hope it makes managing reminders a bit easier! :slight_smile:

3 Likes

This is really cool. Keen to try this with Respeaker and incoming Voice PE!

Having issues with conversation.say in the trace (see below).

Also, it just says “Done” when I request the reminder (may be related to above issue).

Any thoughts?

image

image

Shoot, that’s totally my mistake. I had moved to set_conversation_response in my local automation but missed the change in the blueprint.

Could you maybe re-import the blueprint and see if it works as expected now?

Thank you for sharing, it’s working great so far!

1 Like

If multiple users of HA have their own companion app, and speak to assistant through their app, will it create a unique list per person or consolidated list?

It will use a single list, unfortunately. Considering it’s also possible to use this blueprint on user-less devices (speakers), I left out user-handling, since in those scenarios the user wouldn’t even be known.

1 Like

I wonder if each companion app would have its own ID and whether that is reportable in the HA db, like a activity log tracking from where or whom and what originated each action in HA

1 Like

Yes, working better now. Creates reminder as expected.

When I ask for my reminders, this is what happens, is that normal?

image

Should it read out the reminder?

@jarvis2017home Hmm, that’s strange. Yes, it should read out the automation, just tested it for myself once again and it read it out as expected.

Maybe the extra word at the end threw it off? I’m not sure. If you can share your trace log from the attempt, I can check on it!

Also, are you using it with one of the generative AI options or without?

It does, when it comes from the app. However, I built this for use with the new Voice PE, and that doesn’t (yet) know who is giving commands. Whenever they’re able to build that in though, this will be the first change I make!

Sorry I hadn’t seen the random “Play” at the end of that sentence. Not sure how that happened. I’ve run it again, verbally, through opening assist within HA manually and clicking the mic to give the commands.

I have also issued the same commands using HA Voice PE. To set the reminder it responds correctly, essentially a verbal version of what’s above. When I ask “What tasks are left?”, it jusy says “Done”. Here’s data from the trace:

That’s the first exclamation mark fail.

That’s the second exclamation mark fail.

Here’s my voice setup:

Also, not related to this issue, but a general question. SHould there be a popup at the time of the reminder or similar, to remind the user?

@ronanhalpenny On the popup piece, I’m working on that but right now no.

With regards to your issue, could you download and share the trace log? You can dm me if that’s preferable. Looks like the input Boolean didn’t correctly catch your to-do list (at least that’s what I can glean from the screenshots) but that doesn’t seem like a thing that should happen

Hey, this is a list entry. Is this correct?
Schowek01

Schowek02