PowerTodoist card for Home Assistant Lovelace UI. This card displays items from selected Todoist projects. This project uses the Todoist API but it is not created by, affiliated with, or supported by Doist.
Powertodoist.mp4
This card is available in HACS (Home Assistant Community Store).
Just search for PowerTodoist Card
in the HACS list or click the badge below:
- Download
powertodoist-card.js
file from the latest release. - Put
powertodoist-card.js
file into yourconfig/www
folder. - Add a reference to
powertodoist-card.js
in Lovelace. There are two ways to do that:- Using UI: Configuration → Lovelace Dashboards → Resources → Click Plus button → Set Url as
/local/powertodoist-card.js
→ Set Resource type asJavaScript Module
. - Using YAML: Add the following code to
lovelace
section.resources: - url: /local/powertodoist-card.js type: module
- Using UI: Configuration → Lovelace Dashboards → Resources → Click Plus button → Set Url as
- Add
custom:powertodoist-card
to Lovelace UI as any other card (using either editor or YAML configuration).
This card can be configured using Lovelace UI editor.
-
Add the following code to
configuration.yaml
:sensor: - name: To-do List platform: rest method: GET resource: 'https://api.todoist.com/sync/v9/projects/get_data' params: project_id: TODOIST_PROJECT_ID headers: Authorization: !secret todoist_api_token value_template: '{{ value_json[''project''][''id''] }}' json_attributes: - project - items - sections - project_notes scan_interval: 30 command_line: - sensor: name: label_colors command: !secret todoist_cmd_with_api_token value_template: > {{ value_json.label_colors | length }} json_attributes: - label_colors scan_interval: 200 rest_command: todoist: method: post url: 'https://api.todoist.com/sync/v9/{{ url }}' payload: '{{ payload }}' headers: Authorization: !secret todoist_api_token content_type: 'application/x-www-form-urlencoded'
👉 The REST command and the
label_colors
sensor are constant and need to be defined only once for each Todoist account used (I recommend using only one and handling any content separation with cleverly filtered projects, sections, and labels).👉 The Sensor definition, on the other hand, can be cloned to allow for different projects, just make sure you set a unique entity name, and set the appropriate
TODOIST_PROJECT_ID
for each one (see below). -
In that
configuration.yaml
, replaceTODOIST_PROJECT_ID
with ID of your selected Todoist project.You can get
TODOIST_PROJECT_ID
from project URL after logging in to your Todoist account in a browser. It usually looks like this:https://todoist.com/app/project/**TODOIST_PROJECT_ID**
orhttps://todoist.com/app/project/name_of_project-**TODOIST_PROJECT_ID**
-
Add this to
secrets.yaml
:todoist_api_token: 'Bearer TODOIST_API_TOKEN' todoist_cmd_with_api_token: 'echo "{\"label_colors\":" $(curl -s https://api.todoist.com/rest/v2/labels -H "Accept: application/json" -H "Authorization: Bearer TODOIST_API_TOKEN") "}" '
-
In that
secrets.yaml
, replace two instances ofTODOIST_API_TOKEN
with your private API Token (clickDeveloper
tab on that page). -
Reload configs or restart Home Assistant.
-
In Lovelace UI, click 3 dots in top-right corner.
-
Click Edit Dashboard.
-
Click Add Card button in the bottom right corner to add a new card.
-
Find Custom: PowerTodoist Card in the list.
-
Choose
entity
. -
Now you should see the preview of the card!
A basic example of using this card in YAML config could look like this:
type: 'custom:powertodoist-card'
entity: sensor.to_do_list
show_header: true
show_completed: 5
use_quick_add: true
Note that the to_do_list
entity name is what Home Assistant created based on the name: To-do List
you specified earlier in the sensor definition.
Spaces and hyphens turned into _
, and everything became lowercase. In case of doubt search your entities in HASS for the correct name.
Name | Type | Default | Description |
---|---|---|---|
type |
string |
required | custom:todoist-card |
entity |
string |
required | An entity_id within the sensor domain. |
show_completed |
integer |
5 |
Number of completed tasks shown at the end of the list (0 to disable). |
show_header |
boolean |
true |
Show friendly name of the selected sensor in the card header. |
show_item_add |
boolean |
true |
Show text input element for adding new items to the list. |
show_item_close |
boolean |
true |
Show close/complete and uncomplete buttons. |
show_item_delete |
boolean |
true |
Show delete buttons. |
show_item_labels |
boolean |
true |
Show item-level labels beneath each item (see filter_labels below). |
show_card_labels |
boolean |
true |
Show card-level labels on top (see filter_labels below). |
show_dates |
boolean |
false |
Show due dates on the labels row. |
use_quick_add |
boolean |
false |
Use the Quick Add implementation, available in the official Todoist clients. Note that Power-Todoist will automatically add your card's project tag, and your filter_section , if specified. |
sort_by_due_date |
string |
(none) | Sort the tasks by their due date. If it is undefined, or 'false' , no sorting occurs. If it is set to 'ascending' , it sorts oldest due dates first. Any other string (I suggest using 'descending' ) will sort older dates last. |
friendly_name |
string |
Todoist |
The card name shown on top uses a somewhat elaborate logic: the default is Todoist , if no name is specified. But if a Section filter is specified, then that section name will be used instead. Finally, if you do use the friendly_name option, it will override anything else. |
icons |
list |
|
A list of 4 icon names from the MDI Library, without the mdi: prefix. Icons will be used for the check mark of checkable items, the bullet of uncheckable items, the plus sign to add items, and the trash can to delete. Defaults as shown are ["checkbox-marked-circle-outline", "circle-medium", "plus-outline", "trash-can-outline"] |
filter_section_id |
integer |
(none) |
Only show tasks from one Todoist section, identified by its id. |
filter_section |
string |
(none) |
Only show tasks from one Todoist section, identified by its name. |
filter_labels |
list |
(none) |
Only show tasks with the specified Todoist labels. See Filtering by Labels below for details on this powerful option. |
filter_show_dates_starting filter_show_dates_ending |
integer or string |
(none) |
Only show tasks with the specified dates window. See Filtering by Dates below for details. |
filter_show_dates_empty |
boolean |
true |
Defines whether tasks without any specified date pass the filter or not. See Filtering by Dates below for details. |
Note that the completed tasks list is cleared when the page is refreshed.
Labels are colorful and beautiful. And useful! Define them in Todoist app, and don't forget to pick your favorite colors there - after some time, they will be picked up by PowerTodoist-card!
The filter_labels
option allows for several possibilities.
- a label name will include items with that label
- if you prefix a label with
!
then it will exclude items with that label. - use a special label called
*
to include items with any label (but not items without any labels at all). - use a special label called
!*
to include items without any labels at all. - you can combine lines with any of the above filters to join these conditions (for nerds, this will be a logical OR of the inclusion filters, but the exclusion filters always defeat anything else).
Label Filter examples | Meaning |
---|---|
filter_labels: - "Blue" - "Green" |
Shows items with either a Green or a Blue label, or both. |
filter_labels: - "!Done" |
Shows items that don't have a Done label. |
filter_labels: - "!Hidden" - "%user%" - "Important" |
Shows items that don't have the Hidden label, and that either have the Important label or a label with the current HASS user name. |
filter_labels: - "For%user%" |
Shows items that have a label composed of the letters For and the current user name. For example, if user is called Joe then a label ForJoe would match. |
When you filter by a single label, that label won't appear graphically under each item; instead, it will appear on the top, next to the list name.
The options governing date filters are very powerful but also quite hard to understand. I believe this is due to inherent ambiguities in the ways we think and talk about time. Things get swapped if we think about a condition from the pespective of the task that has a due date, or from the threshold that we specified for the comparison. And we want to specify relative times (3 hours before), but relative to what? And time moves. And when we say a "within a day" we might mean two things: any time tomorrow, or strictly up to 24 hours from now, but not 25...
So, please bear with me and try to get into my term definitions. I promise I will provide a few simple, ready to use examples in the end, if the complexity is too much for you.
Basic notions:
- I decided to use options to configure a time window, that has a beginning and an end. The tasks that fall between these two moments will get shown in the list, the others will be filtered out.
- Each of the bounds of this window is specified in relative terms to now. For example, I can say the window starts 8 hours before now, or a day after now.
- Since the window is relative to now, it moves forward as time goes by. So the end of the window is what causes events to be admitted into the view, and the start of the window is what causes events to be expired out of view.
- Although in Todoist the date associated with a task is a "due" date, you don't necessarily have to use the tasks' dates like that. You can use them as start dates if you prefer.
- Todoist has a secret "duration" attribute on each task, which (to my knowledge) can only be written and read through the API, programatically. You can use that for the filters.
- if a task in Todoist has a due date that includes a time, it is considered inside the window only if that specific time is inside the window. But if it only has a due day, without a specified time, then it is considered inside the window whenever any part of that day falls inside the window.
Date Filter explanations and examples | Meaning |
---|---|
filter_show_dates_starting |
Defines the start of the dates window, which moves forward expiring tasks out of the view. If you use a number (like -8 or 24 ) it is interpreted as a number of hours. If you use a string like "1" it is interpreted as a number of days.If you omit this setting it won't filter anything, so tasks won't expire by date. |
filter_show_dates_ending |
Defines the end of the dates window, which moves forward bringing new tasks into the view. If you use a number (like -8 or 24 ) it is interpreted as a number of hours. If you use a string like "1" it is interpreted as a number of days.If you omit this setting it won't filter anything, so all future tasks will be visible. |
filter_show_dates_starting: 0 (without any defined filter_show_dates_ending ) |
This is a special case that I use to work with event durations. If the event does not have duration, it simply appears in view when the date arrives, and stays there. But if it has a duration defined (through the API), then it will appear when the date arrives, and expire after the duration ends. This way you can actually specify two moments in a single task, defining exact times for it to show and then disappear. |
filter_show_dates_ending: "0" |
Show items due Today, or already overdue |
filter_show_dates_ending: "5" |
Show items coming Due anytime in the next 5 days. |
Basic behaviour is this:
- marks selected task as completed.
- "uncompletes" selected task, adding it back to the list.
- deletes selected task (gray one deletes it only from the list of completed items, not from Todoist archive).
- Input adds new item to the list after pressing
Enter
.
But with this card, almost everything is programmable :-), so in the configurations you can optionally create lists of custom actions to run when the user does something. These action lists use the following headers according to the user event:
User Event | Triggered by | Default actions (if no custom actions are specified) |
---|---|---|
actions_close | A tap on the close button (checking a task as done) | Close (complete) the task as done in Todoist. |
actions_dbl_close | A double-tap on the close button (checking a task as done) | Nothing |
actions_content | A tap on the content (text) of the task | Open dialog box to update the text of the task. |
actions_dbl_content | A double-tap on the content (text) of the task | Nothing |
actions_description | A tap on the desciption text of the task, if it is defined in Todoist. | Open dialog box to update the description of the task. |
actions_dbl_description | A double-tap on the desciption text of the task, if it is defined in Todoist. | Nothing |
actions_label | A tap on any of the task's labels (currently it is not possible to differentiate taps on different labels). | Nothing |
actions_dbl_label | A double-tap on any of the task's labels (currently it is not possible to differentiate taps on different labels). | Nothing |
actions_delete | A tap on the delete button to the right of the task. | Delete the task in Todoist. |
actions_dbl_delete | A double-tap on the delete button to the right of the task. | Nothing |
actions_uncomplete | A tap on the task uncomplete button on a recently completed task (shown at the bottom). | Undo the task completion of a recently completed task. |
actions_dbl_uncomplete | A double-tap on the task uncomplete button on a recently completed task (shown at the bottom). | Nothing |
actions_yourActionName | Not really a user event, but rather a way to add your own "sub-routines" (as many as you want). Just give them unique names such as action_domystuff and list any desired actions inside.The way to call these subroutines from other places is by using the match action (see below). So a typical flow would be a user event such as action_close includes a match action, which then conditionally triggers action_domystuff . |
Nothing |
Under those headers, you can use a list of actions to specify custom behaviours. Your options for the actions are:
Custom Action | What it does |
---|---|
close |
Closes (completes) the item in Todoist. |
delete |
Deletes the item in Todoist. |
move |
Moves the item in Todoist to the next section. If it's currently in the last section, item will be moved to the special "(No section)" section. |
confirm |
Opens a dialog box asking the user to confirm the action. If the user approves, action continues, otherwise it is cancelled. Specify an optional string for a custom confirmation text. |
toast |
Flashes a message for a few seconds giving some information to the user. |
update |
Sets new values to the item's fields in Todoist. This is a list which allows all Todoist field types: content , description , priority , collapsed , assigned_by_uid , responsible_uid , day_order You can use variables here. One of the variables can be %input% which will cause the user to be prompted for the value. use prompt_texts to control the dialog box displayed. |
prompt_texts |
Not really an action, but you can use this to set a couple of strings to be used in other actions. Use two strings separated by the | character. The first will be the dialog box title, the second will be the default value presented in the input box. The variable %content% will be useful here to show the current value. So, for example, "Insert new name:|%content%" will set the prompt for an update action that references %input% , asking the user to give a new name, showing the current name in the input box, so it can be easily edited. |
service |
Calls the specified service in Home Assistant. This is very powerful, you can use it to trigger automations and scripts! It is the action that contains a thousand possibilities! 🚀 And this is what makes the PowerTodoist card really a Home Assistant thing - not just an interface to your Todoist. Examples: service: automation.notify_me or service: script.do_it_all |
label |
Here label is a verb! You use this action to label the current item as you prefer. Use a list of label names. If you prefix a label name with a ! that label will be removed, instead of added. Use !* to clear all labels, !_ to clear all labels starting with underscore, !! to clear all labels except those starting with underscore. |
add |
A list of texts that will be sent as Quick Add to Todoist. More details about the syntax below. Remember to specify Project, section and labels, as necessary to match your filters and ensure the new item is visible where you want it. |
allow |
A list of user names that will be allowed to execute all the actions in the handling of the current event. To allow everyone, simply don't use this option. |
match |
A list of triplets that describe conditions. Each triplet looks like this: [field, value, action_domystuff] .The field is one of the item fields as listed here. The value will be matched to that field (simple fields get simple comparisons, while array fields test if the value is included in the array). If there is a match, then the custom action gets executed. This is a very powerful way of creating conditions to invoke subroutines when handling an event, allowing you to do different things for different users, or according to some label on the item. Note that not everything is tested, and not everything will work, there are many scenarios and data types, and I am not building a full programming language here... but even the basic usage will prove very useful. |
emphasis |
Temporarily adds a CSS class to the item. For example, emphasis: special will add a CSS class called powertodoist-special . This class has to be defined in the card's code, which currently is a bit static and only has that specific "special" class. Later I can try to generalize this a bit. |
The items in this Actions table must always appear below a user Event from the previous table, like this:
- actions_delete
- confirm
- delete
Actions are executed in the order given. If you include a list of actions for an event, the default actions won't be executed unless you specify them explicitly.
This feature is undergoing a major re-factoring and might not work perfectly well in all places. But the general idea is that you can use these in any configuration option and they will get substituted, if the value is available (makes sense in that context). In case of doubt, just try it and see how it goes.
Variable name | Text that will be substituted |
---|---|
%was% |
Previous value |
%input% |
Value returned from a prompt shown to the user. The prompt can be customized with prompt_texts action. |
%line% |
A new line character. Allows breaking lines in places where it would be difficult to add a new line in YAML. |
%user% |
The current Home Assistant user name. This is also super powerful to build multi-user systems. You can create separate lists per user, and you can use labels with user names to move things from one to the other. Note that this is not the Todoist user names; it is meant for use with a single Todoist user, the trick is to use labels or sections to separate tasks by HASS users. |
%date% |
The current date, formatted as specified by the date_format option. Default format is "mmm dd H:mm" Complete formatting options are documented here. |
%str_labels% |
The current items labels, all concatenated as a comma-separated string. |
%project_notes% |
In Todoist, you can add notes at the Project level, not just at the item level. You can access the first of these notes with this variable. You can also use %project_notes_2% , %project_notes_3% , etc, to access the other notes. |
Let me know if you have other ideas for variables that could prove useful.
👉 Have a look at this demo file: https://github.com/pgorod/power-todoist-card/blob/main/todoist_demo.yaml
- Create an automation with whatever triggers and conditions you want.
- For the actions, use Call Service
- Then you should have an option available called
RESTful command: todoist
(internally,rest_command.todoist
which you defined inconfiguration.yaml
). - Enter the following in the Service data box:
service: rest_command.todoist
data:
url: quick/add
payload: "text=Auto created at ({{ now().strftime('%H:%M') }}) #myproject @mylabel"
You can use the full power of Todoist's Quick add feature that will parse the text of the task to be created. It can include...
- due date (in free form text)
- #project
- @label
- +assignee
- /section
- // description (at the end)
- p2 priority
To get this right, I suggest you try your text first directly in the Todoist app, before moving it into the HASS automation.
You can also use the power of Home Assistant's templating language enclosed in {{ }}
brackets, as my example shows.
You can use as many of these cards as you want in your dashboards, of course. But I find that this looks particularly cool, and works in a particularly functional way, if you combine this card with the HACS Swipe card. Just have a card for each Todoist section, and put them all together in a Swipe card, to get the feeling of a Kanban. Use the move
action to move items to the next card.
Or use one card per user (family member) for home tasks that you want everyone to be able to see. You can check everybody's progress by swiping sideways. I even like to use a final card which is a Markdown card with home rules or instructions for the use of the Task list.
- many options are only available through YAML configuration, but could easily be added to the UI configuration. If only somebody would do this and test properly and create a PR... for the most part, you'd just have to copy existing code for the other options.
- ability to set icon colors
- I'd love to have actions you can trigger with long taps. But this is out of my Javascript league, I am not a JS guy, this is the first project I've done in JS, and I can't even say that I've learned it, I just stumbled along and did it :-)
- Automations can add Todoist tasks (with all the power of the Quick Add feature). But they can't change existing tasks, which would definitely be useful. This would require some way of focusing in on a specific task, since you don't have such context in the Automations. I haven't thought of a nice clean way of achieving this.
This project is licensed under the MIT license.
Copyright for portions of project PowerTodoist-card are held by Konstantin Grinkevich as part of project Todoist-card. All other copyright for project PowerTodoist-card is held by pgorod
That was a lot of work 😅! If you enjoy and use this card, I'd appreciate it if you can sponsor my work. I'm actually trying to make a living from Github sponsorships, mostly from other projects, but Home Assistant users are numerous, every small donation will also help! Thanks, I really appreciate it!
Note that you pick a one-time amount and select any value you want.