A different take on designing a Lovelace UI

This has been bothering me, too.
Your question was just the push I needed to try and come up with a temporary solution - and I think I got something working.
I’d much prefer if the root cause got fixed, but let’s make this a learning experience.
It’s not the most elegant, but it does the job – hopefully.

Preview

Plex Recently Added Backup

image

Requirements

Helper (Helper entity, to store the info)

Example: input_text.backup_plex_recently_added

I created one via the GUI:
Navigate using command: Press the letter C → Type: Helpers → Press enter

image

Or, browse here: Settings → Devices & Services → Helpers → Create Helper → Text

image

OBS: Maximum length should be 255

Template sensor (To make it easier with JavaScript later)

This is unnecessary, but it makes sense to me that we have a sensor with attributes.
I tried creating an attribute with a dict similar to the ‘Recently Added’ sensor, but jinja and the formatting got weird on me, so I just did this for now:

This sensor is grabbing the state of the input_text helper, and cleans it up.

Like this

Template select

Updated the select template to handle the new sensor.

Automation (To take backup of 1 item in the ‘Recently Added’ sensor)

Not tested properly yet…

Triggers

platform: state
entity_id:
  - sensor.recently_added_mix
to: Online

Conditions

condition: template
value_template: >-
  {{ trigger.to_state.state not in [trigger.from_state.state, 'cannot be
  reached', 'unavailable', 'undefined','unknown','none','null'] }}

Actions

service: input_text.set_value
data:
  value: >-
    {% if not states('sensor.recently_added_mix') in
    ['unavailable','undefined','unknown','none','null','0'] %}
      {% set state = namespace(return='') %}
      {% set data = state_attr('sensor.recently_added_mix','data') %}
      {%- for value in data %}
        {%- if not loop.first and value is defined and state.return == '' %}
          {%- if not value.number is defined %}
            {% set state.return = 
              "aired:" + value.aired + "|" +
              "title:" + value.title  + "|" +
              "fanart:" + value.fanart + "|" +
              "poster:" + value.poster
            %}
          {%- else %}
            {% set state.return = 
              "aired:" + value.aired + "|" +
              "title:" + value.title  + "|" +
              "number:" + value.number  + "|" +
              "fanart:" + value.fanart + "|" +
              "poster:" + value.poster
            %}
          {%- endif %}
        {%- endif %}
      {%- endfor %}
      {{ state.return }}
    {% endif %}
target:
  entity_id: input_text.backup_plex_recently_added

lovelace.yaml – swipe-card update

button_card_templates.yaml – conditional_media update

(state_display and background-image)

Edit: Added a change in the text color.
This is optional, of course, but I wanted another indicator that something was wrong.

conditional_media:

        - color: >
            [[[
              if (entity.state === "Active") {
                return entity === undefined
                    ? '#97989c'
                    : 'rgba(239, 239, 239, 0.5)';
              }
              else {
                return entity === undefined
                    ? '#97989c'
                    : '#efefef';
              }
            ]]]

PS: I haven’t tested it fully yet, so try at your own risk :wink:

6 Likes

Where do put my enitiy for the temperature on the clima tab?
image

The original one is set up like this. If the entity state is ‘cool’, it’ll display entity.attributes.temperature if the state is anything other than cool, it’ll display entity.attributes.current_temperature. If your device doesn’t have those attributes, you’ll have to modify the circle_input for that button card.

Thank you for clarifying, However my air cleaner from Electrolux does not have attributes… Is it possible to add a entity instead?

yep, you should add the temp sensor entity to triggers_update: if you want the temp to update on the card without the button card entity updating. You’ll also want to modify circle_input to use the triggers_update entity. Here’s an example

- type: custom:button-card
  entity: climate.downstairs
  name: HVAC
  double_tap_action:
    !include popup/downstairs_climate.yaml
  triggers_update: sensor.fireplace_temp
  template:
    - base
    - icon_climate
    - circle
  variables:
    circle_input: "[[[ return Math.round(states[this._config?.triggers_update].state).toString(); ]]]"
    circle_input_unit: '°F'
4 Likes

Well… THANK YOU! <3
image

Hi Br3b, would you share the code from the weather widget? Mine looks like this…

Bildschirm­foto 2023-02-06 um 17.40.31

what do I have to adjust?

After spending lots of time a beautiful picture on the wall! Thanx a lot Mattias!!!

I read everything and learned a lot. But I’m not clear how the sidebar works.

The date has now disappeared, it was in the sidebar.yml, I placed it in a sidebar_time.yml, unfortunately that didn’t work either. It’s also not clear to me where to put what. Do you make a separate yml file for each item? Hopefully someone can help me with this. Can be done via DM or comment. Many thanks in advance!

Hi @weaverprojects,
the card template is not mine.
I just adjusted the “- margin-left: 10%” for all objects in the card. Hope it helps.

  widget_weather:
    variables:
      temp_min: ''
      temp_max: ''
      precip: ''
    aspect_ratio: 1/1
    show_icon: false
    show_entity_picture: true
    show_name: true
    show_state: true
    show_label: true
    tap_action:
      action: more-info
    styles:
      grid:
        - grid-template-areas: |
            "n"        
            "temp"
            "i"
            "s"
            "l"
        - grid-template-columns: 1fr
        - grid-template-rows: min-content repeat(2, 1fr) repeat(2, min-content)
        - gap: 0%
      card:
        - color: rgba(255, 255, 255, 0.8)
        - background: |
            [[[
              if (states['sun.sun'].state == 'below_horizon'){
                return 'linear-gradient(to top, rgba(53,59,83,1) 0%, rgba(10,14,34,1) 100%)';
              } else
                return 'linear-gradient(to top, rgba(123,168,197,1) 0%, rgba(61,132,176,1) 100%)';
            ]]]        
      state:
        - margin-left: 12%
      name:
        - place-self: start
        - margin-left: 10%
        - text-transform: uppercase
        - font-weight: 400
      img_cell:
        - margin-left: 10%
        - justify-content: start
      icon:
        - width: 25%
        - margin-left: 7%
      label:
        - margin-left: 7%
        - place-self: start
      custom_fields:
        temp:
          - place-self: start
          - margin-left: 10%
    custom_fields:
      temp: |
        [[[ return entity.attributes.temperature + "°"; ]]]    
    label: |
      [[[
          if (window.navigator.userAgent.match(/iPhone/i)) {
            return         `<ha-icon
            icon="mdi:arrow-up-thin"
            style="width: 15px; height: 15px; margin-right: -6px;">
            </ha-icon><span> ${states[variables.temp_max].state}°</span>
                  <ha-icon
            icon="mdi:arrow-down-thin"
            style="width: 15px; height: 15px; margin-right: -6px;">
            </ha-icon><span> ${states[variables.temp_min].state}° </span>       
          `;
                }
          else {
                    return `<ha-icon
            icon="mdi:arrow-up-thin"
            style="width: 15px; height: 15px; margin-right: -5px;">
            </ha-icon><span> ${states[variables.temp_max].state}°</span>
                  <ha-icon
            icon="mdi:arrow-down-thin"
            style="width: 15px; height: 15px; margin-right: -5px; margin-left: -5px;">
            </ha-icon><span> ${states[variables.temp_min].state}° </span>       
                  <ha-icon
            icon="mdi:weather-pouring"
            style="width: 14px; height: 14px; margin-right: -2px; margin-left: -1px;">
            </ha-icon><span> ${states[variables.precip].state}%</span>
          `}
      ]]]
    entity_picture: |
      [[[
        return entity && entity.state
          ? `/local/animated-weather-icons/${entity.state}.svg`
          : '?';
      ]]]
    extra_styles: |
      [[[
        return `
          #name {
            font-size: 1vw;
          }
          #temp {
            font-size: 1.9vw;
          }
          #state {
            font-size: 0.60vw;
          }  
          #label {
            font-size: 0.60vw;
          }
          /* portrait */
          @media screen and (max-width: 1200px) {
            #name {
              font-size: 1.3vw;
            }
            #temp {
              font-size: 4.5vw;
            }
            #state {
              font-size: 1.1vw;
            }  
            #label {
              font-size: 1.1vw;
            }
          }
          /* phone */
          @media screen and (max-width: 800px) {
            #name {
              font-size: 3vw;
            }              
            #temp {
              font-size: 2.5vw;
            }    
            #state {
              font-size: 1.8vw;
            }
            #label {
              font-size: 2.25vw;
            }
                   
          }
          @keyframes card_bounce {
            0% {
              transform: scale(1);
            }
            15% {
              transform: scale(0.9);
            }
            25% {
              transform: scale(1);
            }
            30% {
              transform: scale(0.98);
            }
            100% {
              transform: scale(1);
            }
          }
        `
      ]]]
1 Like

sidebar.yaml (at least the one in the base directory) is nothing more than a template sensor. The sections themselves like time, date, greet are attributes of that sensor. If you look in button_card_templates/sidebar.yaml you’ll see how they’re displayed.

If you did want to separate things out or display some other info in a different template sensor, you can put yaml files in the packages folder, but include template: as the first line.

template:
  - sensor:
    ...

You’ll then have to add any new sensor to the sidebar section of ui-lovelace.yaml for it to show up.

A quick example would be
packages/sun_rising.yaml

template:
  - sensor:
    - unique_id: Sun Rising
      state: template
      attributes:
        sun: >
          {% if is_state("sun.sun", "above_horizon") -%}
            The sun rose {{ relative_time(states.sun.sun.last_changed) }} ago.
          {%- else -%}
            The sun will rise at {{ as_timestamp(state_attr('sun.sun', 'next_rising'), '%Y-%m-%d %H:%M:%S') | timestamp_custom("%A @ %-I:%M %p") }}.
          {%- endif %}

ui-lovelace.yaml

...
      #################################################
      #                                               #
      #                    SIDEBAR                    #
      #                                               #
      #################################################

      - type: vertical-stack
        view_layout:
          grid-area: sidebar
        cards:

          - type: custom:button-card
            entity: sensor.template_sidebar
            template: sidebar

          - type: custom:button-card
            entity: sensor.sun_rising
            template: sidebar
...

An alternate option is creating new attributes in sidebar.yaml to display whatever you want. Those will automatically be added since the sidebar template loops through all available attributes of the sensor.

1 Like

Hey guys, any idea how i can change this gap:

THNX!! Did the trick!

hello,

i tried to replace the background of the theme, its the background.png under local or www or?

i tried to replace an reboot and deletet my browser cache but no luck

Just add a padding in the template

... card:
      - padding: 10.9% 9.9% 8.9% 10.9%;
 #Additional padding to the template (Based on the % found on the extra_styles.yaml)
1 Like

check what path you have assigned based on the themes.yaml file
Matts is like:

    card-mod-root: |
      ha-app-layout {
        background: url('/local/background.png');
        background-size: cover;
      }

The file would be in: www/background.png

Based on my own experiences the background was sometimes missing (full-on black) when a card would be broken (Erroring out). Not sure why is this thing; but that’s what I use as an early identifier of a broken card sometimes😂

Hi!

Sorry for the stupid question, but how can I add more icons like (wall sockets, motion sensors) the same way you did with icon_alexa?

Many thanks.

hey this looks amazing well done. Can I just ask how have you got all the time remaining and temp control etc integrated from your washer/dryer? Is it a smart dryer?

Yes, I have an LG washer and dryer and use the LG ThinQ Devices integration.

1 Like

Hello, how do you make the button light up, the radiator only lights up if the heating is on or off but not when it is really heating up.

And since you have managed to do the temperature circle, I don’t quite understand the other partner’s code.

Thank you so much.

      - type: custom:button-card
        entity: climate.termostato
        name: Calefacción
        double_tap_action:
          !include popup/sovrum_klimat.yaml
        triggers_update: sensor.termostato_temperature
        template:
          - base
          - icon_climate
          - circle
        variables:
          circle_input: "[[[ return Math.round(states[this._config?.triggers_update].state).toString(); ]]]"
          circle_input_unit: '°C'

Hello and welcome! Maybe I can help clarify a little bit.

The code you posted is just for using an alternate sensor source to display a temperature in the circle. It won’t show the temperature difference using the circle as a scale. It will show up like this, with the outline always a full circle.

Getting the circle to show the temperature difference or a countdown is more involved. This is my original post about how to accomplish that, but I’m using it as a countdown to when my laundry is done.

And finally, if you want the button to stay “on” or lit up, you might need an alternate state_on variable in your button code.
The original code will only show a button as active or “on” if the entity state matches one of these states: 'on', 'home', 'cool', 'fan_only', 'playing', 'unlocked'. You can change that by defining an alternate state_on variable in specific buttons.

for instance, I do that with my washing machine by adding this

  variables:
    state_on: >
      [[[ return ['Detecting', 'Washing', 'Rinsing', 'Spinning'].indexOf(!entity || entity.state) !== -1; ]]]

You’ll have to look and see what the entity state is when it’s running vs when it’s off to figure out what states you should add.

1 Like