A different take on designing a Lovelace UI

Hey @Mattias_Persson I’m having issues trying to get the primary Media button to display my Plex playing any media. At the moment if I have my Plex playing a video, the primary Media button only displays the recently added thumbnail and the swipe page shows the Plex button is playing/paused. This is what my code currently has:
Template.yaml

    ####################################################
    #                                                  #
    #                      SELECT                      #
    #                                                  #
    ####################################################

  - select:
      - name: conditional_media
        state: >
          {% set recently_added = 'Recently Added' %}
          {% set paused_timeout_minutes = 15 %}
          {% set media_players = [
            states.media_player.plex_plex_for_lg_lg_oled55b6p_u,
            states.media_player.sovrum,
            states.media_player.spotify,
            states.media_player.kok ] %}

          {% macro media(state) %}
          {% set state = media_players | selectattr('state','eq',state) | list %}
          {% set last_changed = recently_added if state | length == 0 else state | map(attribute='last_changed') | list | max %}
            {{ state | selectattr('last_changed','eq', last_changed) | map(attribute='name') | list | join }}
          {% endmacro %}

          {% set playing = media_players | selectattr('state','eq','playing') | list %}
          {% set timeout_playing = False if playing | length == 0 else
            (as_timestamp(now()) - as_timestamp(playing | map(attribute='last_changed') | list | max)) < paused_timeout_minutes * 60 %}

          {% set paused = media_players | selectattr('state','eq','paused') | list %}
          {% set timeout_paused = False if paused | length == 0 else
            (as_timestamp(now()) - as_timestamp(paused | map(attribute='last_changed') | list | max)) < paused_timeout_minutes * 60 %}

          {% if playing %}
            {{ media('playing') if timeout_playing else media('paused') if timeout_paused else media('playing') }}
          {% elif paused %}
            {{ media('paused') if timeout_paused else recently_added }}
          {% else %}
            {{ recently_added }}
          {% endif %}
        options: >
          {% set recently_added = ['Recently Added'] %}
          {% set media_players = [
            states.media_player.plex_plex_for_lg_lg_oled55b6p_u,
            states.media_player.sovrum,
            states.media_player.spotify,
            states.media_player.kok ] %}
          {{ recently_added + media_players | map(attribute='name') | list }}
        select_option:
          service: select.select_option
          target:
            entity_id: select.conditional_media
          data:
            option: >
              {{ option }}

      - name: vacuum_speed
        state: >
          {% set fan_speed = state_attr('vacuum.morty', 'fan_speed') %}
          {{ iif(fan_speed == None, 'Standard', fan_speed) }}
        options: >
          {% set fan_speed_list = state_attr('vacuum.morty', 'fan_speed_list') %}
          {{ iif(fan_speed_list == None, ['Standard'], fan_speed_list) }}
        select_option:
          service: vacuum.set_fan_speed
          target:
            entity_id: vacuum.morty
          data:
            fan_speed: >
              {{ option }}

      - name: hdmi_lg
        state: >
          {% set source = state_attr('media_player.lg_webos_smart_tv', 'source') %}
          {{ iif(source == None, 'HDMI', source) }}
        options: >
          {% set source_list = state_attr('media_player.lg_webos_smart_tv', 'source_list') %}
          {{ iif(source_list == None, ['HDMI'], source_list) }}
        select_option:
          service: media_player.select_source
          target:
            entity_id: media_player.lg_webos_smart_tv
          data:
            source: >
              {{ option }}

ui-lovelace.yaml

      #################################################
      #                                               #
      #                     MEDIA                     #
      #                                               #
      #################################################

      - type: grid
        title: Media
        view_layout:
          grid-area: media
        columns: 1
        cards:

          - type: custom:swipe-card
            parameters:
              speed: 550
              spaceBetween: 40
              threshold: 5
            cards:

              - type: horizontal-stack
                cards:

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state_not: LivingRoom

                      - entity: select.conditional_media
                        state_not: Bedroom

                      - entity: select.conditional_media
                        state_not: Spotify

                      - entity: select.conditional_media
                        state_not: Kök
                    card:
                      type: custom:button-card
                      entity: sensor.plex_recently_added
                      name: Recently Added
                      tap_action:
                        action: none
                      template:
                        - conditional_media
                        - icon_plex

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: LivingRoom
                    card:
                      type: custom:button-card
                      entity: media_player.plex_plex_for_lg_lg_oled55b6p_u
                      template:
                        - conditional_media
                        - icon_plex

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: Bedroom
                    card:
                      type: custom:button-card
                      entity: media_player.sovrum
                      template:
                        - conditional_media
                        - icon_apple_tv

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: Spotify
                    card:
                      type: custom:button-card
                      entity: media_player.spotify
                      template:
                        - conditional_media
                        - icon_spotify

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: Kök
                    card:
                      type: custom:button-card
                      entity: media_player.kok
                      template:
                        - conditional_media
                        - icon_nest_mini

              - type: grid
                columns: 2
                cards:

                  - type: custom:button-card
                    entity: media_player.plex_plex_for_lg_lg_oled55b6p_u
                    name: Living Room
                    template:
                      - media
                      - icon_plex

                  - type: custom:button-card
                    entity: media_player.sovrum
                    name: Bedroom
                    template:
                      - media
                      - icon_apple_tv

                  - type: custom:button-card
                    entity: media_player.spotify
                    name: Spotify
                    template:
                      - media
                      - icon_spotify

                  - type: custom:button-card
                    entity: media_player.kok
                    name: Nest Mini
                    template:
                      - media
                      - icon_nest_mini

Thanks.

@Mattias_Persson I use your button card templates and mostly all of your card code in a normal Lovelace view. But here I have problem with the tilt.js on safari.

I did some research on this and found a solution that I need to apply “-webkit-transform: translateZ(0);” to the parent element of the cards. This works when I put it in with developer tools. I would like to have this done in the card templates. is this possible or is there another way to fix tilt in safari in normal Lovelace view?

@Br3b hi, your weather button looks amazing… would you share the code with me? thx in advance

jm

Hello. Is it possible to make an automation that checks when you make a modification in your repository?

Hi all,
i try to make a card which deplays the state of an input_boolean and the state of an zone in the top right circle. Like in the person template i would love to see the circle, no matter if the input_booolean is on or not.
But on problem occur:
The circle is not displayed and the value not in the right position.
Moreover: Is it possible that the circle is half fuilled if one person is home, full fuilled if two person are home ?

Here is my code:

          - type: custom:button-card
            entity: input_boolean.home_empty
            name: Unterwegs
            hold_action:
              action: none
            template:
              - base
              - icon_away
              - circle
            styles:
              custom_fields:
                icon:
                  - clip-path: circle()
                  - width: 77%
                  - pointer-events: none
                  - display: grid
            custom_fields:
              circle: >
                [[[
                  if (entity) {
                    let entity_zone = states['zone.home'];
                    return entity_zone === undefined || entity_zone.state;
                    stroke = entity_zone.state === '2'
                      ? '#b2b2b2'
                      : 'none',
                    fill = entity_zone.state !== '2'
                      ? 'rgba(255,255,255,0.04)'
                      : 'none';
                    return `
                      <svg viewBox="0 0 50 50">
                        <circle cx="25" cy="25" r="20.5" stroke="${stroke}" stroke-width="1.5" fill="${fill}" />
                        <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle">${entity_zone}</text>
                      </svg>
                    `;
                  }
                ]]]

Thanks all and what a wonderful interface!

hi @gekberlin and welcome,

so, after i stole the idea and added it to my dashboard :wink:
this is what i got.

edit: updated to use the number of people home not the percentage of people home.

Recording 2022-06-12 at 22.11.35

in your case use 2 not 3 in circle_input, but that should do it.

- type: custom:button-card
  entity: input_select.state_home
  name: Home
  variables:
    circle_input:  >
      [[[
        return entity === undefined || Math.round(states['zone.home'].state / 3 * 100 ) ;
      ]]]
  hold_action:
    action: more-info
  tap_action:
    action: call-service
    service: input_select.select_next
    service_data:
      entity_id: input_select.state_home
  double_tap_action:
    action: call-service
    service: input_select.select_previous
    service_data:
      entity_id: input_select.state_home
  custom_fields:
    circle: >
      [[[
          let input = variables.circle_input,
            radius = 20.5,
            circumference = radius * 2 * Math.PI;
          let inner_text = states['zone.home'].state
          return `
            <svg viewBox="0 0 50 50">
              <style>
                circle {
                  transform: rotate(-90deg);
                  transform-origin: 50% 50%;
                  stroke-dasharray: ${circumference};
                  stroke-dashoffset: ${circumference - input / 100 * circumference};
                }
                tspan {
                  font-size: 10px;
                }
              </style>
              <circle cx="25" cy="25" r="${radius}" stroke="#b2b2b2" stroke-width="1.5" fill="none" />
              <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle">${inner_text}</text>
            </svg>
          `;
      ]]]
  template:
    - base
    - icon_home
    - circle
1 Like

@Quinnod34 thanks for the icons loveing the work, they look much better that what i had. I am using the downlight, garage, and washer icons. id love a soundbar icon if you get bord again, im useing the monitors icon at the moment, but it looks odd with the name.

image

this is what i had for the garage and its about as creative as i get. icons are from mui icon set

  icon_garage:
    custom_fields:
      icon: >
        [[[
          if (variables.state === 'on') {
            return `
              <svg viewBox="0 0 50 50">
                <path d="M37.4 15.3V34H34V18.7H6.8V34H3.4V15.3L20.4 8.5 37.4 15.3M32.3 20.4H8.5V23.8H32.3V20.4Z" fill="#9da0a2" />
              </svg>
            `;
          } 
            return `
              <svg viewBox="0 0 50 50">
                <path d="M37.4 15.3V34H34V18.7H6.8V34H3.4V15.3L20.4 8.5 37.4 15.3M32.3 20.4H8.5V23.8H32.3V20.4M32.3 30.6H8.5V34H32.3V30.6M32.3 25.5H8.5V28.9H32.3V25.5Z" fill="#9da0a2" />
              </svg>
            `;
        ]]]

How to change update 2 available to 5?

Works like a charm. Perfect, thank you for your help. I made a few changes so that the state of the card is defined by a different entity then the input_select entity.

image

I just noticed your card tilt has depth (with the icon and circle style in the foreground)

Mine lacks this, have I somehow implemented the code wrong, or have you got some unpublished updates for it?

1 Like

happy to help
the state of the card is for my settup, i can toggle between home, away, guest, and party, and that state is used to limmit automations, i have a system state aswell thats auto, passive and off that limit the running of automaitons aswell, this is set in the config popup that i added to the footer.

hi @arifroni

the square shape is from the grid card, try this

      - type: grid
        square: false
        title: Weather
        view_layout:
          grid-area: weather
        columns: 1
        cards:
          - type: custom:weather-chart-card
            entity: weather.tomorrow_io_daily
1 Like

How to get sensors?

hass_version_latest
hass_version_latest_beta

I think you can just use the “Version”-Integration. You can configure it from the UI.

I tried using a Fire HD 10 Plus for my dashboard but the popups are really slow. It sometimes takes 3-5 seconds loading them. Everything else - even the swiper elements - seems to be quite responsive and there is almost no delay. Is there something I can do to make the popups come up more smooth? Or do I have to switch to a better tablet to get rid of this?

has perhaps someone a animated icon for a pool or pool pump?

1 Like

i have the same tablet (2021), and yes sometimes it takes 2 seconds in my setup, but not 5 seconds.

hay do you have an update on the weather card? i started using it but some of the backgrounds are not used in the code you shared above

you should have a sidebar template sensor, under attributes, you can add a new attribute and it will show up in the sidebar.

i did go one step further, i have a few dashboards of the above style so i split all the attributes out into there own template sensors. so i can reuse them as needed
so my sidebar llooks like this

unique_id: sidebar
state: template
attributes:
  time: "{{ states('sensor.template_sidebar_time') }}"
  date: "{{ states('sensor.template_sidebar_date') }}"
  greet: "{{ states('sensor.template_sidebar_greet') }}"
  temperature:  "{{ states('sensor.template_sidebar_temperature') }}"
  rain:  "{{ states('sensor.template_sidebar_rain') }}"
  mason_timeline:  "{{ states('sensor.template_sidebar_mason_timeline') }}"
  washer:  "{{ states('sensor.template_sidebar_washer') }}"
  dryer:  "{{ states('sensor.template_sidebar_dryer') }}"
  bins:  "{{ states('sensor.template_sidebar_bins') }}"
  litter_box:  "{{ states('sensor.template_sidebar_litter_box') }}"
  cats_fed:  "{{ states('sensor.template_sidebar_cats_fed') }}"
  nas:  "{{ states('sensor.template_sidebar_nas') }}"

and template_sidebar_cats_fed looks like this

unique_id: sidebar_cats_fed
state: >
    {% if states.input_datetime.fed_cats_last_updated is defined %}
      {% set fed_cats_time = as_datetime(states('input_datetime.fed_cats_last_updated')).astimezone() %}
      {% set fed_cats_ago_time =  (now()- fed_cats_time ) %}
      {% set fed_cats_ago_day =  (now().day - fed_cats_time.day ) %}
      {% set fed_cats_ago_minutes =  (fed_cats_ago_time.seconds / 60 )| int %}

      {% if fed_cats_ago_time.days > 0 %}
        The cats were fed on <span class='error'>{{fed_cats_time.strftime("%A at %-I:%M %p") }}<span/>
      {% elif fed_cats_ago_minutes < 1 %}
        The cats just got fed
      {% elif fed_cats_ago_minutes < 60 %} 
        The cats got fed {{fed_cats_ago_minutes}} minutes ago
      {% elif fed_cats_ago_minutes < 120 %}
        The cats got fed 1 hour and {{fed_cats_ago_minutes - 60}} minutes ago
      {% elif fed_cats_ago_minutes < 780  %}
        The cats got fed {{(fed_cats_ago_minutes / 60) | round}} hours ago
      {% else %}
        The cats got fed <span class='warning'>{{(fed_cats_ago_minutes / 60) | round}}<span/> hours ago
      {% endif %}
    {% endif %}   
3 Likes