rianadon / timer-bar-card

A progress bar display for Home Assistant timers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Specify array or direct values

SLaks opened this issue · comments

I'd like to configure a single timer-bar-card to display an arbitrary number of timers from an arbitrary number of Google Home devices.

#19 (comment) works for Google Home timers, but I don't want to have to write a separate template sensor for each one.

I can think of two ways to support this:

  1. Add a new mode that consumes an entity's timers attribute (as described in #19) and produces a separate timer bar for each timer in the array (this would involve hard-coding the Google Home integration's timers array format in your source).
  2. Add a new mode that lets me directly pass active_state and *_time values as values, instead of from an entity.
    • I would then use https://github.com/thomasloven/lovelace-auto-entities with a template, or config-template-card or card-templater, to pass these values from the timers array in my own template.
    • This would keep your code generic.
    • This isn't a performance issue, because the template would only change/rerender when a timer is set or removed.

I would also love to add a Dismiss button next to each timer (which would call the google_home.delete_timer service). This would be possible with my second option with no additional code changes; I don't think it would be possible with my first option.

I'd be happy to implement either option and send a PR; which do you prefer?

I'd be happy to implement either option and send a PR; which do you prefer?

You have my attention 😆

I honestly don't feel too strongly about either option. In the 3 years I've had this card on GitHub, Google Home and Amazon Alexa are the only two timer platforms that store a lot of timer info like this in attributes. I wouldn't mind having code specific to a few special cases like these. On the other hand, the second option is more flexible.

The dismiss button would be a great thing to build into the card, especially the mushroom version. There could be a pause and cancel button similar to how there are two buttons in the alarm card:
image

The home assistant actions configuration will make it easy to specify the service to call, and it could be configured like tap_action. Maybe they default to call timer.pause and timer.cancel but can be configured to custom actions. However, I'd like to keep this part as generic as possible. If the arguments to this service call need to be computed specifically from Google Home's timers array, that's a good reason to go with the second, templating option.

I was actually planning to use this in an entities card, adding buttons via Paper Buttons Row.

I'll send a PR when I get a chance.

Do you have any thoughts on exactly what the parameter(s) should look like?

Maybe

type: custom:timer-bar-card
timer_values:
 - name: Timer 1
   state: active
   start_time: ...
   end_time: ...
 - name: Timer 2
   state: active
   start_time: ...
   duration: 1:23
 - name: Timer 3
   state: active
   start_time: ...
   remain_time: 1:23

Paper Buttons Row is definitely a good solution. I'll still probably add the buttons myself because something like Paper Buttons Row doesn't exist for mushroom cards.

As for parameters, ideally the existing parameters can be re-used. The per-timer options override the card options, so you could do something like:

type: custom:timer-bar-card
entities:
 - name: Timer 1
   state: active # I guess this will have to be an extra parameter.
                 # Maybe rename to indicate this is a fake/manual/virtual timer?
   start_time: { fixed: ... }
   end_time: { fixed: ... }
 - name: Timer 2
   state: active
   start_time: { fixed: ... }
   duration: { fixed: 1:23 }
 - name: Timer 3
   state: active
   start_time: { fixed: ... }
   remain_time: { fixed: 1:23 }

You don't think it's confusing to put non-entities in an entities array?

OTOH, that would make it more natural to mix entity-based timers and direct-value timers, so maybe that is better.

Yeah I think it makes sense as you might want a mix of both direct-value and entity-based things. There was just recently an issue here where having an "always-on" timer for calendar events would be useful. That is, the timer is always in active state but the end time is fetched from a calendar event and start time is the entity's last changed property.

Now that I think about it, for consistency how about deprecating state_attribute and adding an attribute state that can be configured like start_time or end_time?

For example,

  - name: Timer 1
   entity: virtual # Make it explicit that this is a non-entity
   state: { fixed: active }
   start_time: { fixed: ... }
   end_time: { fixed: ... }
  - name: Timer 1
   entity: timer.special_timer
   state: { attribute: "timer_status" }
   start_time: { attribute: "timer_start" }
   end_time: { entity: "sensor.timer_end" }

Or this one is just silly:

  - name: Silly Timer
   entity: switch.this_switch_is_useless
   state: { entity: "timer.the_real_timer" }
   start_time: { entity: "sensor.real_timer_start" }
   end_time: { entity: "sensor.real_timer_end" }

More suggestions:

state: {value: active} # I think value makes more sense than fixed here
start_time: { entity: timer.foo, attribute: "timer_start" }

And probably raise an error if entity is specified but no other field uses it (by specifying attribute only).

The *_state fields would apply no matter what form you use, though they would be redundant when specifying a fixed value.

Good suggestions, but I like fixed better since it's consistent with the others. value might have been a better name, but it's too late to change.

Combined entity & attribute is already supported.

There's a few weird edge cases where you might still want an entity but not use it in any of the configuration. For instance, you might want a specific entity to show up when you click the card, but the timer information is all in different entities. So I don't think an error is needed.

Come to think of it, maybe in the case of the google home timer each timer should have entity assigned to it Google Home timer entity so that clicking a timer opens up the information for all of them. As in:

type: custom:timer-bar-card
entities:
 - name: Timer 1
   entity: timer.Google_Home_timers
   state: { fixed: active }
   start_time: { fixed: ... }
   end_time: { fixed: ... }
 - name: Timer 2
   entity: timer.Google_Home_timers
   state: { fixed: active }
   start_time: { fixed: ... }
   duration: { fixed: 1:23 }
 - name: Timer 3
   entity: timer.Google_Home_timers
   state: { fixed: active }
   start_time: { fixed: ... }
   remain_time: { fixed: 1:23 }

I could also see the *_state parameters still being just to reduce the templating. Imagine the ACTIVE variable is either true or false

- entity: sensor.trueorfalse
  state:
    fixed: {{ 'on' if ACTIVE == 'true' else 'off' }}

is equivalent to:

- entity: sensor.trueorfalse
  state:
    fixed: {{ ACTIVE }}
  active_state: on

Which one you like better is personal preference.

Makes sense.

You probably want to keep active_state because it can be used directly, without wrapping in a templater card.

I ran npm test on a fresh clone and got

Test Suites: 6 failed, 4 passed, 10 total
Tests:       15 failed, 15 passed, 30 total
Snapshots:   20 failed, 9 obsolete, 20 passed, 40 total

Is that expected?

It should be ok. Home Assistant changes the HTML they use for cards faster than I can update the tests, so the snapshots are out of date. This is what I get on the main branch:

Test Suites: 6 failed, 4 passed, 10 total
Tests:       13 failed, 17 passed, 30 total
Snapshots:   22 failed, 34 passed, 56 total
Time:        27.386 s
Ran all test suites.

Do a npm run test -- -u to update the snapshots then commit the new snapshots along with your changes. The changes look like pretty inconsequential things to me. For instance:

-           <state-badge _showIcon="true" class="pointer" stateObj="[object Object]" tabindex="0">
+           <state-badge class="pointer" icon="true" tabindex="0">

Fixed by #140