[Custom Component] Activity Manager - Keep track of recurring tasks

I have several recurring tasks that happen with some frequency where I want to reset the clock when I do it. Several of us solved this with a combination of helpers, templates, and scripts.

I built Activity Manager to solve for this in a simpler way, while still supporting maximum flexibility. This custom component is heavily inspired by the core Shopping List integration, so major thanks to the HA team.

  • Activity Manager - the custom component with support for HACS installation and in-UI setup.
  • Activity Manager Card - a companion Lovelace card design to let you manage activities and reset timers.


Create cards to group related activities in their own card


Switch to “manager” mode to manage activities


This being my first Custom Component, I’m sure there are several things I can do better (e.g. test coverage, conform to HA/python patterns, etc.), but it’s a learning experience.

3 Likes

This looks great! Playing around with a bit and it’s something I’ve been looking for quite a while.
(Just a headsup, the readme for the card says to add the repository under integrations, but this should be lovelace)

I agree with @Slalamander that this looks great. I’ll give it a shot with some maintenance chores that I’ve got coded up with a bunch of helpers and automations.

Thanks - corrected!

really great! gave it a try and it is exactly what I was searching for! since check-button-card (GitHub - custom-cards/check-button-card: Check Button Card is a button that tracks when it is last pressed, for the Home Assistant Lovelace front-end using MQTT auto discovery.) is no longer maintained, I was looking for a replacement.

there are still some flaws; but overall it’s already great!

would appreciate if the card could be filtered for due tasks only. Also overdue tasks are only colored in red - not so visible at the first glance!

thanks for contributing!

Awesome, i m looking forward how does it progress. Is there any way to trigger an automation when a task is over due?

Yup! A time triggered automation is totally possible and looks like you landed an automation in your thread here.

Let me know if you need more help

Filtering the card itself is a great feature suggestion. I can look to support that.

1 Like

Yes i did, thanks a lot!

good job really nice
i hope there will be a german translation later

Hi all I published 0.0.9 today with a few improvements.

@sir106 - you can now include showDueOnly: true in the card config to show only due tasks.

I also renamed a couple classes so you can more easily use CardMod

type: custom:activity-manager-card
category: Workout
showDueOnly: true
card_mod:
  style: |
    .am-due {
      background-color: red;
      color: white !important;
      padding: 5px;
      border-radius: 5px;
    }

1 Like

@optimalhome - really appreciate! thanks for the enhancement, works really great…

this custom component is already one of my top favorites!!!

when playing around, I found two minor bugs using header and category options. See github for pull request fixing these two.

Great Work @OptimalHome. I saw your example of a notification for Android. However, I’m struggling to do the same for iOS with multiple lines for the due tasks. Do you have an example?

I don’t have an iOS device, so can’t verify, but I found this example

Hi all I recently released 0.0.4 of the integration and 0.0.12 of the card.

A lot of improvements, I want to cover:

  • Re-styled the card to match the Tile Card for a most consistent feel
  • A visual card editor to make it easier to know what the card can do
  • Lots more customization - change the action button text and style activities that are due soon
  • Activities can now have frequency in days, hours, minutes, and seconds

In the next release I’m moving to sensor entities which are tied to the integration. This will make the component more consistent with HA integrations.

Also, for those that like the integration but not the card, I’ll share some fun I had with custom:button-card:

type: custom:auto-entities
filter:
  include:
    - integration: activity_manager
      attributes:
        category: Workout
      options:
        type: custom:button-card
        show_state: true
        show_name: true
        show_label: false
        icon: |
          [[[
            var l = entity.attributes.friendly_name.charAt(0).toLowerCase();
            var icon;
            switch(entity.attributes.friendly_name) {
              case "Running":
                icon = `mdi:run-fast`;
                break;
              case "Chest":
                icon = `mdi:weight-lifter`;
                break;
              case "Arms":
                icon = `mdi:dumbbell`;
                break;
              case "Cycling":
                icon = `mdi:bike-fast`;
                break;
              default:
                icon = `mdi:alpha-${l}-box`;
            }
            return icon;
          ]]]
        state_display: |
          [[[
            var last_completed = new Date(entity.attributes.last_completed);
            var due = new Date(last_completed.valueOf() + entity.attributes.frequency_ms);
            return `
              by ${due.toLocaleDateString("en-US", {weekday: 'short', month: 'short', day:'numeric', year:'numeric'})}
            `;
          ]]]
        styles:
          card:
            - padding: 12px
            - '--mdc-ripple-press-opacity': 0
          grid:
            - grid-template-areas: '"i n" "i s"'
            - grid-template-columns: min-content 1fr
            - grid-template-rows: min-content min-content
          img_cell:
            - background-color: rgba(var(--rgb-primary-text-color), 0.05)
            - border-radius: var(--icon-border-radius)
            - border-radius: 50%
            - place-self: flex-start
            - width: 42px
            - height: 42px
            - margin-right: 12px
          icon:
            - color: var(--disabled-text-color)
            - width: 20px
            - height: 20px
          name:
            - justify-self: flex-start
            - align-self: center
            - font-size: 14px
            - font-weight: bold
            - color: var(--primary-text-color)
          state:
            - justify-self: flex-start
            - align-self: center
            - font-size: 12px
            - color: rgb(114,114,114)
        state:
          - value: |
              [[[
                var last_completed = new Date(entity.attributes.last_completed);
                var due = new Date(last_completed.valueOf() + entity.attributes.frequency_ms);
                var now = new Date();
                return due < now;
              ]]]
            styles:
              img_cell:
                - background-color: '#ff4a4a14'
              icon:
                - color: '#ff4a4a'
            operator: template
        tap_action:
          action: call-service
          service: activity_manager.update_activity
          service_data:
            category: '[[[ return entity.attributes.category; ]]]'
            name: '[[[ return entity.attributes.friendly_name; ]]]'
        confirmation:
          text: |
            [[[ 
              return `Did you complete ${entity.attributes.category}\\${entity.attributes.friendly_name}?` 
            ]]]
  exclude: []
card:
  square: false
  type: grid
  columns: 2
show_empty: true
card_param: cards
1 Like

Can anyone tell me how I can mark an activity DID IT by scanning an NFC tag?

Created the below automation but it doesn’t work:

alias: NFC - KATTENBAK DONE
description: “”
trigger:

  • platform: tag
    tag_id: 4a0987a5-c59c-40aa-b695
    condition:
    action:
  • service: activity_manager.update_activity
    data:
    name: Kattenbak
    mode: single

@OptimalHome thanks for the custom component. We are looking forward to updates.
I did something similar to your button-card with some minor changes. Thought I would share. I was trying to get creative since the native card seemed not to work in non-management mode.

When a task is clicked indicating it is complete. It automatically moves to the completed section. Anything in the completed section can be clicked to be sent back up. I did the filtering all with auto-entities at first but started to see it get really slow so I got creative with auto-entities and card-mod.
image
The following is the “Configuration Dashboard”

I think you are missing a property needed to mark a task complete. Add one of the following:

last_completed: “2024-02-11 19:30:00”
now: true

Well that’s not good! I’m using the latest version of the official card and it does work for me. So I’m definitely interested in fixing your issue.

I like your setup! Great job!

Thank you for this! It’s been what I’ve been wanting to have so i don’t forget my daily tasks and if I’ve done it already

Is it posible to change the icon to green if It’s been done this day? For a quicker visual confirmation

type: custom:auto-entities
filter:
  include:
    - integration: activity_manager
      attributes:
        category: Dagliga
      options:
        type: custom:button-card
        show_state: true
        show_name: true
        show_label: false
        icon: |
          [[[
            var l = entity.attributes.friendly_name.charAt(0).toLowerCase();
            var icon;
            switch(entity.attributes.friendly_name) {
              case "Medicin":
                icon = `mdi:pill-multiple`;
                break;
              case "Stretcha":
                icon = `mdi:human`;
                break;
              case "Vattna":
                icon = `mdi:flower`;
                break;
              case "5 Saker":
                icon = `mdi:trash-can-outline`;
                break;
              default:
                icon = `mdi:alpha-${l}-box`;
            }
            return icon;
          ]]]
        state_display: |
          [[[
            var last_completed = new Date(entity.attributes.last_completed);
            var due = new Date(last_completed.valueOf() + entity.attributes.frequency_ms);
            return `
              by ${due.toLocaleDateString("en-US", {weekday: 'short', day:'numeric'})}
            `;
          ]]]
        styles:
          card:
            - padding: 12px
            - '--mdc-ripple-press-opacity': 0
          grid:
            - grid-template-areas: '"i n" "i s"'
            - grid-template-columns: min-content 1fr
            - grid-template-rows: min-content min-content
          img_cell:
            - background-color: rgba(var(--rgb-primary-text-color), 0.05)
            - border-radius: var(--icon-border-radius)
            - border-radius: 50%
            - place-self: flex-start
            - width: 42px
            - height: 42px
            - margin-right: 12px
          icon:
            - color: var(--disabled-text-color)
            - width: 20px
            - height: 20px
          name:
            - justify-self: flex-start
            - align-self: center
            - font-size: 14px
            - font-weight: bold
            - color: var(--primary-text-color)
          state:
            - justify-self: flex-start
            - align-self: center
            - font-size: 12px
            - color: rgb(114,114,114)
        state:
          - value: |
              [[[
                var last_completed = new Date(entity.attributes.last_completed);
                var due = new Date(last_completed.valueOf() + entity.attributes.frequency_ms);
                var now = new Date();
                return due < now;
              ]]]
            styles:
              img_cell:
                - background-color: '#ff4a4a14'
              icon:
                - color: '#ff4a4a'
            operator: template
        tap_action:
          action: call-service
          service: activity_manager.update_activity
          service_data:
            category: '[[[ return entity.attributes.category; ]]]'
            name: '[[[ return entity.attributes.friendly_name; ]]]'
        confirmation:
          text: |
            [[[ 
              return `Har du gjort: ${entity.attributes.friendly_name}?` 
            ]]]
  exclude: []
card:
  square: false
  type: grid
  columns: 2
show_empty: true
card_param: cards

Edit: It seems like when i press on the button to mark it as done, nothing happens after i confirm it. I must go to the manager card list and mark it done there. What have i messed up? :sweat_smile:

Cheers!