A different take on designing a Lovelace UI

I don’t know if you solved it already, but I solved the problem by adding the theme again. This caused problems due to the changes in extra_styles.yaml.

@venealis
I’ve run it on a Windows server for a while, but just recently migrated it back to a Synology NAS.
The Windows server used HASS.Agent. And now I’m just using the Synology integration.

Here’s the current popup (plex.yaml called with tap_action)

action: fire-dom-event
browser_mod:
  command: popup
  title: Plex
  style:
    .: |
      :host .main-title {
        pointer-events: none;
      }
    hui-vertical-stack-card:
      $hui-conditional-card>hui-vertical-stack-card$: |
        hui-horizontal-stack-card {
          padding: 0em 2em 1.5em 2em;
        }
      $hui-conditional-card>hui-vertical-stack-card$hui-horizontal-stack-card$: |
        #root {
          justify-content: space-evenly;
        }
        
  card:
    type: vertical-stack
    cards:

      ### ON ###
      - type: conditional
        conditions:
          - entity: binary_sensor.ping_rackstation
            state: 'on'
        card:
          type: vertical-stack
          cards:
            - type: entities
              state_color: true
              card_mod:
                class: content
              entities:

                - entity: switch.wol_plex
                  name: Power state
                  secondary_info: last-changed
                  icon: mdi:power

                - type: custom:bar-card
                  width: 55%
                  height: 2em
                  decimal: 0
                  unit_of_measurement: '%'
                  positions: &pos
                    icon: outside
                    indicator: 'off'
                    name: outside
                  severity: &sev
                    - color: '#303435'
                      from: 0
                      to: 89
                    - color: '#6d2525'
                      from: 90
                      to: 100
                  entity_row: true
                  entities:

                    - entity: sensor.rackstation_cpu_utilization_total
                      name: CPU load
                      tap_action:
                        action: call-service
                        service: homeassistant.update_entity
                        service_data:
                          entity_id: sensor.rackstation_cpu_utilization_total

                    - entity: sensor.rackstation_memory_usage_real
                      name: RAM usage
                      tap_action:
                        action: call-service
                        service: homeassistant.update_entity
                        service_data:
                          entity_id: sensor.rackstation_memory_usage_real


                - entity: sensor.plex_issues
                  name: Health

                - entity: sensor.plex_sagaflix
                  name: Activity
                  icon: mdi:progress-upload

                - entity: sensor.rackstation_last_boot
                  name: Last boot

                - entity: sensor.sagaflix_library_movies
                  name: Movies

                - entity: sensor.sagaflix_library_tv_shows
                  name: TV Shows


            - type: horizontal-stack
              cards:
              - type: custom:button-card
                name: Sleep
                icon: mdi:power-sleep
                tap_action:
                  action: call-service
                  service: switch.toggle
                  service_data:
                    entity_id: switch.hass_custom_sleep_cmd
                template: icon_name

              - type: custom:button-card
                name: Refresh
                icon: mdi:cog-refresh
                tap_action:
                  action: call-service
                  service: switch.toggle
                  service_data:
                    entity_id: switch.hass_custom_hass_restart
                template: icon_name

              - type: custom:button-card
                name: Reboot
                icon: mdi:restart
                tap_action:
                  action: call-service
                  service: switch.toggle
                  service_data:
                    entity_id: switch.hass_pc_restart
                template: icon_name


      ### OFF ###
      - type: conditional
        conditions:
          - entity: binary_sensor.ping_rackstation
            state: 'off'
        card:
          type: vertical-stack
          cards:
            - type: entities
              state_color: true
              show_header_toggle: false
              card_mod:
                class: content
              entities:

                - entity: switch.wol_plex
                  name: Plex
                  secondary_info: last-changed

            - type: horizontal-stack
              cards:
                - type: custom:button-card
                  name: Power On
                  icon: mdi:power
                  tap_action:
                    action: call-service
                    service: switch.turn_on
                    service_data:
                      entity_id: switch.wol_plex
                  template: icon_name

Appreciate it thanks

I made an attempt at getting the circle value in a more generic way. but im going to give up for now.

the issue I have is the number of switches on is not up to date, it always displays 1, but ill post the code so you have more of a base to work from. this was added to the template code you posted above

  variables:
      circle_input:  >
        [[[
          let on = 0, id = Boolean(entity.attributes.entity_id)
            ? [entity.entity_id].concat(entity.attributes.entity_id)
            : [entity.entity_id];
          for (let i = 1; i < id.length; i++) {
            if(states[id[i]].state == 'on') on++
          }
          return entity === undefined || Math.round(on / (id.length -1) * 100 ) ;

        ]]]
  custom_fields:
    circle: >
      [[[
          let input = variables.circle_input,
            radius = 20.5,
            circumference = radius * 2 * Math.PI;
          let on = 0, id = Boolean(entity.attributes.entity_id)
            ? [entity.entity_id].concat(entity.attributes.entity_id)
            : [entity.entity_id];
          for (let i = 1; i < id.length; i++) {
            if(states[id[i]].state == 'on') on++
          }

          let inner_text = `${on} / ${(id.length -1)}`
          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>
          `;
      ]]]

so I have been working on integrating my AC that was just a input_select for fan level and is now using the generic_thermostat, but I having an odd issue tithe the icon_fan2, on the left is the new card and on the right is the old card.

I found that the issue was when the icon was used along with the circle,

Screen Shot 2022-08-28 at 1.43.28 pm

Fix

I needed to apply a better css selector in the icon’s css so it would over ride the css from the circle, I did try important but that didn’t work.

  icon_fan2:
    styles:
      custom_fields:
        icon:
          - width: 75%
          - margin-left: -3%
    custom_fields:
      icon: >
        [[[
          let path = `
            <circle cx="25" cy="25" r="6.6"/>
            <path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
          `,
          style = `
            <svg viewBox="0 0 50 50">
              <style>
                @keyframes rotate {
                  0% {
                    visibility: visible;
                    transform: rotate(0deg) translateZ(0);
                  }
                  100% {
                    transform: rotate(1080deg) translateZ(0);
                  }
                }
                .start {
                  animation: rotate 2.8s ease-in;
                  transform-origin: center;
                  fill: #5daeea;
                  visibility: hidden;
                  will-change: transform;
                }
                .start > circle {
                  fill: #5daeea;
                }
                .on {
                  animation: rotate 1.8s linear infinite;
                  transform-origin: center;
                  fill: #5daeea;
                  animation-delay: 2.8s;
                  visibility: hidden;
                  will-change: transform;
                }
                .on > circle {
                  fill: #5daeea;
                }
                .end {
                  animation: rotate 2.8s;
                  transform-origin: center;
                  fill: #9ca2a5;
                  animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
                  will-change: transform;
                }
                .end > circle {
                  fill: #9ca2a5;
                }
                .start_timeout {
                  animation: rotate 1.8s linear infinite;
                  transform-origin: center;
                  fill: #5daeea;
                  visibility: hidden;
                  will-change: transform;
                }
                .start_timeout > circle {
                  fill: #5daeea;
                }
                .end_timeout {
                  fill: #9ca2a5;
                }
                .end_timeout > circle {
                  fill: #9ca2a5;
                }
              </style>
          `;
          if (variables.state_on && variables.timeout < 2000) {
            return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
          }
          if (variables.state === 'off' && variables.timeout < 2000) {
            return `${style}<g class="end">${path}</g></svg>`;
          }
          if (variables.state_on && variables.timeout > 2000) {
            return `${style}<g class="start_timeout">${path}</g></svg>`;
          } else {
            return `${style}<g class="end_timeout">${path}</g></svg>`;
          }
        ]]]
        
1 Like

Hi! I feel like I’m missing something stupid. The sidebar isn’t coming up even though I haven’t done any edits to it yet. Any ideas? Thanks!

Got the same error yesterday, while I forgot to close a bracket inside a if-condition.

Hey @Laffer, these popups look great!

Are you able to share the code please? Or do you have a repo I could browse through etc?

Thanks!

Hey, fresh HA user here!

I have been trying to add this UI to my home assistant, without proper success.
I’m currently struggling on getting the button_card_templates to work and this is my setup:

The button card template is not defined in config.yaml, if it should be, which way to add it?
I’m completely new to programming so it might be an easy fix, but it seems i can not make HA read the yaml files inside “button_card_templates”, i have been searching online for hours…
I have tested with 'button_card_templates / ’ and without ’ / '… NB, the " behind is not there usually, was after a test i performed.

Can someone tell me what to do to get these button-card templates to work?

1 Like

Figured it out! Somehow the ’ turned into ` so I replaced those and got it working :slight_smile:

Copy this in your first line:

button_card_templates:
  !include_dir_merge_named button_card_templates

In your case its “button-card-templates” instead of “button_card_templates”

On firefox it is very blurry as well here. Is there any way to "configure"this in the tilt.yaml or int he tilt JS we included? the gif is not showing the heavyness of the issue tho.

ezgif.com-gif-maker

Uh, this worked, thank you!!! I feel pretty stupid right now, but i feel i have tested that out earlier so i don’t really understand what i have done wrong. But as long as it works now. :sweat_smile:

1 Like

has perhaps some make a animated volume icon?

klingel

for on / off state?

Welcome @AlfieJ04

They are amazing.

I don’t have all of them but I did copy the Plex one with some edits to get it working for my HA set-up.

Most of the work with the popups like this is getting the data, crating the popup after that is not that bad.

Code

action: fire-dom-event
browser_mod:
  command: popup
  title: Plex
  style:
    hui-vertical-stack-card:
      $: |
        hui-horizontal-stack-card {
          padding: 0em 2em 2.3em 2em;
        }
      $hui-horizontal-stack-card$: |
        #root {
          justify-content: space-evenly;
        }
  card:
    type: vertical-stack
    cards:
      - type: entities
        state_color: true
        card_mod:
          class: content
        entities:
          - entity: switch.docker_plex
            secondary_info: last-changed
            name: Power state
            icon: mdi:power
          - type: custom:bar-card
            width: 55%
            height: 2em
            decimal: 0
            unit_of_measurement: '%'
            positions:
              icon: outside
              indicator: 'off'
              name: outside
            severity:
              - color: '#6d2525'
                from: 90
                to: 999
            entity_row: true
            entities:
              - entity: sensor.template_plex_cpu
              - entity: sensor.template_plex_mem
          - entity: sensor.template_plex_state
            name: health
            icon: mdi:heart-pulse
          - type: divider
          - entity: sensor.plex_crawfordnas
            name: Activity
            icon: mdi:progress-upload
          - entity: sensor.crawfordnas_library_audiobooks
            name: Audiobooks
          - entity: sensor.crawfordnas_library_movies
            name: Movies
          - entity: sensor.crawfordnas_library_tv_shows
            name: TV Shows
      - type: horizontal-stack
        cards:
          - type: custom:button-card
            name: Scan Libraries
            icon: mdi:refresh
            tap_action:
              action: call-service
              service: script.plex_refresh_all
            template: icon_name
          - type: custom:button-card
            name: Scan Clients
            icon: mdi:magnify
            tap_action:
              action: call-service
              service: button.press
              service_data:
                entity_id: button.scan_clients_crawfordnas
            template: icon_name

3 Likes

Hi @masoncrawford1994, thanks for sharing.

I did manage to get something similar put together in the end;

2 Likes

nice work, I like the Movies and Tv shows displaying the usage ill need to look into if I can get that data out of Plex.

Depending on how you have your Plex instance configured, you could use SSH command-line sensors similar to mine;

movies_folder_used: ssh -q -o StrictHostKeyChecking=no -i /config/.ssh/id_rsa <yourUser>@<yourServer> du -shc <yourFolder> | awk '{print $1}' | tail -n 1 2>/dev/null
movies_folder_items: ssh -q -o StrictHostKeyChecking=no -i /config/.ssh/id_rsa <yourUser>@<yourServer> ls -1U <yourFolder> | wc -l | awk '{print $1}' | tail -n 1 2>/dev/null

My popup entry looks like this:

          - entity: sensor.movies_folder_items
            type: custom:multiple-entity-row
            name: Movies
            state_header: current
            show_state: false
            icon: "mdi:folder-play"
            #secondary_info: last-changed
            entities:
              - entity: sensor.movies_folder_items
                name: Amount
              - entity: sensor.movies_folder_used
                name: Usage
3 Likes

I cant read the text on my popups on my tablet. On mobile or browser everything works.
What could this be?

Set theme to dark

1 Like