A different take on designing a Lovelace UI

Ok, so i resized my background to fit the 4:3 ratio, and it works.

But what about the sidebar? do i have to play with the top property ? don’t get how it works

EDIT: ok by playing with the width property, i managed to make it fit. thxs!

1 Like

A while ago I read some posts here of people experiencing slower/slugging dashboards. I mentioned that my tablet was completely useless overnight. My tablet would freeze when trying to even load the dashboard (only fix was force closing Fully Kiosk Browser). Though I don’t use UI, I do have a similar design of my own and use card-mod alot. I had a suspicion it was card-mod, since that is also heavy used in this dashboard.

I haven’t seen other reports in the card-mod thread, so decided to test myself: 🔹 Card-mod - Add css styles to any lovelace card

I now downgraded to 2.0.3 and notice it works a LOT faster on all my devices. And my tablet works as before as well, successfully loading the dasbhoard again. I wanted to post this here as well, perhaps there are other people noticing this and are willing to test this as well. This could help in creating a ticket if more people experience this.

If you decide to test this, make sure you clear caches and the browser is loading 2.0.3 through developer tools.

2 Likes

@crozo5

Hi, could you share your svg icon for the ambilight please ?

Is anyone could share a windows animated svg icon please.

I’ve tried but not able to make one.

Here is my custom field code:

  icon_tv: |
    [[[
      const boolean = states['light.ambilight'].state;
      const style = `
      <style>
        .fade-in1 {
        animation: fadeIn1 ease 3s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeIn1 {
        0% {opacity:0;}
        97% {opacity:1;}
        98% {opacity:0.9;}
        99% {opacity:0.8;}
        100% {opacity:0.7;}
        }
        .fade-in2 {
        animation: fadeIn2 ease 3s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeIn2 {
        0% {opacity:0;}
        98% {opacity:0.7;}
        99% {opacity:0.6;}
        100% {opacity:0.5;}
        }
        .fade-in3 {
        animation: fadeIn3 ease 3s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeIn3 {
        0% {opacity:0;}
        100% {opacity:0.3;}
        }
        .fade-out1 {
        animation: fadeOut1 ease 2s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeOut1 {
        0% {opacity:1;}
        100% {opacity:0;}
        }
        .fade-out2 {
        animation: fadeOut2 ease 2s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeOut2 {
        0% {opacity:0.6;}
        100% {opacity:0;}
        }
        .fade-out3 {
        animation: fadeOut3 ease 2s;
        animation-fill-mode: forwards;
        }
        @keyframes fadeOut3 {
        0% {opacity:0.3;}
        100% {opacity:0;}
        }
        @keyframes animate_on {
        from {
            transform: scaleY(0);
        }
        to {
            transform: scaleY(1);
        }
        }
        .animate_on {
        animation: animate_on 1s;
        transform-origin: -100% 46%;
        animation-fill-mode: forwards;
        }
        @keyframes animate_off {
        from {
            transform: scaleY(1);
        }
        to {
            transform: scaleY(0);
        }
        }
        .animate_off {
        animation: animate_off 1s;
        transform-origin: -100% 46%;
        animation-fill-mode: forwards;
        }
        </style>
        `;
      const path = `
      <path d="M56,17.1v27.5H14.1V17.1H56 M58.4,14.8H11.6V47h46.7C58.4,47,58.4,14.8,58.4,14.8z M21.9,51.2h26.3c0.6,0,1.1-0.4,1.1-1v-0.3c0-0.6-0.4-1.1-1-1.1H21.9c-0.6,0-1.1,0.4-1.1,1V50c0,0.3,0.1,0.6,0.3,0.8C21.3,51,21.6,51.1,21.9,51.2z"/>
      `;
      const gradient = `
      <linearGradient id="A" gradientUnits="userSpaceOnUse" x1="20.401" y1="43" x2="30.817" y2="27.74">
      <stop offset="0" stop-color="#64acb7"/>
      <stop offset="1" stop-color="#7fdbe9"/>
      </linearGradient>
      <linearGradient id="B" gradientUnits="userSpaceOnUse" x1="10" y1="110" x2="100" y2="40" >
      <stop stop-color="#FF5B99" offset="0%"/>
      <stop stop-color="#FF5447" offset="20%"/>
      <stop stop-color="#FF7B21" offset="40%"/>
      <stop stop-color="#EAFC37" offset="60%"/>
      <stop stop-color="#4FCB6B" offset="80%"/>
      <stop stop-color="#51F7FE" offset="100%"/>
      </linearGradient>
      `;
      if (entity.state === 'off') {
      return `
        <svg viewBox="0 0 70 70"> ${style} ${gradient} 
        <path class="fade-out1" d="M 11.6 13.5 L 58.4 13.5 L 58.4 14.8 L 11.6 14.8 ZM 10.6 13.5 L 11.9 13.5 L 11.9 47 L 10.6 47 Z M 58.4 13.5 L 59.7 13.5 L 59.7 47 L 58.4 47 Z" fill="url(#B)"/>
        <path class="fade-out2" d="M 9.3 13.5 L 10.6 13.5 L 10.6 47 L 9.3 47 Z M 9.3 12.2 L 61 12.2 L 61 13.5 L 9.3 13.5 Z M 59.7 13.5 L 61 13.5 L 61 47 L 59.7 47 Z " fill="url(#B)"/>
        <path class="fade-out3" d="M 9.3 10.9 L 61 10.9 L 61 12.2 L 9.3 12.2 Z M 61 10.9 L 62.3 10.9 L 62.3 47 L 61 47 Z M 8 10.9 L 9.3 10.9 L 9.3 47 L 8 47 Z" fill="url(#B)"/>
        <path class="animate_off" d="M14.1,17.1H56v27.5H14.1V17.1z" fill="url(#A)"/> ${path} 
      `;
      }
      if (entity.state === 'on' && boolean === 'on') {
      return `
        <svg viewBox="0 0 70 70"> ${style} ${gradient} 
        <path d="M14.1,17.1H56v27.5H14.1V17.1z" fill="#20262890"/>
        <path d="M 7.9 47 L 11.5 47 L 11.6 11.4 L 8 11.4 Z M 11.6 11.4 L 58.4 11.4 L 58.4 14.8 L 11.6 14.8 Z M 58.4 11.4 L 62 11.4 L 62 47 L 58.4 47 Z" fill="#ffff"/>
        <path class="animate_on" d="M14.1,17.1H56v27.5H14.1V17.1z" fill="url(#A)"/> ${path} 
        <path class="fade-in1" d="M 11.6 13.5 L 58.4 13.5 L 58.4 14.8 L 11.6 14.8 ZM 10.6 13.5 L 11.9 13.5 L 11.9 47 L 10.6 47 Z M 58.4 13.5 L 59.7 13.5 L 59.7 47 L 58.4 47 Z" fill="url(#B)"/>
        <path class="fade-in2" d="M 9.3 13.5 L 10.6 13.5 L 10.6 47 L 9.3 47 Z M 9.3 12.2 L 61 12.2 L 61 13.5 L 9.3 13.5 Z M 59.7 13.5 L 61 13.5 L 61 47 L 59.7 47 Z " fill="url(#B)"/>
        <path class="fade-in3" d="M 9.3 10.9 L 61 10.9 L 61 12.2 L 9.3 12.2 Z M 61 10.9 L 62.3 10.9 L 62.3 47 L 61 47 Z M 8 10.9 L 9.3 10.9 L 9.3 47 L 8 47 Z" fill="url(#B)"/>
      `;
      }
      if (entity.state === 'on' && boolean === 'off') {
      return `
        <svg viewBox="0 0 70 70"> ${style} ${gradient} 
        <path d="M14.1,17.1H56v27.5H14.1V17.1z" fill="#20262890"/>
        <path d="M 7.9 47 L 11.5 47 L 11.6 11.4 L 8 11.4 Z M 11.6 11.4 L 58.4 11.4 L 58.4 14.8 L 11.6 14.8 Z M 58.4 11.4 L 62 11.4 L 62 47 L 58.4 47 Z" fill="#ffff"/>
        <path d="M14.1,17.1H56v27.5H14.1V17.1z" fill="url(#A)"/> ${path} 
        <path class="fade-out1" d="M 11.6 13.5 L 58.4 13.5 L 58.4 14.8 L 11.6 14.8 ZM 10.6 13.5 L 11.9 13.5 L 11.9 47 L 10.6 47 Z M 58.4 13.5 L 59.7 13.5 L 59.7 47 L 58.4 47 Z" fill="url(#B)"/>
        <path class="fade-out2" d="M 9.3 13.5 L 10.6 13.5 L 10.6 47 L 9.3 47 Z M 9.3 12.2 L 61 12.2 L 61 13.5 L 9.3 13.5 Z M 59.7 13.5 L 61 13.5 L 61 47 L 59.7 47 Z " fill="url(#B)"/>
        <path class="fade-out3" d="M 9.3 10.9 L 61 10.9 L 61 12.2 L 9.3 12.2 Z M 61 10.9 L 62.3 10.9 L 62.3 47 L 61 47 Z M 8 10.9 L 9.3 10.9 L 9.3 47 L 8 47 Z" fill="url(#B)"/>
        </svg>
      `;
      }
      if (entity.state === 'off' && boolean === 'on') {
      return `
        <svg viewBox="0 0 70 70"> ${style} ${gradient} 
        <path d="M14.1,17.1H56v27.5H14.1V17.1z" fill="#20262890"/>
        <path d="M 7.9 47 L 11.5 47 L 11.6 11.4 L 8 11.4 Z M 11.6 11.4 L 58.4 11.4 L 58.4 14.8 L 11.6 14.8 Z M 58.4 11.4 L 62 11.4 L 62 47 L 58.4 47 Z" fill="#ffff"/>
        <path d="M14.1,17.1H56v27.5H14.1V17.1z" fill="url(#A)"/> ${path} 
        <path class="fade-in1" d="M 11.6 13.5 L 58.4 13.5 L 58.4 14.8 L 11.6 14.8 ZM 10.6 13.5 L 11.9 13.5 L 11.9 47 L 10.6 47 Z M 58.4 13.5 L 59.7 13.5 L 59.7 47 L 58.4 47 Z" fill="url(#B)"/>
        <path class="fade-in2" d="M 9.3 13.5 L 10.6 13.5 L 10.6 47 L 9.3 47 Z M 9.3 12.2 L 61 12.2 L 61 13.5 L 9.3 13.5 Z M 59.7 13.5 L 61 13.5 L 61 47 L 59.7 47 Z " fill="url(#B)"/>
        <path class="fade-in3" d="M 9.3 10.9 L 61 10.9 L 61 12.2 L 9.3 12.2 Z M 61 10.9 L 62.3 10.9 L 62.3 47 L 61 47 Z M 8 10.9 L 9.3 10.9 L 9.3 47 L 8 47 Z" fill="url(#B)"/>
      `;
      }
    ]]]
1 Like

Thxs a lot.

I use this in my sidebar to show weekly incidence of my region.

<b>Inzidenzen</b><br>
              <b>Bayern: <font color='#e89210'>{{ states('sensor.inzidenz_bayern')| round(0) }}</b></font><br>
              <b>Memmingen: <font color='#e89210'>{{ states('sensor.inzidenz_memmingen')| round(0) }}</b></font><br>
              <b>Unterallgäu: <font color='#e89210'>{{ states('sensor.inzidenz_unterallgau')| round(0) }}</b></font><br>

I want the numbers to be colored according to value.
Below 35 green
Between 35-50 orange
Over 100 red.

I dont have a clue how to realize this. Can anybody give me a hint?

From where you get this sensor?
sensor.inzidenz_bayern

First I was using this integration: https://github.com/thebino/rki_covid
But he has problems with the data source. So for the moment I changed to a rest sensor.

platform: rest
name: Inzidenz Bayern
resource: "https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/Coronaf%C3%A4lle_in_den_Bundesl%C3%A4ndern/FeatureServer/0/query?where=LAN_ew_GEN%20%3D%20%27BAYERN%27&outFields=LAN_ew_AGS,LAN_ew_GEN,cases7_bl_per_100k&outSR=4326&f=json"
value_template: '{{ value_json.features[0].attributes.cases7_bl_per_100k | round(1) }}'
scan_interval: 3600
2 Likes

Hi @Mattias_Persson, where does those vacuum sensors come from please? i checked evrywhere but not able to find it :

  • sensor.main_filter
  • sensor.main_brush
  • sensor.sensor
  • sensor.right_side_brush
 ####################################################
    #                                                  #
    #                      VACUUM                      #
    #                                                  #
    ####################################################

      roborock_filter:
        friendly_name: Filtre
        icon_template: custom:roborock-filter
        unit_of_measurement: '%'
        value_template: >
          {{ ((states('sensor.main_filter') | int / 60) / 150 * 100) | round }}

      roborock_mainbrush:
        friendly_name: Brosse Principale
        icon_template: custom:roborock-mainbrush
        unit_of_measurement: '%'
        value_template: >
          {{ ((states('sensor.main_brush') | int / 60) / 300 * 100) | round }}

      roborock_sensors:
        friendly_name: Capteurs
        icon_template: custom:roborock-sensor
        unit_of_measurement: '%'
        value_template: >
          {{ ((states('sensor.sensor') | int / 60) / 30 * 100) | round }}

      roborock_sidebrush:
        friendly_name: Brosses latérales
        icon_template: custom:roborock-sidebrush
        unit_of_measurement: '%'
        value_template: >
          {{ ((states('sensor.right_side_brush') | int / 60) / 200 * 100) | round }}

Thxs

1 Like

Just curiosity , cause i found a way to make mine :

{{((state_attr('vacuum.roborock_vacuum', 'main_brush_left') | int *100 )/300) | round }}

I REALLY want this look. But I have copied and pasted everything and there are errors everywhere. What is it that I have to do more myself? What parts? Here is how it looks for me:

Also, I have had to flush and re-install my whole HA several times after trying to restart the server when I tried to just add the first lines in the configuration file.

Is there any way I can prevent that from happening that everything doesn’t crash and I have to re-install everything after trying to restart?

You have to solve one error after the other.
The first that I see, is that you didnt installed “swipe-card”.

And please, before doing anything other, check that every entity that is used, is a existing entity. If you refer to only one entity that doesnt exist, it could throw an error.
Go trough the whole configuration (ui-lovelace.yaml, button-templates, etc…) and check every single entity. Replace all the entities which don’t exist with similar entities from your setup.

1 Like

It’s not a “plug and play” design. You must adjust evrything manually to make it works, with an understanding of how it works

I thought maybe there would be some instructions in readme about that. But allright. And when it comes to swipe-card and so on I thought that came with the package. But okay. Good that I have something to do coming weekend then.

The swipe-card is included. But did you included the resource correctly?

The best thing is as @Djal mentioned, take your time, understand how it works and then start.
I needed two days to fully understand how it works and get it running. And a few more weeks to customize it for my dashboard.

1 Like

exactly. long story short, it consists in a picture-element wich takes the whole screen with all inside (essentially button-card but not only). take your time and you will manage to do it.

This setup (as the use case suggests in the original post of course) is meant for running it in Kiosk mode in larger screens such as tablets/monitors/TVs.

In regard with mobile use what is your take on the matter? Do you not use it or you have gone with some other solution?

For mobile I just use HomeKit

Why is the path to the background image “local” in the file while it’s “www” for real? Something I’ve missed here

I don’t mean to discourage you, but with little home assistant knowledge, trying to setup this “setup” may leave you frustrated and hating home assistant.
I would suggest starting with basics.

Sorry if this feels like no help, but I’ve seen this multiple times here in the forums.
Replicating this is jumping straight to “hard mode”.