A different take on designing a Lovelace UI

Thanks a lot, that was my missing piece.

Hi all,
any suggestion how I can add an if else function in the button_card_templates.yaml ?
I do want to change the color of the circle for the person card in dependence of the teams presence status and the original state home <-> not home.

So far it’s working pretty well:
(Red Circle for in a call)
2022-08-19 11_02_42-Übersicht – Home Assistant und 23 weitere Seiten - Geschäftlich – Microsoft​ Edg

But when not at home and not in a call the circle is not like in the original design from Matthias:
2022-08-19 11_26_31-Übersicht – Home Assistant und 23 weitere Seiten - Geschäftlich – Microsoft​ Edg

This is obivously because of my moddification in the template file as I don’t know how to implent the if else function:

            stroke = states[variables.teams].state == 'Am Telefon' || states[variables.teams].state == 'In einer Besprechung'  
              ? 'red'
              : '#b2b2b2',

E.g. if stroke = states[variables.teams].state == ‘Work’ then ‘none’

Furthermore I try to let the circle (just the circle) blink when I’m in a call. I don’t get it, how to select just the circle himself? With the following modification, the hole SVG (so circle and text) start to blink. Any suggestion how to achieve that, just the circle blinks?

Animation

        circle:
          - animation: >
              [[[
                if (entity) {
                  return states[variables.teams].state == 'Am Telefon'
                    ? 'blink 2s ease infinite'
                    : 'none';
                }
              ]]]
2 Likes

Yeah, doing it that way styles the whole div. You can add a new custom_field to set the styles with js

person:
  custom_fields:
    blink: >
      [[[
        setTimeout(() => {
          let elt = this.shadowRoot,
            circle_stroke = elt.getElementById('circle_stroke');
          if (
            states[variables.teams]?.state == 'Am Telefon' ||
            states[variables.teams]?.state == 'In einer Besprechung'
          ) {
            circle_stroke.style.animation = 'blink 2s ease infinite';
            circle_stroke.style.stroke = 'red';
          } else {
            circle_stroke.removeAttribute('style');
          }
        }, 0);
      ]]]
1 Like

Hi @Mattias_Persson, apologies if this was asked and answered, i might be late to the party on this.

I am trying to updated form the old command_line for udm_unifios that was stored in the secrets file (see old command below) to the new python3 implementation, but the script is not running, i just get an error in the logs “Command failed (with return code 1):” followed by the script (see full error message below), i think i am missing a step but with the move of the file i cant find the commit where this was added.

oh and in this commit, use update entities · matt8707/hass-config@1408d40 · GitHub you forgot to remove the use of udm_upgradable on line 586 in ui-lovelace.yaml

Error Message

Command failed (with return code 1): python3 << EOF import json, yaml, requests from datetime import datetime from urllib3 import disable_warnings disable_warnings() SECRETS_FILE = "/config/secrets.yaml" def get_secret(secret): try: with open(SECRETS_FILE, "r", encoding="utf8") as file: secrets = yaml.full_load(file) for key, value in secrets.items(): if key == secret: return value except FileNotFoundError: print("secrets.yaml not found") exit() IP = get_secret("unifi_host") PORT = get_secret("unifi_port") USER = get_secret("unifi_username") PASS = get_secret("unifi_password") URL = f"https://{IP}:{PORT}" login = requests.request("POST", f"{URL}/api/auth/login", \ headers={"Content-Type": "application/json"}, \ data=json.dumps({"username": USER, "password": PASS}), verify=False) response = requests.request("GET", f"{URL}/proxy/network/api/s/default/stat/device/", \ cookies=login.cookies, verify=False) data = response.json()["data"][0] print(json.dumps({ "cpu": data["system-stats"]["cpu"], "cpu_temp": round(data["temperatures"][1]["value"], 1), "mem": data["system-stats"]["mem"], "disk": round(data["storage"][1]["used"] / data["storage"][1]["size"] * 100, 1), "internet": data["internet"], "uptime": datetime.fromtimestamp(data["startup_timestamp"]).isoformat(), "version": data["displayable_version"] })) EOF

Note: i did update the keys in the script to match what i have in my secrets
unifi_host is just the IP that i use to connect to my UDM
unifi_port is 433 that was the port used in the old script.

Old Command

platform: command_line
name: udm_unifios
command: !secret udm_unifios
value_template: |-
  {% set json = value_json.data[0] %}
  {{ json["system-stats"].cpu }}|
  {{ json.temperatures[1].value | round(1) }}|
  {{ json["system-stats"].mem }}|
  {{ ((json.storage[1].used / json.storage[1].size) * 100) | round(1) }}|
  {{ json.internet }}|
  {{ json.startup_timestamp | timestamp_local }}|
  {{ json.displayable_version }}|
  {{ json.upgradable }}
scan_interval: 120

Hello,

Thanks for this great dashboard! I’m currently trying to create a template for a climate (radiator) card, code shown below. The base template is referenced from the original.

climate:
  template:
    - base
  double_tap_action:
    action: fire-dom-event
    browser_mod:
      command: popup
      title: >
        [[[
          return !entity || entity.attributes.friendly_name;
        ]]]
      style:
        hui-entities-card:
          $: |
            #states {
              padding-top: 0.8em;
            }
      card:
        type: entities
        entities: >
          [[[
            if (entity) {
                let climate = [],
                    id = Boolean(entity.attributes.entity_id)
                        ? [entity.entity_id].concat(entity.attributes.entity_id)
                        : [entity.entity_id];

                for (let i = 0; i < id.length; i++) {
                    climate.push({
                        "type": "custom:mushroom-climate-card",
                        "entity": id[i],
                        "fill_container": false,
                        "primary_info": "name",
                        "secondary_info": "state",
                        "icon_type": "icon",
                        "show_temperature_control": true,
                        "hvac_modes": ["off","auto","heat"],
                        "collapsible_controls": true
                    });
                }
                return climate;
            }
          ]]]
  variables:
    circle_current_temp_input: >
      [[[ {
            const current_temperature = entity.attributes.current_temperature;
            return current_temperature;
        }
      ]]]
    circle_current_temp_unit: "°"
    circle_set_temp_input: >
      [[[ {
            const set_temperature = entity.attributes.temperature;
            return set_temperature;
        }
      ]]]
    circle_set_temp_unit: "°"
  custom_fields:
    circle_current_temp: >
      [[[
        if (entity) {
            let r = 22.1,
                c = r * 2 * Math.PI,
                tspan = '<tspan dx=".2" dy="-.4">',
                domain = entity.entity_id.split('.')[0],
                state = variables.state,
                input = variables.circle_current_temp_input || ' ',
                unit = variables.circle_current_temp_unit || ' ';

           /* * * * * * * * * * * * * * * * * *
            *                                 *
            *             CIRCLE              *
            *                                 *
            * * * * * * * * * * * * * * * * * */

            let circle = (state, input, unit) => {
                return `
                  <svg viewBox="0 0 50 50">
                    <style>
                      circle {
                        transform: rotate(-90deg);
                        transform-origin: 50% 50%;
                        stroke-dasharray: ${c};
                        stroke-width: var(--c-stroke-width);
                        stroke: ${state ? 'var(--c-stroke-color-on-current)' : 'var(--c-stroke-color-off-current)'};
                        fill: ${state ? 'var(--c-fill-color-off-current)' : 'var(--c-fill-color-on-current)'};
                      }
                      text {
                        font-size: var(--c-font-size);
                        font-weight: var(--c-font-weight);
                        letter-spacing: var(--c-letter-spacing);
                        fill: ${state ? 'var(--c-font-color-off)' : 'var(--c-fill-color-on)'};
                      }
                      tspan {
                        font-size: var(--c-unit-font-size);
                      }
                      #circle_value, tspan {
                        text-anchor: middle;
                        dominant-baseline: central;
                      }
                    </style>
                    <circle id="circle_stroke" cx="25" cy="25" r="${r}"/>
                    <text id="circle_value" x="50%" y="52%">${input}${tspan}${unit}</tspan></text>
                  </svg>
                `;
            }

            if (domain === 'climate') {
                return circle(state, input, unit);
            }
        }
      ]]]
    circle_target_temp: >
      [[[
        if (entity.state === "heat") {
            let r = 22.1,
                c = r * 2 * Math.PI,
                tspan = '<tspan dx=".2" dy="-.4">',
                domain = entity.entity_id.split('.')[0],
                state = variables.state,
                input = variables.circle_set_temp_input || ' ',
                unit = variables.circle_set_temp_unit || ' ',
                valve_pos = variables.valve,
                valve_pos_num = valve_pos.slice(0, -1);


           /* * * * * * * * * * * * * * * * * *
            *                                 *
            *             CIRCLE              *
            *                                 *
            * * * * * * * * * * * * * * * * * */

            let circle = (state, input, unit) => {
                return `
                  <svg viewBox="0 0 50 50">
                    <style>
                      circle {
                        transform: rotate(-90deg);
                        transform-origin: 50% 50%;
                        stroke-dasharray: ${c};
                        stroke-dashoffset: ${c - valve_pos_num / 100 * c};
                        stroke-width: var(--c-stroke-width);
                        stroke: ${state ? 'var(--c-stroke-color-on-target)' : 'var(--c-stroke-color-off-target)'};
                        fill: ${state ? 'var(--c-fill-color-on-target)' : 'var(--c-fill-color-off-target)'};
                      }
                      text {
                        font-size: var(--c-font-size);
                        font-weight: var(--c-font-weight);
                        letter-spacing: var(--c-letter-spacing);
                        fill: var(--c-font-color);
                      }
                      tspan {
                        font-size: var(--c-unit-font-size);
                      }
                      #circle_value, tspan {
                        text-anchor: middle;
                        dominant-baseline: central;
                      }
                    </style>
                    <circle id="circle_stroke" cx="25" cy="25" r="${r}"/>
                    <text id="circle_value" x="50%" y="52%">${input}${tspan}${unit}</tspan></text>
                  </svg>
                `;
            }

            if (domain === 'climate') {
                return circle(state, input, unit);
            }
        }
      ]]]
  styles:
    card:
      - --c-stroke-color-on-target: "#b0b0b0"
      - --c-stroke-color-off-target: none
      - --c-stroke-color-on-current: none
      - --c-stroke-color-off-current: none
      - --c-fill-color-on-target: none
      - --c-fill-color-off-target: rgba(255,255,255,0.04)
      - --c-fill-color-on-current: rgba(78,198,110,0.6)
      - --c-fill-color-off-current: rgba(255,255,255,0.04)
      - --c-stroke-width: 2.3
      - --c-stroke-width-current: 0
      - --c-stroke-width-dragging: 4
      - --c-font-color: "#97989c"
      - --c-font-color-off: "#97989c"
      - --c-font-color-on: white
      - --c-font-size: 14px
      - --c-unit-font-size: 10.5px
      - --c-font-weight: 700
      - --c-letter-spacing: -0.02rem
    custom_fields:
      circle_target_temp:
        - display: initial
        - width: 88%
        - margin: -3% 2% 0 0
        - justify-self: end
        - opacity: 1
      circle_current_temp:
        - display: initial
        - width: 88%
        - margin: -3% 14% 0 0
        - justify-self: end
        - opacity: 1
    grid:
      - grid-template-areas: |
          "circle_current_temp  circle_target_temp"
          "n                    n"
          "s                    s"
      - grid-template-columns: repeat(2, 1fr)
      - grid-template-rows: auto repeat(2, min-content)
      - gap: 1.3%
      - align-items: start

This is what i get when the climate entity state is off, no problems. Current temperature is shown in the top left corner:
image

When the climate enitity state is heat, this is what i get, but this is not the way i intended:
image

What i expected is this, with a green fill-color for the circle and the target temperature in the top right corner:
image

If someone could point me in the rigtht direction, it would be much appriciated! :crossed_fingers:

Yeah, that error doesn’t tell much. Test the most basic form locally then if that works add the json paths and lastly the secrets function.

import json, yaml, requests
from datetime import datetime
from urllib3 import disable_warnings
disable_warnings()

IP = " "
PORT = " "
USER = " "
PASS = " "
URL = f"https://{IP}:{PORT}"

login = requests.request("POST", f"{URL}/api/auth/login", \
    headers={"Content-Type": "application/json"}, \
    data=json.dumps({"username": USER, "password": PASS}), verify=False)
response = requests.request("GET", f"{URL}/proxy/network/api/s/default/stat/device/", \
    cookies=login.cookies, verify=False)

print(response.json())

Thanks! 95c6a1f

Hello There
I have a problem with the footer and I have no idea what it can be. The size of the buttons does not adjust automatically. If I change the with from “fit-content” to 100px in footer.yaml, the buttons scale.

#button_card_templates: !include button_card_templates.yaml
button_card_templates:
  !include_dir_merge_named button_card_templates

views:
  - type: custom:grid-layout
    path: 0
    layout:
      #default
      margin: 0
      grid-gap: var(--custom-layout-card-padding)
      grid-template-columns: repeat(4, 1fr) 0
      grid-template-rows: 0 repeat(2, fit-content(100%)) 0fr
      grid-template-areas: |
        "sidebar  .           .       .             ."
        "sidebar  wohnzimmer  flur    schlafzimmer  ."
        "sidebar  media       sonos   home          ."
        "sidebar  footer      footer  footer        ."
      mediaquery:
        #phone
        "(max-width: 800px)":
          grid-gap: calc(var(--custom-layout-card-padding) * 1.7)
          grid-template-columns: 0 repeat(2, 1fr) 0
          grid-template-rows: 0 repeat(5, fit-content(100%)) 0fr
          grid-template-areas: |
            ".  .           .             ."
            ".  sidebar     sidebar       ."
            ".  wohnzimmer  schlafzimmer  ."
            ".  flur        home          ."
            ".  media       sonos         ."
            ".  footer      footer        ."
            ".  .           .             ."
        #portrait
        "(max-width: 1200px)":
          grid-gap: var(--custom-layout-card-padding)
          grid-template-columns: repeat(3, 1fr) 0
          grid-template-rows: 0 repeat(3, fit-content(100%)) 0fr
          grid-template-areas: |
            "sidebar  .           .             ."
            "sidebar  wohnzimmer  schlafzimmer  ."
            "sidebar  flur        home          ."
            "sidebar  media       sonos         ."
            "sidebar  footer      footer        ."
    cards:

      - type: custom:button-card #extra_styles fix
        styles: {card: [display: none]}

      #################################################
      #                                               #
      #                    SIDEBAR                    #
      #                                               #
      #################################################

      - type: vertical-stack
        view_layout:
          grid-area: sidebar
        cards:
          - type: custom:button-card
            entity: sensor.template_sidebar
            template: sidebar

      #################################################
      #                                               #
      #                  Wohnzimmer                   #
      #                                               #
      #################################################

      - type: grid
        title: Wohnzimmer
        view_layout:
          grid-area: wohnzimmer
        columns: 2
        cards:

          - type: custom:button-card
            entity: light.new_york
            name: New York
            template:
              - light
              - icon_hue

          - type: custom:button-card
            entity: light.schnapstrue
            name: Schnapstruhe
            template:
              - light
              - icon_hue

          - type: custom:button-card
            entity: sensor.weather_station_temperature
            name: Temperatur
            tap_action:
              action: more-info
            custom_fields:
              graph:
                card:
                  entities: 
                    - sensor.weather_station_temperature
            template:
              - temperature
              - icon_temp
            variables:
              popup_name: Temperatur


          - type: custom:button-card
            entity: light.salzstein
            name: Salzstein
            template:
              - light
              - icon_hue

      #################################################
      #                                               #
      #                    Schlafzimmer               #
      #                                               #
      #################################################

      - type: grid
        title: Schlafzimmmer
        view_layout:
          grid-area: schlafzimmer
        columns: 2
        cards:

          - type: custom:button-card
            entity: light.schlafzimmer
            name: Ständerlampe
            template:
              - light
              - icon_lamp

          - type: custom:button-card
            entity: fan.luftibert 
            name: "Lüftibert"
            hold_action:
              !include popup/schlafzimmer_fan.yaml
            tap_action:
              action: more-info
            template:
              - base
              - icon_fan



          - type: custom:button-card
            entity: media_player.hauptschlafzimmer
            name: Sonos
            hold_action:
              !include popup/sonos.yaml
            template:
              - base
              - icon_sonos
              - loader

          - type: custom:button-card
            entity: sensor.luftibert_temperature
            name: Temperatur
            tap_action:
              action: more-info
            custom_fields:
              graph:
                card:
                  entities: 
                    - sensor.luftibert_temperature
            template:
              - temperature
              - icon_temp
            variables:
              popup_name: Temperatur



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

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

          - type: custom:swipe-card
            start_card: 1
            parameters:
              roundLengths: true
              effect: coverflow
              speed: 650
              spaceBetween: 20
              threshold: 7
              coverflowEffect:
                rotate: 80
                depth: 300
            cards:

              - type: custom:spotify-card
                account: default
                spotify_entity: media_player.spotify_jan_stager
                playlist_type: discover-weekly
                grid_covers_per_row: '2'
                limit: 4
                country_code: DE
                default_device: Küche
                display_style: grid
                known_connect_devices:
                  - id: d4757ab523224358f9c9052ee4de85ba324c41fa
                    name: Küche
                    entity_id: media_player.kuche

              - type: custom:mini-media-player
                entity: media_player.kuche
                hide:
                  power: true
                  volume: true
                  controls: true
                  source: true
                speaker_group:
                  platform: sonos
                  show_group_count: true
                  entities:
                    - entity_id: media_player.kuche
                      name: Sonos Küche
                    - entity_id: media_player.badezimmer
                      name: Sonos Badezimmer
                    - entity_id: media_player.buro
                      name: Sonos Büro
                    - entity_id: media_player.hauptschlafzimmer
                      name: Sonos Schlafzimmer
                    - entity_id: media_player.balkon
                      name: Sonos Balkon
                entities:
                  - type: custom:mini-media-player
                    entity: media_player.multiroom_player
                    group: true
                    source: icon
                    artwork: cover
                    info: scroll
                    hide:
                      volume: true
                      power_state: true
                  - type: custom:mini-media-player
                    entity: media_player.kuche
                    group: true
                    hide:
                      controls: true
                  - type: custom:mini-media-player
                    entity: media_player.badezimmer
                    group: true
                    hide:
                      controls: true
                  - type: custom:mini-media-player
                    entity: media_player.buro
                    group: true
                    hide:
                      controls: true
                  - type: custom:mini-media-player
                    entity: media_player.hauptschlafzimmer
                    group: true
                    hide:
                      controls: true
                  - type: custom:mini-media-player
                    entity: media_player.balkon
                    group: true
                    hide:
                      controls: true
                

      #################################################
      #                                               #
      #                    Sonos                      #
      #                                               #
      #################################################
      - type: grid
        title: Sonos
        view_layout:
          grid-area: sonos
        columns: 1
        cards:

          - type: entities
            entities:
              - type: custom:mini-media-player
                entity: media_player.kuche
                group: true
                hide:
                  controls: true
                  power: true
                  icon: true
                  info: true
                  source: true
                  progress: true
              - type: custom:mini-media-player
                entity: media_player.buro
                group: true
                hide:
                  controls: true
                  power: true
                  icon: true
                  info: true
                  source: true
                  progress: true
              - type: custom:mini-media-player
                entity: media_player.badezimmer
                group: true
                hide:
                  controls: true
                  power: true
                  icon: true
                  info: true
                  source: true
                  progress: true
              - type: custom:mini-media-player
                entity: media_player.hauptschlafzimmer
                name: Schlafzimmer
                group: true
                hide:
                  controls: true
                  power: true
                  icon: true
                  info: true
                  source: true
                  progress: true
              - type: custom:mini-media-player
                entity: media_player.balkon
                name: Balkon
                group: true
                hide:
                  controls: true
                  power: true
                  icon: true
                  info: true
                  source: true
                  progress: true

      #################################################
      #                                               #
      #                    Flur                       #
      #                                               #
      #################################################

      - type: grid
        title: Flur
        view_layout:
          grid-area: flur
        columns: 2
        cards:


          - type: custom:button-card
            entity: light.group_hall
            name: Hall
            template:
              - light
              - icon_spot

      #################################################
      #                                               #
      #                     Home                      #
      #                                               #
      #################################################

      - type: grid
        title: Home
        view_layout:
          grid-area: home
        columns: 2
        cards:

          - type: custom:button-card
            entity: script.home_leave
            name: Good Bye
            hold_action:
              action: none
            template:
              - base
              - icon_away

          - type: custom:button-card
            entity: script.home_arrive
            name: Welcome
            hold_action:
              action: none
            template:
              - base
              - icon_home

          - type: custom:button-card
            entity: script.good_night
            name: Good Night
            hold_action:
              action: none
            template:
              - base
              - icon_good_night

          - type: custom:button-card
            entity: script.music
            name: Music
            hold_action:
              action: none
            template:
              - base
              - icon_music


      #################################################
      #                                               #
      #                    FOOTER                     #
      #                                               #
      #################################################
      
      - type: horizontal-stack
        view_layout:
          grid-area: footer
        cards:

          - type: custom:button-card
            name: >
              <ha-icon icon="mdi:nas"></ha-icon> NAS
            tap_action:
              !include popup/footer_nas.yaml
            triggers_update:
              - binary_sensor.jan_home_update_available
              - sensor.jan_home_status
              - binary_sensor.jan_home_security_status
              - sensor.disk_use_percent
            variables:
              notify: >
                [[[
                  let id = this._config.triggers_update;
                  if (id.every(e => states[e]))
                      return states[id[0]].state === 'on'
                          ? 1
                          : states[id[1]].state === 'background_scrubbing' ||
                            states[id[2]].state === 'on' ||
                            parseFloat(states[id[3]].state) >= 85;
                ]]]
            template: footer

          - type: custom:button-card
            name: >
              <ha-icon icon="mdi:arrow-up-bold-circle-outline"></ha-icon> Updates
            tap_action:
              !include popup/footer_updates.yaml
            triggers_update:
              - sensor.hacs
              - sensor.docker_hub_beta
              - sensor.docker_hub
            variables:
              notify: >
                [[[
                  let id = this._config.triggers_update;
                  if (id.every(e => states[e])) {
                      let hacs = parseInt(states[id[0]].state),
                          installed = hass.config.version,
                          latest = installed.includes('b')
                              ? states[id[1]].state
                              : states[id[2]].state;

                      if (latest.includes('.') && Number.isInteger(hacs))
                          return hacs + (installed !== latest ? 1 : 0);
                  }
                  return 0;
                ]]]
            template: footer

          - type: custom:button-card
            name: >
              <ha-icon icon="custom:roborock-vacuum"></ha-icon> Buddy
            tap_action:
              !include popup/footer_vacuum.yaml
            triggers_update:
              - sensor.date
            variables:
              notify: >
                [[[
                  let id = states['sensor.morty_last_clean_end'];
                  if (id) return (Date.now() - Date.parse(id.state)) > 6048e5;
                ]]]
            template: footer

          - type: custom:button-card
            name: >
              <ha-icon icon="mdi:chart-line-variant"></ha-icon> Statistik
            tap_action:
              !include popup/footer_history.yaml
            template: footer

          - type: custom:button-card
            name: >
              <ha-icon icon="custom:cupra"></ha-icon> Cupra
            tap_action:
              !include popup/footer_cupra.yaml
            template: footer     

I am grateful for every hint

Hi @Mattias_Persson , first thank you for your setup and help. I did everything as listed in Github Installation Instructions. First I got error:
secret Youtube_token not defined
but I fixed it by commenting it in media.yaml.
But now I get the error:
Secret apexcharts_tibber not defined
I dont know how to fix and I already searched this post but didnt find any solution. I already installed the apexcharts repo via hacs.
Can you please give me a solution?
Thank you!

That’s outdated instructions, there’s no secrets anymore. You’ll have to copy the files from my repo again https://github.com/matt8707/hass-config/blob/00de2dd3ce0f3145e20ae0de5adda518b37b0194/INSTALL.md

Try this #00de2dd

Okay thank you so much I will try it!

Hi so I´m sure this was asked a lot, but can somebody please tell me which files I need to look at for changing text, language, adding my own entities?
Thanks

Thank you :slight_smile:

but where can I do like the living room etc? Because in Lovelace ui it messes up everything when I change?

Mattias,
Or really anyone with the knowledge.
I have the Unifi UDM-Pro but I’m really struggling trying to get the footer to populate. Everything pops-up as should but shows “unknown” for values.
I’ve made the appropriate changes in !secrets and looked over "router_unifi.yaml to see where i may need some changes.
This instance of Unifi controller is not hosted anywhere other than on the UDM-pro.
I’ve tried doing the ssh into UDM without success.
Does something need to be enabled that I’m missing?
I do have the Unifi addon working, and have tried the same user and pass as that and still no go.

Hey buddy great work, would you mind sharing your Plex popup. Is this collected off of another computer or server (docker)?

I’m attempting to make an auto-populating card for switch groups, based of the code for the new light popup… however I am was scratching my head as to what format is needed for:

tap_action:
  action: toggle

I eventually figured it out.
Here is the button card template:

switch:
  template:
    - base
    #- circle
    - loader
  double_tap_action:
    action: fire-dom-event
    browser_mod:
      command: popup
      title: >
        [[[
          return !entity || entity.attributes.friendly_name;
        ]]]
      style:
        hui-entities-card:
          $: |
            #states {
              padding-top: 0.8em;
            }
      card:
        type: entities
        entities: >
          [[[
            if (entity) {
                let switches = [],
                    id = Boolean(entity.attributes.entity_id)
                        ? [entity.entity_id].concat(entity.attributes.entity_id)
                        : [entity.entity_id];

                for (let i = 0; i < id.length; i++) {
                    switches.push({
                        "type": "custom:mushroom-entity-card",
                        "entity": id[i],
                        "fill_container": false,
                        "primary_info": "name",
                        "secondary_info": "last-changed",
                        "icon_type": "icon",
                        "icon_color": "light-green",
                        "tap_action": { action: 'toggle' }
                    });
                }
                return switches;
            }
          ]]]

I’m still yet two wrap my head around how to set up the circle info to display “x/y” (where x is number of switches in the on state and y is the total of switches), then all that’s left is to fill the circle line out as a percentage of that.

I got it working, it was a combination of issues,

I had port 433 not 443 in my secretes but when I tested the code I used 443
and my HA user role didn’t have access to UniFiOS.

Thanks for the help, would not have been as much of an issue if the errors was more understandable but that’s a HA issue.

Love your config for the second screen. Could you share the Yaml?