rianadon / timer-bar-card

A progress bar display for Home Assistant timers
Other
340 stars 15 forks source link

Allow state: {fixed: 'active'} instead of using an entity #140

Closed SLaks closed 3 months ago

SLaks commented 3 months ago

This refactors a bunch of the card code to make state objects optional.

It also makes accessors consistent.

SLaks commented 3 months ago

image

To use this with Google Home timers, install the following cards from HACS:

type: custom:auto-entities
filter:
  template: >
    {%- set results = namespace(timers = []) -%}

    {%- set state_map = {
      "set": "active",
      "ringing": "active",
    } -%} {%- set icon_map = {
      "set": "mdi:timer",
      "ringing": "mdi:timer-alert",
      "paused": "mdi:timer-pause",
    } -%} {%- for entity_id in integration_entities('google_home') if entity_id
    is contains '_timers' -%}
      {%- set multiple = not loop.first or not loop.last -%}
      {%- set suffix = '' if not multiple
                  else ' – ' + state_attr(entity_id, 'friendly_name')
                      | replace(' timers', '') -%}
      {%- for t in state_attr(entity_id, 'timers') -%}
        {%- set label  = t.label if t.label else t.duration | regex_replace('^0:0*', '') + ' timer' -%}
        {%- set results.timers = results.timers + [{
          'icon': icon_map[t.status],
          'duration': {'fixed': t.duration},
          'end_time': {'fixed': t.local_time_iso},
          'name': label + suffix,
          'state': {'fixed': state_map[t.status] | default(t.status)},
          "extend_paper_buttons_row": {
            "position": "right",
            "buttons": [
              {
                "icon": "mdi:close",
                "tooltip": "Dismiss",
                "tap_action": {
                  "action": "call-service",
                  "service": "google_home.delete_timer",
                  "service_data": {
                    "timer_id": t.timer_id,
                    "entity_id": entity_id,
                    "skip_refresh": False,
                  }
                }
              }
            ]
          }
        }] -%}
      {%- endfor -%}
    {%- endfor -%} {{ results.timers }}
card:
  type: custom:timer-bar-card
show_empty: false

This will generate one row per timer on every Google Home device in HA; if you have multiple Google Homes, each timer will also be labeled with its device.

rianadon commented 3 months ago

Thanks so much! That's quite the hefty PR. I'll take a read though it this weekend.

SLaks commented 3 months ago

Yes; there is no way to make this shorter.

FYI, for the future, I recommend building this kind of code in 2 separate parts: A model class that takes the config and exposes resolved properties (eg, name, total and remaining time), and the card layout code that consumes the model only. This keeps the config system separate from the rendering, and would mean that a change like this one wouldn't touch the rendering code at all.

rianadon commented 3 months ago

Yeah that's great advice. If I had to redo this card that would be a great way to structure it. This card originated just as me uploading the timer part of my opensprinkler card to a separate repository. I never expected it to grow this much.

The PR overall looks great. Thanks so much for writing this!

dnestico commented 1 month ago

Finally this works! But not sure why it won't display the name of the device with the active timer for me, weird.

Screenshot 2024-05-18 at 9 15 54 PM
SLaks commented 1 month ago

My code above only adds the device name if there are multiple Google Home devices.

To always add the device name, remove '' if loop.first and loop.last else

Also check whether it's getting truncated.

dnestico commented 1 month ago

I did CTRL-F and found 2 of those lines in the code, not sure exactly what I need to change sorry.

    {%- set multiple = not loop.first or not loop.last -%}
      {%- set suffix = '' if loop.first and loop.last
                  else ' – ' + state_attr(entity_id, 'friendly_name')
                      | replace(' timers', '') -%}
Screenshot 2024-05-19 at 7 58 26 PM
SLaks commented 1 month ago

The second one (which contains else).

The first line is currently unused; I just edited the instructions to fix that.

dnestico commented 1 month ago

Ok so I just tried doing this updated code and the card just disappears with it unfortunately doesn't work....

type: custom:auto-entities
filter:
  template: >
    {%- set results = namespace(timers = []) -%}

    {%- set state_map = {
      "set": "active",
      "ringing": "active",
    } -%} {%- set icon_map = {
      "set": "mdi:timer",
      "ringing": "mdi:timer-alert",
      "paused": "mdi:timer-pause",
    } -%} {%- for entity_id in integration_entities('google_home') if entity_id
    is contains '_timers' -%}
      {%- set multiple = not loop.first or not loop.last -%}
      # {%- set suffix = '' if not multiple
      #             else ' – ' + state_attr(entity_id, 'friendly_name')
      #                 | replace(' timers', '') -%}
      {%- for t in state_attr(entity_id, 'timers') -%}
        {%- set label  = t.label if t.label else t.duration | regex_replace('^0:0*', '') + ' timer' -%}
        {%- set results.timers = results.timers + [{
          'icon': icon_map[t.status],
          'duration': {'fixed': t.duration},
          'end_time': {'fixed': t.local_time_iso},
          'name': label + suffix,
          'state': {'fixed': state_map[t.status] | default(t.status)},
          "extend_paper_buttons_row": {
            "position": "right",
            "buttons": [
              {
                "icon": "mdi:close",
                "tooltip": "Dismiss",
                "tap_action": {
                  "action": "call-service",
                  "service": "google_home.delete_timer",
                  "service_data": {
                    "timer_id": t.timer_id,
                    "entity_id": entity_id,
                    "skip_refresh": False,
                  }
                }
              }
            ]
          }
        }] -%}
      {%- endfor -%}
    {%- endfor -%} {{ results.timers }}
card:
  type: custom:timer-bar-card
show_empty: false
SLaks commented 1 month ago

I don't mean comment out those lines; I mean delete literally '' if loop.first and loop.last else (to make it unconditional) and nothing else.

dnestico commented 1 month ago

Ok so this is the new code? thanks.

      {%- set suffix =  ' – ' + state_attr(entity_id, 'friendly_name')
                      | replace(' timers', '') -%}
SLaks commented 1 month ago

Exactly