Service Call Tile Features - Buttons, Sliders, Selectors, and Spinboxes

I actually have an automation that detects when Spotify is running and increases the update frequency when playing or paused. I’m not sure what your media source is, but could something like this possibly work?

alias: Spotify - Refresh Every 5 Seconds While Playing
description: ""
trigger:
  - platform: state
    entity_id:
      - media_player.spotify
    from: idle
condition: []
action:
  - repeat:
      while:
        - condition: or
          conditions:
            - condition: state
              entity_id: media_player.spotify
              state: playing
            - condition: state
              entity_id: media_player.spotify
              state: paused
      sequence:
        - delay:
            hours: 0
            minutes: 0
            seconds: 5
            milliseconds: 0
        - service: homeassistant.update_entity
          data: {}
          target:
            entity_id: media_player.spotify
mode: single

Using as_timestamp with these tile feature templates wouldn’t work since it uses ha-nunjucks for templating, which only supports a subset of Home Assistant templating functions (but renders instaneously in the front end). Adding pythonic time and timestamp functionality to ha-nunjucks is definitely an option, but I hadn’t gotten around to it since Python and JavaScript/TypeScript handle datetimes differently. There are a few npm packages that add pythonic datetimes to JS but I haven’t dug too much into them. Still the label and other templates only re-render if the hass object or an internal state changes, so I’d have to figure out how to make it re-render once per second anyway (which may end up not being that hard but I’m a backend engineer by trade so it could just be something I don’t know yet).

There’s also a visual bug with input ranges that makes it so that they stop visually updating if they are manually changed, which makes it harder to use for something like this which gets updated a lot by the backend this should hopefully be fixed in the next in progress minor version.

Also here’s a long label template to display the current and total media time.

label: >-
      {{ (VALUE / 60) | int }}:{{ 0 if (VALUE - 60*((VALUE / 60) | int)) < 10
      else "" }}{{ (VALUE - 60*((VALUE / 60) | int)) | int }}/{{
      (state_attr("media_player.spotify", "media_duration") / 60) |
      int }}:{{ 0 if (state_attr("media_player.spotify",
      "media_duration") - 60*((state_attr("media_player.spotify",
      "media_duration") / 60) | int)) < 10 else "" }}{{
      (state_attr("media_player.spotify", "media_duration") -
      60*((state_attr("media_player.spotify", "media_duration") /
      60) | int)) | int }}

Can this frequent rendering be an option to show also a timer countdown? Or is there already a possibility to show it as label somehow?
I tried to use a template for that, but it doesn’t work, I assume, because of the same reasons as above.

As it is now the reactive update cycle doesn’t trigger unless a property or state of the custom element changes, namely the state of any entity in Home Assistant. We we could do is create an input number entity to track media position more granularly and use an automation to update it once a second. I’ve updated my Spotify automation here to do so without increasing the polling rate to Spotify:

alias: Spotify Refresh Every 5 Seconds While Playing
description: ""
trigger:
  - platform: state
    entity_id:
      - media_player.spotify
    from: idle
condition: []
action:
  - repeat:
      while:
        - condition: or
          conditions:
            - condition: state
              entity_id: media_player.spotify
              state: playing
            - condition: state
              entity_id: media_player.spotify
              state: paused
      sequence:
        - service: homeassistant.update_entity
          data: {}
          target:
            entity_id: media_player.spotify
        - service: input_number.set_value
          target:
            entity_id: input_number.spotify_media_position
          data:
            value: >-
              {{ state_attr("media_player.spotify",
              "media_position") | int }}
        - repeat:
            count: 5
            sequence:
              - delay:
                  hours: 0
                  minutes: 0
                  seconds: 1
                  milliseconds: 0
              - if:
                  - condition: state
                    entity_id: media_player.spotify
                    state: playing
                  - condition: template
                    value_template: >-
                      {{ states("input_number.spotify_media_position") | int
                      < state_attr("media_player.spotify",
                      "media_duration") | int }}
                then:
                  - service: input_number.increment
                    target:
                      entity_id:
                        - input_number.spotify_media_position
                    data: {}
mode: single

This makes the slider update once a second. I also changed it’s entity ID to be for input_number.spotify_media_position while still calling the media_player.media_seek service like so:

  - type: slider
    tap_action:
      action: call-service
      service: media_player.media_seek
      data:
        seek_position: VALUE
        entity_id: media_player.spotify_nerwyn_singh
    entity_id: input_number.spotify_media_position
    range:
      - 0
      - '{{ state_attr("media_player.spotify_nerwyn_singh", "media_duration") }}'
    thumb: line
    label: >-
      {{ (VALUE / 60) | int }}:{{ 0 if (VALUE - 60*((VALUE / 60) | int)) < 10
      else "" }}{{ (VALUE - 60*((VALUE / 60) | int)) | int }}/{{
      (state_attr("media_player.spotify_nerwyn_singh", "media_duration") / 60) |
      int }}:{{ 0 if (state_attr("media_player.spotify_nerwyn_singh",
      "media_duration") - 60*((state_attr("media_player.spotify_nerwyn_singh",
      "media_duration") / 60) | int)) < 10 else "" }}{{
      (state_attr("media_player.spotify_nerwyn_singh", "media_duration") -
      60*((state_attr("media_player.spotify_nerwyn_singh", "media_duration") /
      60) | int)) | int }}
    style:
      '--color': rgb(31, 223, 100)
    background_style:
      height: 39%
      border-radius: 32px

There is a little jumpiness when pausing and when moving the slider position, but it bounces back to the correct position once the up to date media position is fetched from Spotify.

Edit: This method leaves the last used value on the slider label with the thumb visible. I need to figure out something else.

Version 3.3.0 adds spinboxes a la the climate target temperature feature! This feature allows you to increment and decrement a value, and only calls the service once you’ve stopped changing the value. You can modify both it’s center icon and label, and the icons and labels of it’s buttons. You can also override it’s buttons to behave like normal buttons.

This release also adds customizable timings for double tap and hold actions, repeat on hold actions with customizable repeat delay, momentary button mode, and a new fire-dom-event action.

This release marks the first code contributions of another developer! irakhlin contributed to the research of spinbox behavior and the actual implementation of the fire-dom-event action.

1 Like