Make tasks smart based on how long something is used, like empty the vacuum bin after xx:xx time of cleaning

Home Assistant is at it’s best when you combine integrations. One thing on my task list was: smarter tasks. So I did that.

You know the situation. After x time of use, some device needs some maintenance. Those tasks are never fun, so you want to do them only when it is needed. You could of course make a repeating task, but that would not know if you actually used the device a lot or not. So using the power of Home Assistant to make things smart is much more fun.

Note: While it is always good to know how things can be done, a part of the below examples has been made way easier by new integrations that were made after I wrote this. Goes to show how fast the Home Assistant ecosystem evolves:

Since you’re still reading, let’s continue with what I did before those integrations were released.

What this does:

  • I made three examples, where three tasks are created:
    • A task for when a device has run for x hours
    • A task for when a device was used x times
    • A task for when a device was not maintained for x days
  • When a task is created, you get an actionable notification.
  • If you press the button in the notification, it completes the task for you
  • You can also complete the task in HA or your favorite task manager
  • When the task is completed, the measuring begins again and the task is removed.

Find out what the state of each task is

For this I integrated my favorite task list. You could also use the local task list. The hardest part when you have the tasks in Home Assistant is to know when you finished a task. Home Assistant has no event for that, so you have to create your own. For that I need to know the state of my favorite tasks.

I created template sensors for each task, to tell me it’s state. The below code goes in templates.yaml
I created sensors for three tasks to tell me the state of the task: “needs_action”, “complete” or “none” (when there is no task). The due date attributes are not needed for the example, but added for convenience so you can see how late you are completing the task.

- trigger:
    platform: time_pattern
    minutes: "/10"
  action:
    - service: todo.get_items
      target:
        entity_id: todo.mijn_taken
      response_variable: tasks
  sensor:
    - name: Stoffie task state
      unique_id: sensor.stoffie_task_state
      state: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Stoffie legen') | map(attribute='status') | list | first | default('none') }}"
      attributes:
        due: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Stoffie legen') | map(attribute='due') | list | first | default('') }}"
    - name: Douche-afvoer task state
      unique_id: sensor.douche_afvoer_task_state
      state: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Douche-afvoer reinigen') | map(attribute='status') | list | first | default('none') }}"
      attributes:
        due: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Douche-afvoer reinigen') | map(attribute='due') | list | first | default('') }}"
    - name: Kalkpatroon task state
      unique_id: sensor.kalkpatroon_task_state
      state: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Kalkpatroon koffiezetter vervangen') | map(attribute='status') | list | first | default('none') }}"
      attributes:
        due: "{{ tasks['todo.mijn_taken']['items'] | selectattr('summary', 'eq', 'Kalkpatroon koffiezetter vervangen') | map(attribute='due') | list | first | default('') }}"

Find out when a task was last completed, and remove the completed task

Next, I need to know when a task is finished. I chose not to look for “completed” in case someone removed a task. So instead, I look for when it is no longer in state “needs_action” and then I remember when that was. This also goes in the templates.yaml file. As soon as I set the date, I remove the task as well:

- trigger:
    platform: state
    entity_id: sensor.stoffie_task_state
    from: needs_action
    not_to:
      - unknown
      - unavailable
  action:
    - service: todo.remove_item
      continue_on_error: true
      data:
        item: 'Stoffie legen'
      target:
        entity_id: todo.mijn_taken
  sensor:
    - name: Stoffie task last completed
      unique_id: sensor.stoffie_task_last_completed
      device_class: timestamp
      state: "{{now()}}"
- trigger:
    platform: state
    entity_id: sensor.douche_afvoer_task_state
    from: needs_action
    not_to:
      - unknown
      - unavailable
  action:
    - service: todo.remove_item
      continue_on_error: true
      data:
        item: 'Douche-afvoer reinigen'
      target:
        entity_id: todo.mijn_taken
  sensor:
    - name: Douche-afvoer task last completed
      unique_id: sensor.douche_afvoer_task_last_completed
      device_class: timestamp
      state: "{{now()}}"
- trigger:
    platform: state
    entity_id: sensor.kalkpatroon_task_state
    from: needs_action
    not_to:
      - unknown
      - unavailable
  action:
    - service: todo.remove_item
      continue_on_error: true
      data:
        item: 'Kalkpatroon koffiezetter vervangen'
      target:
        entity_id: todo.mijn_taken
  sensor:
    - name: Kalkpatroon task last completed
      unique_id: sensor.kalkpatroon_task_last_completed
      device_class: timestamp
      state: "{{now()}}"

An easy way to see how many days ago the task was completed last

Next, I create sensors to tell me how many days it has been since I completed the tasks. While they are not strictly needed, they come in handy later on. Again, this goes in templates.yaml:

- sensor:
    - name: Days_since_stoffie_task_completed
      unique_id: sensor.days_since_stoffie_task_completed
      unit_of_measurement: ""
      state: "{{ (now() - states('sensor.stoffie_task_last_completed') | as_datetime).days }}"
- sensor:
    - name: Days_since_douche_afvoer_task_completed
      unique_id: sensor.days_since_douche_afvoer_task_completed
      unit_of_measurement: ""
      state: "{{ (now() - states('sensor.douche_afvoer_task_last_completed') | as_datetime).days }}"
- sensor:
    - name: Days_since_kalkpatroon_task_completed
      unique_id: sensor.days_since_kalkpatroon_task_completed
      unit_of_measurement: ""
      state: "{{ (now() - states('sensor.kalkpatroon_task_last_completed') | as_datetime).days }}"

How long (or how many times) was a device used

The history stats integration is great for measuring how often something was on, or how long it was on for. Below are two examples for my tasks.

One thing to remember though: History stats only works for as long as the recorder maintains history. So make sure to set the recorder setting purge_days long enough for meaningful results. Because I did not want to set the recorder for too long a period, I also use the day count above as a fallback. Because if a device is not used often, history might not be enough to set off the task. The number of days test will work regardless of history.

On for x hours

To see how long a device was used (in this case, find out how long a vacuum was cleaning, so I know when to clean the bin), I created a sensor in sensors.yaml:

- platform: history_stats
  name: Stoffie_actief_sinds_legen
  entity_id: vacuum.stoffie
  state: "cleaning"
  type: time
  start: "{{ states('sensor.stoffie_task_last_completed') }}"
  end: "{{ now() }}"

On for x times

For the shower, I count how often the shower is used in order to clean the drain (based on a binary sensor from a smart shower head, but you could also determine if a shower was used by making a threshold sensor on humidity):

- platform: history_stats
  name: Gedouched sinds putje schoon
  entity_id: binary_sensor.ble_tracker_3_dsh_showeroccupied
  state: "on"
  type: count
  start: "{{ states('sensor.douche_afvoer_task_last_completed') }}"
  end: "{{ now() }}"

Automating

For the automations, I trigger when an operation finishes rather than when a limit is reached. I check the limit in the conditions. I do this to make sure I do not miss when that happens. I want to make sure the task is made after an operation is completed. Then I cre\te a task, and an actionable notification:

Task to clean the bin of the vacuum

When vacuum has run for 4 hours or more (or when it is been too long for my history setting to keep history, which is 31 days), create a task and send an actionable notification:

alias: Stoffie legen taak maken
description: ""
trigger:
  - platform: state
    entity_id:
      - vacuum.stoffie
    to: docked
    not_from:
      - unavailable
      - unknown
condition:
  - condition: or
    conditions:
      - condition: numeric_state
        entity_id: sensor.stoffie_actief_sinds_legen
        above: 4
      - condition: numeric_state
        entity_id: sensor.days_since_stoffie_task_completed
        above: 31
  - condition: not
    conditions:
      - condition: state
        entity_id: sensor.stoffie_task_state
        state: needs_action
action:
  - service: todo.add_item
    metadata: {}
    data:
      item: Stoffie legen
      due_date: "{{now().date()}}"
    target:
      entity_id: todo.mijn_taken
  - service: notify.mobile_app_in2023
    data:
      message: Stoffie wil graag een lege stofbak
      data:
        actions:
          - action: STOFFIE_BIN_EMPTIED
            title: Afvalbak stoffie geleegd
mode: single

And if the actionable notification button is used: complete the task:

alias: Stoffie legen taak uitgevoerd
description: ""
trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: STOFFIE_BIN_EMPTIED
condition: []
action:
  - service: todo.update_item
    metadata: {}
    data:
      item: Stoffie legen
      status: completed
    target:
      entity_id: todo.mijn_taken
mode: single

Task to clean the drain in the shower

When the shower was used more than 9 times (or when it is been too long for my history setting to keep history, which is 31 days), create a task and send an actionable notification:

alias: Douche-afvoer schoonmaaktaak maken
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.ble_tracker_3_dsh_showeroccupied
    to: "off"
    not_from:
      - unavailable
      - unknown
condition:
  - condition: not
    conditions:
      - condition: state
        entity_id: sensor.douche_afvoer_task_state
        state: needs_action
  - condition: or
    conditions:
      - condition: numeric_state
        entity_id: sensor.gedouched_sinds_putje_schoon
        above: 9
      - condition: numeric_state
        entity_id: sensor.days_since_douche_afvoer_task_completed
        above: 31
action:
  - service: todo.add_item
    metadata: {}
    data:
      item: Douche-afvoer reinigen
      due_date: "{{now().date()}}"
    target:
      entity_id: todo.mijn_taken
  - service: notify.mobile_app_in2023
    data:
      message: Douche-afvoer reinigen
      data:
        actions:
          - action: SHOWER_DRAIN_CLEANED
            title: Douche-afvoer schoongemaakt
mode: single

And then when the action button is pressed:

alias: Douche-afvoer reinigen taak uitgevoerd
description: ""
trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: SHOWER_DRAIN_CLEANED
condition: []
action:
  - service: todo.update_item
    metadata: {}
    data:
      item: Douche-afvoer reinigen
      status: completed
    target:
      entity_id: todo.mijn_taken
mode: single

Task to replace the decalcifier after it was in place for 70 days

The decalcifier in the coffee maker is good for two months, but I’m cheap so I wait a little longer :slight_smile: :

alias: Kalkpatroon taak aanmaken
description: ""
trigger:
  - platform: time
    at: "10:00:00"
condition:
  - condition: numeric_state
    entity_id: sensor.days_since_kalkpatroon_task_completed
    above: 70
  - condition: not
    conditions:
      - condition: state
        entity_id: sensor.kalkpatroon_task_state
        state: needs_action
action:
  - service: todo.add_item
    metadata: {}
    data:
      item: Kalkpatroon koffiezetter vervangen
      due_date: "{{now().date()}}"
    target:
      entity_id: todo.mijn_taken
  - service: notify.mobile_app_in2023
    data:
      message: Kalkpatroon koffiezetter vervangen
      data:
        actions:
          - action: CHALK_UNIT_REPLACED
            title: Kalkpatroon verwisseld
mode: single

And when the notification is confirmed:

alias: Kalkpatroon vervangen taak uitgevoerd
description: ""
trigger:
  - platform: event
    event_type: mobile_app_notification_action
    event_data:
      action: CHALK_UNIT_REPLACED
condition: []
action:
  - service: todo.update_item
    metadata: {}
    data:
      item: Kalkpatroon koffiezetter vervangen
      status: completed
    target:
      entity_id: todo.mijn_taken
mode: single

Get it started

The above needs the last completion date to work. When you build this, that isn’t set yet. To get started, first manually trigger the automation that creates the task. Wait untill Home Assistant has seen the task (it can take over 5 minutes), then complete the task to set the date. Now you’re all set.

7 Likes