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 :
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.