A different take on designing a Lovelace UI

Awesome. Would you mind sharing the code for this Plex pop up? It looks incredibly useful as a footer and would love to incorporate this.

Thanks for your numerous replies. I’ll have a look into this later this week! :slight_smile:

happy to, share the updated code, I had shared it already A different take on designing a Lovelace UI - #3715 by masoncrawford1994

action: fire-dom-event
browser_mod:
  service: browser_mod.popup
  data:
    title: Plex
    style: >
      --ha-card-border-radius: 0;
    content:
      type: custom:mod-card
      card_mod:
        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.plex_audiobooks_folder_used_2
                type: custom:multiple-entity-row
                name: Audiobooks
                state_header: current
                show_state: false
                icon: "mdi:folder-eye"
                entities:
                  - entity: sensor.plex_audiobooks_folder_items_2
                    name: Amount
                  - entity: sensor.plex_audiobooks_folder_used_2
                    name: Usage
              - entity: sensor.plex_tv_shows_folder_used_2
                type: custom:multiple-entity-row
                name: TV Shows
                state_header: current
                show_state: false
                icon: "mdi:folder-play"
                entities:
                  - entity: sensor.plex_tv_shows_folder_items_2
                    name: Amount
                  - entity: sensor.plex_tv_shows_folder_used_2
                    name: Usage
              - entity: sensor.plex_movies_folder_used_2
                type: custom:multiple-entity-row
                name: Movies
                state_header: current
                show_state: false
                icon: "mdi:folder-play"
                entities:
                  - entity: sensor.plex_movies_folder_items_2
                    name: Amount
                  - entity: sensor.plex_movies_folder_used_2
                    name: Usage
          - 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

Hello again. :slight_smile:

Im pretty sure, someone of you can help me with my problem. :sweat_smile:
At the Moment I got these two cards, the left one is for my climate and the left one for dehumidifier.
The entity_id of the card are climate.xxx and humidifier.xxx, aswell as the “18°C” and the graph at the bottom.
Screenshot 2022-11-15 093515

But im tryining to show there two different sensor which are not from the device. But I have no clue how to get this.

This is the code from the climate in ui-lovelace.yaml:

          - type: custom:button-card
            entity: climate.wohnzimmer_hz
            name: Heizung
            tap_action:
              action: call-service
              service: |
                [[[ return variables.state === 'off' ? 'climate.turn_on' : 'climate.turn_off']]]
              service_data:
                entity_id: climate.wohnzimmer_hz
            double_tap_action:
              !include popup/wohnzimmer_heizung_2.yaml
            custom_fields:
              graph:
                card:
                  entities:
                    - entity: sensor.temperature_7
                    - entity: sensor.nightstate
                      color: gray
                      y_axis: secondary
                      show_line: false
                      show_points: false
                      show_legend: false
                      show_labels: false
                  double_tap_action: !include popup/wohnzimmer_heizung_2.yaml
            template:
              - climate
              - icon_climate
              - circle
            variables:
              circle_input: >
                [[[
                  if (entity) {
                      return entity.state === 'heat'
                          ? Math.round(entity.attributes.temperature).toString()
                          : Math.round(entity.attributes.current_temperature).toString();
                  }
                ]]]
              circle_input_unit: '°C'

And this from the dehumidifier:

          - type: custom:button-card
            entitiy: humidifier.midea_dehumidifier_142936511696163
            name: Entfeuchter
            tap_action:
              action: call-service
              service: |
                [[[ return variables.state === 'off' ? 'humidifier.turn_on' : 'humidifier.turn_off']]]
              service_data:
                entity_id: humidifier.midea_dehumidifier_142936511696163
            double_tap_action:
               !include popup/humidity.yaml
            custom_fields:
              graph:
                card:
                  entities:
                    - entity: sensor.humidity_8
                    - entity: sensor.nightstate
                      color: gray
                      y_axis: secondary
                      show_line: false
                      show_points: false
                      show_legend: false
                      show_labels: false
                  double_tap_action: !include popup/humidity.yaml
            variables: 
              state_on: >
                [[[
                  if (entity) {
                      return entity.state
                  }
                ]]]
              circle_input: >
                [[[
                  if (entity) {
                      return Math.round(entity.state).toString()
                  }
                ]]]
              circle_input_unit: '%'
            template:
              - humidity
              - icon_humidity
              - circle

Could someone help me?


Edit: Solved my problem:

            variables: 
              circle_input: >
                [[[
                  if (entity) {
                      return entity.state === 'on'
                          ? Math.round(entity.attribute.humidity).toString()
                          : Math.round(states['sensor.humidity_8'].state).toString();
1 Like

i have updated browser_mod to the v2 and now my tap actions are not working

I have tried different code but again “nothing pops up”

code is currently

                    entity: cover.all_kitchen_windows
                    tap_action:
                      action: call-service
                      service: browser_mod.popup
                      service_data:
                        content: !include popup/velux.yaml
                    name: Velux

can anyone help please?

Browser_Mod 2 is completely rewriten:

i understand and can see the changes in the files

however it does not cover the code changes required in ui-lovelace.yaml

let me expand abit more

For example on the footer area the button “sensors”

this is the lovelace-ui.yaml code for sensors…

          - type: custom:button-card
            name: >
              <ha-icon icon="mdi:robot-vacuum-variant"></ha-icon>SENSORS
            tap_action:
              !include popup/studio_flakt.yaml
            template: footer

this is the code inside the studio_flakt.yaml file

action: fire-dom-event
browser_mod:
   service: browser_mod.popup

nothing pops up.

I can think of 2 possible issues
1: the code in the popup file should be

action: fire-dom-event
browser_mod:
  service: browser_mod.popup
  data:
    title: title
    content:

followed by the content of the popup.

2: after you make a change to the popup file you will need to make a change in ui-lovelace.yaml for the update to take effect. just delete a letter save, add it back and save.

this is a limitation with home assistant

mason i have excatly that.

Code from popup file…

action: fire-dom-event
browser_mod:
  service: browser_mod.popup
  data:
    title: "Fläkt\u00B2"
    content:
      type: vertical-stack
      cards:
        - type: entities
          state_color: true
          card_mod:
            class: content
          entities:

            - entity: switch.gosund_fan_switch
              secondary_info: last-changed

            - type: custom:slider-entity-row
              entity: input_number.fan_timer
              hide_state: false

code from lovelace-ui.yaml

          - type: custom:button-card
            name: >
              <ha-icon icon="mdi:robot-vacuum-variant"></ha-icon>SENSORS
            tap_action: !include popup/studio_flakt.yaml
            template: footer

tried saving / restarting / cleared cash

have you followed all steps of the browser mod installation?

  • Install browser mod
  • Thoroughly clear your browser cache
  • Go to the Browser Mod panel in your sidebar
  • Make sure the “Register” toggle is checked.
    This is required in order to enable backend services to target this browser.
  • Refresh the page (F5)
  • Go to Developer Tools → Services Open your Home Assistant instance and show your service developer tools.
  • Select service “Browser Mod: popup (browser_mod.popup)”
  • Check the “Title” checkbar and write something as a title
  • Enter some text in the “Content” text box
    Not yaml or anything, just any text for now.
  • Click “CALL SERVICE”
    The button is likely grayed out. That’s a Home Assistant visual bug. Click it anyway.
  • A popup dialog should now open on all your Registered Browsers.
1 Like

Hey there! I am struggling to make the On & Off sound work on my wall mounted tablet with fully kiosk. Haptic feedback works fine, if I call the service manually, the sound does play. I am using fully kiosk integration for media_player and screensaver, tried playing the sound with Browser mod media_player on the same tablet, no luck. Here is my base template code:

  tap_action:
    ui_sound_tablet: |
      [[[
        const tablet = states['switch.galaxy_tab_screensaver'];
        const screensaver = states[tablet] === undefined || states[tablet].state;
        if (variables.state === 'off' && screensaver === 'off') {
            hass.callService('media_player', 'play_media', {
                entity_id: media_player.galaxy_tab,
                media_content_id: '/local/sound/on.m4a',
                media_content_type: 'music'
            });
        }
        if (variables.state_on && screensaver === 'off') {
            hass.callService('media_player', 'play_media', {
                entity_id: media_player.galaxy_tab,
                media_content_id: '/local/sound/off.m4a',
                media_content_type: 'music'
            });
        }
      ]]]
    action: toggle
    haptic: medium

Any and all help is very much appreciated! Have a good one :slight_smile:

Hi dear, how did u put the person in the sidebar? Can u show me the code?

2 Likes

Could you share the code for the weather button you have?

1 Like

hass-config-lajv de lukevink

1 Like

Wow, this looks amazing… did you happen to make a dryer one?

2 Likes

happy to, it was from this post A different take on designing a Lovelace UI - #3268 by htpc2308 and I made a few modifications.

this is a more advanced card and vary custom to my use case, and still a WIP

use

- type: custom:button-card
  entity: weather.home_2
  template:
    - base
    - weather
  tap_action:
    !include ../popup/weather.yaml

weather template

#################################################
#                                               #
#                    Weather                    #
#                                               #
#################################################

weather:
  variables:
    rain: ''        
  entity_picture: |
    [[[
      return entity && entity.state 
        ? `/local/animated-weather-icons/${entity.state}.svg`
        : '?';
    ]]]
  name: |
    [[[
      return entity && entity.attributes && entity.attributes?.temperature
        ? `${entity.attributes.temperature}<sup>°</sup>`
        : '?';
    ]]]
    
  custom_fields:
    rain: |
        [[[
          return entity && entity.attributes && entity.attributes?.forecast
            ? `${ entity.attributes.forecast[0].precipitation_probability} % Rain`
            : '?';
        ]]]
        
    home: |
        [[[
          return entity 
            ? entity.state 
            : '?';
        ]]]
  show_icon: true
  show_state: false
  show_label: false
  show_entity_picture: true
  aspect_ratio: 1/1
  styles:
    
    ############################################################################
    #       GRID (#container)
    ############################################################################
    grid:
      - grid-template-areas: |
          'i n'
          'home home'
          'home home'
          'rain rain'
      - grid-template-columns: 1fr
      - grid-template-rows: min-content repeat(2, 1fr) repeat(2, min-content)
      - gap: 0%
    entity_picture:
      - position: relative
      - margin-top: 0px
      - margin-left: -45%
    icon:
      - align-self: left
      - width: 60%
      - justify-self: flex-end
    name:
      - justify-self: flex-end
      - font-size: 2.4rem
      - margin-top: 10%
      - font-weight: bold
      - text-transform: lowercase
    label:
      - width: 100%
    state:
      - justify-self: start
    card:
      - border-radius: calc(var(--button-card-border-radius) / 2)
      - padding: 1rem
      - height: 100%
      - background-position: center
      - background-size: cover
      - background-repeat: no-repeat
    color: |
          [[[
            const active = 'var(--nolu-color-active, rgb(22, 22, 22))';
            const inactive = 'var(--nolu-color-inactive, rgb(245, 245, 245))';
            const onState = ['on', 'auto', 'home', 'active', 'enabled', 'heat', 'cool', 'heat_cool', 'fan', 'open'];
            const offState = ['off', 'unknown', 'unavailable', 'disabled', 'closed', 'not_home'];
            return variables && variables.state && onState.some(state => variables.state.toLowerCase() === state) 
              ? active 
              : inactive;
          ]]]
          
    
    ############################################################################
    #       CUSTOM FIELDS
    ############################################################################
    custom_fields:
      home:
        - width: 200%
        - place-self: start
        - margin-left: -73%
        - margin-top: 0px
        - font-size: 1.7rem
        - font-weight: light  
      rain:
        - justify-self: flex-end
        - font-size: 1.4rem
        - font-weight: light
  # https://developers.home-assistant.io/docs/core/entity/weather/#recommended-values-for-state-and-condition
  extra_styles: |
            [[[
              let is_day = states['sun.sun'].state === 'above_horizon';
              let image_path = '/local/weather_back/';
              let cardBgColor = '';
              let cardBgImage = '';
              let image_name = '';
              if (entity && entity.state) {
                switch(entity.state) {
                  case 'sunny':
                  case 'clear-night':
                    image_name = is_day ? 'sunny_small.gif':'clear_night_small.gif';
                    break;
                  case 'windy':
                  case 'windy-variant':
                  case 'cloudy':
                    image_name = is_day ? 'cloudy_small.gif':'cloudy_night.gif';
                    break;
                  case 'fog':
                    image_name = 'fog_small.gif';
                    break;
                  case 'hail':
                    image_name = 'hail_small.gif';
                    break;
                  case 'lightning':
                  case 'lightning-rainy':
                    image_name = 'lightning_small.gif';
                    break;
                  case 'partlycloudy':
                    image_name = is_day ? 'partly_cloudy_small.gif':'partlycloudy_night.gif';
                    break;
                  case 'pouring':
                    image_name = is_day ? 'pouring.gif':'pouring_night.gif';
                    break;
                  case 'rainy':
                    image_name = is_day ? 'rainy_small.gif':'rainy_night.gif';
                    break;
                  case 'snowy':
                  case 'snowy-rainy':
                    image_name = 'snowy_small.gif';
                    break;
                  default:
                    cardBgColor = 'rgba(43, 104, 233, 1)';
                    image_name = '';
                    break;
                }
                cardBgColor = 'rgb(117,121,128)';
                cardBgImage = image_name != ''?'linear-gradient(to bottom, rgba(117,121,128,0.4) 10% , rgba(0,0,0,0.4) 38%), url(' + image_path + image_name + ')':none;
              }
              return `
                #aspect-ratio {
                  height: 100%;
                }
                #name > sup {
                  color: rgba(255, 255, 255, 0.5);
                  font-size: 2rem;
                }
                #wind span,
                #humidity span,
                #visibility span {
                  display: block;
                  width: 100%;
                  text-align: center;
                }
                #wind ha-icon,
                #humidity ha-icon,
                #visibility ha-icon {
                  --mdc-icon-size: 20px;
                  margin-top: 0.5rem;
                }
                #wind #title,
                #humidity #title,
                #visibility #title {
                  font-size: 0.95rem;
                  font-weight: 500;
                  margin-top: 0.5rem;
                }
                #title b {
                  font-size: 0.85rem;
                  color: rgba(255, 255, 255, 0.6);
                }
                #wind #subtitle,
                #humidity #subtitle,
                #visibility #subtitle {
                  color: rgba(255, 255, 255, 0.6);
                  font-size: 0.90rem;
                  margin-top: 0.5rem;
                  overflow: hidden;
                  text-overflow: ellipsis;
                  white-space: nowrap;
                }
                #card {
                  background-color: ${cardBgColor};
                  background-image: ${cardBgImage};
                }
                @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);
                  }
                }
              `;
            ]]]

popup

action: fire-dom-event
browser_mod:
  command: popup
  title: Forecast  
  card:
    type: vertical-stack
    cards:
      - type: custom:mushroom-chips-card
        chips:
          - type: entity
            entity: sun.sun
          - type: template
            content: >-
              Sunrise  {% if states.sun.sun %} {{
              (as_timestamp(states.sun.sun.attributes.next_rising)) |
              timestamp_custom(('%H:%M') )}} {% endif %}
            icon: mdi:weather-sunset-up
          - type: template
            content: >-
              Sunset  {% if states.sun.sun %} {{
              (as_timestamp(states.sun.sun.attributes.next_setting)) |
              timestamp_custom(('%H:%M') )}} {% endif %}
            icon: mdi:weather-sunset-down
          - type: entity
            entity: sensor.moon_phase
        alignment: center
      - type: weather-forecast
        entity: weather.home_2
        secondary_info_attribute: humidity
        show_current: true
        show_forecast: true

backgrounds

note: the “pouring” image was too big you will need to hunt one down

Click to view images

clear_night_small
cloudy_night
cloudy_small
fog_small
hail_small
lightning_small
partly_cloudy_small
partlycloudy_night
pouring_night
rainy_night
rainy_small_new
snowy_small
sunny_small

8 Likes

Thanks. Yes so we were in the same boat. Programming is not always a pro when working with projects I’ve learned. Conditional media for me was also weird mostly because I kept trying to apply logic and syntax from JS frameworks which is obviously not the correct syntax.

I’m working on the video now. I’ve added some new stuff lately too such as pet detection with a customized frigate NVR etc. I am considering doing several video tutorials because my prior text ones seem to be too much for normal users to follow.

I adore this community but despite most of us being geeks there are plenty of people just starting out and I think HA really shines for them too.

This is amazing. Thank you.

Finally done and ready to share some of my screenshots
I kept the dashboard pretty vanilla, but with some small changes/additions specific to my usecase:

Main dashboard:

Alternative to Media for me, is a remote, for when I have a cat laying on me, and can’t reach the physical remote:
image

Pop-up for environment sensors such as the bottom left of the first block of four called “Woonkamer”
It’s not perfect, but it gives the information I want at a glance, hovering over the graphs gives the actual values in a small popup tooltip
image

Ventilation popup

Garbage popup is nothing more than next garbage days:
image

Weather popup

Doorbell popup

OpnSense popup
image

I think that’s mostly it.
As I said, a lot is just default, but some custom adjustments
Still needs some work here and there, not happy with every popup, but overall it works very well for me :slight_smile:

8 Likes