Nerwyn/service-call-tile-feature

Timers / read only sliders

Jab2870 opened this issue ยท 9 comments

Is your feature request related to a problem? Please describe.

I currently use the timer-bar-card to display the amount of time an entity has been "on", when that entity turns itself off after a predefined time. This feels similar to the Spotify seeking example given in the readme.

This is what I am hoping to re-create:

image

Describe the solution you'd like

The "value" of the slider I would like to be templateable, allowing me to get how long an entity has been on, and for the slider to be set to be read only / not draggable.

Describe alternatives you've considered

I am currently using the custom:timer-bar-card card, although am trying to move to tile cards where possible.

Additional context

type: custom:service-call
entries:
  - type: slider
    range:
      - 0
      - '{{ states("number.heating_downstairs_timeout") }}'
    thumb: line
    value: '{{as_timestamp(now()) - as_timestamp(switch.heating_downstairs_relay.last_changed) | float}}'

I am aware that the value option I've used here isn't anywhere. As far as I can tell, value_attribute is used everywhere. However, given this isn't an attribute on the entity, I felt maybe it wasn't appropriate to overload that option.

value_attribute refers to the attribute (or just state) that should be used for the custom tile features internal value and wouldn't be used like that, but I get what you mean.

I should be able to calculate the current timer value and have the slider update to accurately display that. I don't want to make the slider not do anything when tapped by default, but should also add some logic so that it does nothing if tap_action.action is none or not set.

I've got timers working as of the latest alpha with this config:

type: tile
entity: timer.timer_test
features:
  - type: custom:service-call
    entries:
      - type: slider
        value_attribute: elapsed
        thumb: flat
        slider_style:
          height: 10px
          width: 90%
          justify-content: flex-end
          right: 0px
        background_style:
          height: 10px
          border-radius: 12px
          width: 90%
          right: 0px
        label_style:
          justify-content: flex-start
        style:
          height: 12px
          border-radius: 0px
          flex-direction: row
        label: |-
          {% set minutes = (VALUE / 60) | int %}
          {% set seconds = VALUE - 60*minutes %}
          {{ minutes }}:{{ 0 if seconds < 10 else "" }}{{ seconds | int }}
        step: 1
        range:
          - 0
          - >-
            {% set hms = state_attr("timer.timer_test", "duration").split(":")
            %}

            {{ (hms[0] |int ) * 3600 + (hms[1] | int) * 60 + (hms[2] | int)
            }}      
  - type: custom:service-call
    entries:
      - type: button
        icon: mdi:timer-check
        tap_action:
          action: call-service
          service: timer.start
          target:
            entity_id: timer.timer_test
      - type: button
        icon: mdi:timer-pause
        tap_action:
          action: call-service
          service: timer.pause
          target:
            entity_id: timer.timer_test
      - type: button
        icon: mdi:timer-cancel
        tap_action:
          action: call-service
          service: timer.cancel
          target:
            entity_id: timer.timer_test

image

elapsed isn't an actual attribute, but I'm using it as a fake one just for timers so other attributes can be accessed by users as needed.

TODO:

  • Make slider do nothing and not change position or value if tap_action.action is none.
  • Figure out what's causing the render delay.
    • Probably due to value not being set until the interval delay happens, I should set the value once before setting the interval.

That is fantastic, thank you for implementing this so quickly!

I have not yet experimented, but will do after work. However, from reading your code, it does appear that I would need to use Home Assistant's timer entities for the elapsed value_attribute to work. Is that correct?

That certainly works for one of my use cases, but a number of my devices implement the timer onboard, rather than using Home Assistant's timers. My heating for example, consists of a relay and a timeout

image

The heating controller turns it off after an hour, without relying on home assistant's timers.

That is why I used the template {{as_timestamp(now()) - as_timestamp(switch.heating_downstairs_relay.last_changed) | float}} in my example.

That template wouldn't have worked anyway, since templates only update when entities change. I wouldn't be able to make value update frequently without a lot of additional specialized logic, and there's a lot of logic around slider values that would be difficult to make user customizable.

Why not create an automation that sets a timer using the heating controller information?

alias: Heating Timer Trigger
description: ""
trigger:
  - platform: state
    entity_id:
      - switch.heating_downstairs_relay
    to: "on"
    from: "off"
condition: []
action:
  - service: timer.start
    target:
      entity_id: timer.heating_downstairs
    data:
      duration: >-
        {% set seconds =  states("number.heating_downstairs_timeout") %}
        {% set minutes = (seconds / 60) | int %}
        {% set seconds = seconds - 60 * minutes %}
        {% set hours = (minutes / 60) | int %}
        {% set minutes = minutes - 60 * hours %}
        {{ '%02d' % hours }}:{{ '%02d' % minutes }}:{{ '%02d' % seconds }}
mode: single

Fixed the late rendering and made the slider not interactable if tap_action.action is set to none. Here's an even better read only timer slider config:

features:
  - type: custom:service-call
    entries:
      - type: button
        value_attribute: elapsed
        label: >-
          {% set minutes = (VALUE / 60) | int %} {% set seconds = (VALUE - 60 *
          minutes) | int %} {{ minutes }}:{{ 0 if seconds < 10 else "" }}{{
          seconds | int }}
        style:
          overflow: visible
          height: 12px
          border-radius: 0px
          '--color': none
      - type: slider
        tap_action:
          action: none
        value_attribute: elapsed
        thumb: flat
        style:
          flex-basis: 1200%
          height: 10px
          '--tooltip-label': >-
            {% set minutes = (VALUE / 60) | int %} {% set seconds = (VALUE - 60
            * minutes) | int %} {{ minutes }}:{{ 0 if seconds < 10 else "" }}{{
            seconds | int }}
        step: 1
        range:
          - 0
          - >-
            {% set hms = state_attr(config.entity, "duration").split(":") %} {{
            (hms[0] |int ) * 3600 + (hms[1] | int) * 60 + (hms[2] | int)
            }}      
      - type: button
        value_attribute: duration
        label: '{% set hms = VALUE.split(":") %} {{ hms[1] | int }}:{{ hms[2] }}'
        style:
          overflow: visible
          height: 12px
          border-radius: 0px
          '--color': none
  - type: custom:service-call
    entries:
      - type: button
        icon: mdi:timer-check
        tap_action:
          action: call-service
          service: timer.start
          target:
            entity_id: timer.timer_test
      - type: button
        icon: mdi:timer-pause
        tap_action:
          action: call-service
          service: timer.pause
          target:
            entity_id: timer.timer_test
      - type: button
        icon: mdi:timer-cancel
        tap_action:
          action: call-service
          service: timer.cancel
          target:
            entity_id: timer.timer_test
type: tile
entity: timer.timer_test

image

As for supporting devices that have internal timers but do not have timer entities - I don't think there's a good way to do so in a standardized way. The implementation wouldn't be standard across all devices, and the devices aren't using the same entity or attribute names or time formats. Like your heater doesn't provide a finishes at datetime or a remaining time sensor.

It should be possible to create timer helpers from the existing heater entities, and those should work with this card now.

@Jab2870 if you're okay with creating timer helpers for internal device timers, then the latest 3.3.2 beta should be the release candidate for this feature.

Thanks very much @Nerwyn . Creating timers like that should be fine. Thanks. I'm using that beta and all seems good. Thanks again.

Added in 3.3.2