Track repetitive tasks with NFC tags

An automation blueprint to track the completion status of a repetitive task.

The task can be marked “complete” by scanning an NFC tag. If a task is due (or overdue), a custom action is triggered.

This is inspired by @Futuresmarthome 's concept: https://www.youtube.com/watch?v=DhU2Jw2-op8

NOTE: This automation only checks task completion status once a day, and therefore is not useful for tasks that need to be completed multiple times in a 24-hour period.

Blueprint

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

blueprint:
  name: Track and Remind about a Task
  source_url: https://raw.githubusercontent.com/nwithan8/configs/main/home_assistant/blueprints/automations/track_and_remind_task.yaml
  description: >
    Track the completion of a repetitive task, and trigger actions when the task is due, overdue or completed.

    Based on Future Smart Home's concept: https://www.youtube.com/watch?v=DhU2Jw2-op8


    NOTE: This automation only checks task completion status once a day, and therefore is not useful for tasks that need to be completed multiple times in a 24-hour period.
  
    
    PRE-REQUISITES:
    
    - Create an input_datetime helper to track the last time the task was completed.
    - Create an NFC tag that will be used to mark the task as completed.

  domain: automation
  input:
    task_name:
      name: Task name
      description: >
        The name of the task to track.
      selector:
        text:
          type: text

    task_interval:
      name: Task interval
      description: >
        How often the task needs to be completed, in days.
      selector:
        number:
          min: 1
          max: 365
          step: 1
          mode: box

    nfc_tag:
      name: NFC tag
      description: >
        The ID of the NFC tag that marks the task as "completed".

        Can be found under Settings -> Tags, and then click on the relevant tag.
      selector:
        text:
          type: text

    date_tracker:
      name: Date tracker
      description: >
        The datetime helper that will track the task completion.
      selector:
        entity:
          filter:
            domain: input_datetime

    status_check_time:
      name: Status check time
      description: >
        What time, every day, this automation will check for incomplete tasks and send notifications.
      selector:
        time:

    due_action:
      name: Due reminder action
      description: >
        What action to take when a reminder needs to be sent about a task due today.
        
        For example, send a notification to a mobile device, turn on a light, change a binary sensor, etc.


        The following variables are available to the action:
          - "task_name": The name of the task (string)
          - "task_due_date": The date the task was originally due (string)
          - "days_since_last_completed": How many days since the task was last completed (integer)
          - "task_interval": How often the task is due (integer)
          - "task_is_due": Whether the task is due today (boolean)
          - "task_is_overdue": Whether the task is overdue (boolean)
      selector:
        action:
      default: []

    overdue_action:
      name: Overdue reminder action
      description: >
        What action to take when a reminder needs to be send about an overdue task.
        
        For example, send a notification to a mobile device, turn on a light, change a binary sensor, etc.
        
        If not set, overdue tasks will use the same action as above.


        The following variables are available to the action:
          - "task_name": The name of the task (string)
          - "task_due_date": The date the task was originally due (string)
          - "days_since_last_completed": How many days since the task was last completed (integer)
          - "task_interval": How often the task is due (integer)
          - "task_is_due": Whether the task is due today (boolean) (always false)
          - "task_is_overdue": Whether the task is overdue (boolean) (always true)
      selector:
        action:
      default: []

    skip_days_of_week:
      name: Days of the week to skip
      description: >
        Which days of the week to skip task completion status checks.

        This has no impact on the completion or due/overdue status of the task; it simply skips checking the status on the specified days.
      selector:
        select:
          multiple: true
          options:
            - label: Monday
              value: "0"
            - label: Tuesday
              value: "1"
            - label: Wednesday
              value: "2"
            - label: Thursday
              value: "3"
            - label: Friday
              value: "4"
            - label: Saturday
              value: "5"
            - label: Sunday
              value: "6"
      default: []

    rolling_completion:
      name: Use rolling completion
      description: >
        If enabled, when marking a task complete, mark it completed at original due date rather than current date.


        For example, assume you have a task that needs to be completed every 7 days. After 10 days, you mark the task as completed.

        If enabled, the "completed date" will be the original due date, three days ago, which means it will be due again 4 days from now.

        If not enabled, the "completed date" will be today, which means it will be due again 7 days from now.


        This can be useful if you don't want your delay in completing the task to affect the next date the task is due.
      selector:
        boolean:
      default: false

    on_completion_action:
      name: Action upon completion
      description: >
        An optional additional action to take when the task has been completed.
        
        For example, send a notification to a mobile device, turn on a light, change a binary sensor, etc.
      default: []
      selector:
        action:

mode: single
max_exceeded: silent

variables:
  task_name: !input "task_name"
  task_interval: !input "task_interval"
  date_tracker: !input "date_tracker"
  rolling_completion: !input "rolling_completion"
  overdue_action: !input "overdue_action"
  skip_days_of_week: !input "skip_days_of_week"
  days_since_last_completed: >
    {% set last_date = states(date_tracker) | as_datetime %}
    {{ (now().date() - last_date.date()).days }}
  task_due_date: >
    {% set last_date = states(date_tracker) | as_datetime %}  
    {{ last_date.date() + timedelta(days=task_interval) }}
  task_is_due: "{{ days_since_last_completed == task_interval }}"
  task_is_overdue: "{{ days_since_last_completed > task_interval }}"

trigger:
  - alias: On schedule
    id: schedule
    platform: time
    at: !input status_check_time
  - alias: When associated NFC tag is scanned
    id: tag_scan
    platform: tag
    tag_id: !input nfc_tag

action:
  - choose:
      - conditions:
          - alias: NFC tag scanned
            condition: trigger
            id: tag_scan
        sequence:
          - alias: Update date tracker to next due date
            service: input_datetime.set_datetime
            entity_id: !input date_tracker
            data:
              datetime: >
                {% if rolling_completion %}
                  {% set last_date = states(date_tracker) | as_datetime %}
                  {{ last_date.date() + timedelta(days=task_interval) }}
                {% else %}
                  {{ now().date() + timedelta(days=task_interval) }}
                {% endif %}
          - alias: Execute "on completion" action if set
            choose:
              - conditions: "{{ true }}"
                sequence: !input on_completion_action
      - conditions:
          - alias: At scheduled time
            condition: trigger
            id: schedule
          - alias: Today is not a skip day
            condition: template
            value_template: "{{ now().date().weekday() | string not in skip_days_of_week }}"
        sequence:
          - choose:
              - conditions:
                  - alias: Task is due today
                    condition: template
                    value_template: "{{ task_is_due }}"
                sequence: !input due_action
              - conditions:
                  - alias: Task is overdue
                    condition: template
                    value_template: "{{ task_is_overdue }}"
                sequence:
                  - if:
                      - alias: Custom overdue action
                        condition: template
                        value_template: "{{ overdue_action != [] }}"
                    then:
                      - alias: Execute overdue action
                        choose:
                          - conditions: "{{ true }}"
                            sequence: !input overdue_action
                    else:
                      - alias: Execute due action
                        choose:
                          - conditions: "{{ true }}"
                            sequence: !input due_action

Install

  1. Click the “Import Blueprint” button above and follow the on-screen instructions to import the blueprint into your Home Assistant.
  2. Create the required entities:
    • Create a new “Datetime” helper to store the last time the specific task was marked “completed”
    • Create/register a new NFC tag that, when scanned, will mark the task as “completed”.
  3. Create a new automation using the blueprint (Settings → Automations & Scenes → “Create Automation” → Select “Track and Remind about a Task” from the list)
    1. Task name: The name of the task. This will be available in the due/overdue/completed actions as {{ task_name }}
    2. Task interval: How often the task needs to be completed, in days (min: 1, max: 365)
    3. NFC tag: The ID of the NFC tag (created earlier) that, when scanned, will mark the task “completed”
    4. Date tracker: The Datetime helper (created earlier) that will store a timestamp of the last time the task was marked “completed”
    5. Status check time: The time, every day, when this automation will run to check for due/overdue tasks and potentially trigger reminder actions.
    6. Due reminder action: An action (or series of actions) to take when a task is due today.
    7. Overdue reminder action: An action (or series of actions) to take when a task is overdue. If not set, will automatically use the same action(s) as Due reminder action.
    8. Days of the week to skip: Optional days of the week to skip running the status check. For example, skip checking for due/overdue tasks on weekends.
    9. Use rolling completion: When marking a task as “completed”, whether to mark it at its original due date or today. Useful if you don’t want the delay in completing the task to affect the next time the task is due.
    10. Action upon completion: Optional action(s) to take when a task is marked as “completed”.


Usage

The automation will execute every day at the set Status check time.

  • If the current day is one of the Days of the week to skip, no further action will happen.

If the Task interval has lapsed, either the Due reminder action or Overdue reminder action will trigger, depending on if the task is due today or before today.

You can mark a task as “completed” by scanning the NFC tag. Any configured Action upon completion will trigger.

Release History:

1.0.0 (January 24, 2024):

  • Initial release
8 Likes

This is really cool, thanks for putting it together.

I’m experiencing difficulty with the {{ }} variables. I’ve filled in the Task Name field and then set the message as is written in a screenshot "{{ task_name }} is due" but when I run that action to test it, the message received by my phone is is due.

Basically the variable isn’t getting parsed/passed to the message. Am I doing something wrong?

Hmm, could you share a screenshot or the YAML of your automation config? And/or the trace of when it ran, specifically the “Changed Variables”? You should see a “task_name” variables, like this:

This is an awesome blueprint! I’ve entered in all of the required information and saved it. Now, how do I display it properly on my dashboard? I can’t seem to find a way to display it with the full task name and a descending numeric value. It’s just showing a date entry. Many thanks for everything!

Here’s my YAML (please let me know if everything looks correct or if I missed something):

alias: Task Reminder - HVAC filter change
description: >-
  Reminder every 60 days to change HVAC filters. Once NFC tag has been scanned,
  the reminder is reset.
use_blueprint:
  path: nwithan8/track_and_remind_task.yaml
  input:
    task_name: HVAC filter change
    task_interval: 60
    nfc_tag: 823c6552-e013-4483-a590-fb81af51aee8
    date_tracker: input_datetime.hvac_filter_change_date
    status_check_time: "00:09:00"
    due_action:
      - service: notify.mobile_app_pixel_7
        data:
          title: Task Reminder
          message: "{{ task_name }} is due!"
    rolling_completion: true
    overdue_action:
      - service: notify.mobile_app_pixel_7
        data:
          title: Task Overdue!
          message: "{{ task_name }} is overdue!"
    on_completion_action:
      - service: notify.mobile_app_pixel_7
        data:
          title: Task Completed!
          message: "{{ task_name }} was completed!"

Hey thanks for the quick reply!

YAML

alias: Doggie flea ointment tracker
description: ""
use_blueprint:
  path: nwithan8/track_and_remind_task.yaml
  input:
    task_name: Doggie Flea Ointment
    task_interval: 31
    nfc_tag: 2587fdf4-fff9-490b-a04d-99c5703839f8
    date_tracker: input_datetime.doggie_flea_tracker
    status_check_time: "20:00:00"
    due_action:
      - service: notify.mobile_app_me
        data:
          message: "{{ task_name }} is due today"
      - service: notify.mobile_app_iphone
        data:
          message: "{{ task_name }} is due today"
      - service: notify.mobile_app_me_galaxy_watch4
        data:
          message: Doggie flea ointment is due today
    overdue_action:
      - service: notify.mobile_app_me_s23
        data:
          message: Doggie flea ointment was due yesterday!
      - service: notify.mobile_app_iphone
        data:
          message: Doggie flea ointment was due yesterday!
      - service: notify.mobile_app_me_galaxy_watch4
        data:
          message: Doggie flea ointment was due yesterday!

Changed Variables:

this:
  entity_id: automation.doggie_flea_ointment_tracker
  state: 'on'
  attributes:
    id: '1706452946901'
    last_triggered: '2024-01-30T11:00:00.273633+00:00'
    mode: single
    current: 0
    friendly_name: Doggie flea ointment tracker
  last_changed: '2024-01-30T09:28:30.465549+00:00'
  last_updated: '2024-01-30T11:00:00.283882+00:00'
  context:
    id: 01HND0D84E70FN38XWY8YXG0H9
    parent_id: null
    user_id: null
trigger:
  id: schedule
  idx: '0'
  alias: On schedule
  platform: time
  now: '2024-01-31T20:00:00.269788+09:00'
  description: time
  entity_id: null
task_name: Doggie Flea Ointment
task_interval: 31
date_tracker: input_datetime.doggie_flea_tracker
rolling_completion: false
overdue_action:
  - service: notify.mobile_app_me_s23
    data:
      message: Doggie flea ointment was due yesterday!
  - service: notify.mobile_app_iphone
    data:
      message: Doggie flea ointment was due yesterday!
  - service: notify.mobile_app_me_galaxy_watch4
    data:
      message: Doggie flea ointment was due yesterday!
skip_days_of_week: []
days_since_last_completed: -28
task_due_date: '2024-03-30'
task_is_due: false
task_is_overdue: false

Task name variable seems to be right.

Hmm, that’s weird. I’m not able to recreate that on my end. As you can see, it populated task_name (“Test ting”) correctly for me:

This blueprint doesn’t really have a visual component to it. The task name only exists in the automation; it’s not an entity that can be visually displayed or is recorded anywhere.

This blueprint only relies on a “last completed” timestamp, so that’s the only entity you’d have to put on a dashboard, as you’ve discovered.

Nate, this is an awesome blueprint. Thank you!

1 Like

Thank you Nate! I wanted to do exactly what you made. You saved me a lot of time.

1 Like

Question: Does the “datetime” entity value persist during resets? I would love to use this to remind/track a medication administration for my dog, given every 28 days. It’s important that the countdown doesn’t get reset by changes to my config or an update/crash

It should, it’s an entity value that is written to HA’s database like any other value.