A different take on designing a Lovelace UI

Hello. Do you do this with a smart washing machine or simulate washing for a while? thank you

Yes it’s a smart washer / dryer.

Ahh. Beautiful. Thanks for answering

Hello everyone. I wanted to ask you for help with a card. I really don’t know how to make it look good.
The first problem I find is that the entire grid is divided into more parts than it should or the grid-template-areas is badly set up.

I would like the image to occupy almost the entire card and for the temperature to be superimposed so that both things can be appreciated well, the image of the weather and the temperature. Could someone explain to me what I’m doing wrong and what I can do to correct it? Thank you so much.

#################################################
#                                                                                              #
#                                         CLIMA                                          #
#                                                                                              #
#################################################

clima:
  variables:
    state: >
      [[[ return entity === undefined || entity.state;]]]
    timeout: >
      [[[ return entity === undefined || Date.now() - Date.parse(entity.last_changed); ]]]
    light_color: >
      [[[ return entity === undefined ? 'var(--state-icon-color)' : 'var(--button-card-light-color-no-temperature)'; ]]]
  aspect_ratio: 1/1
  show_state: false
  show_icon: false # linea const tablet     states['switch.galaxy_tab_a_screensaver'];
  tap_action:
    ui_sound_tablet: |
      [[[      
        const tablet = 1; 
        const screensaver = states[tablet] === undefined || states[tablet].state;
        if (variables.state === 'off' && screensaver === 'off') {
          hass.callService('media_player', 'play_media', {
            entity_id: 'media_player.tab_10_pro',
            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.tab_10_pro',
            media_content_id: '/local/sound/off.m4a',
            media_content_type: 'music'
          });
        }
      ]]]
    animation_card: |
      [[[
        const animation_speed_ms = 900;
        const animation = `card_bounce ${animation_speed_ms}ms cubic-bezier(0.22, 1, 0.36, 1)`;
        this.shadowRoot.getElementById("card").style.animation = animation;
        window.setTimeout(() => {
          this.shadowRoot.getElementById("card").style.animation = "none";
        }, animation_speed_ms)
      ]]]
    action: toggle
    haptic: medium
  styles:
    grid:
      - grid-template-areas: |
          "icon"
      - grid-template-columns: auto 
      - grid-template-rows: auto 
    #  - align-items: start
    # name:
    #   - justify-self: start
    #   - line-height: 100%
    # state:
    #   - justify-self: start
    #   - line-height: 100%
    card:
      - font-family: Sf Text
      - border-radius: var(--custom-button-card-border-radius)
      - -webkit-tap-highlight-color: rgba(0,0,0,0)
      - transition: none
      - padding: 10% 10% 6% 10%
      - --mdc-ripple-color: >
          [[[
            return 'rgba(255, 255, 255, 0.3)';
          ]]]
      - color: >
          [[[
            return 'rgba(255, 255, 255, 0.3)';
          ]]] 
    custom_fields:
      temperature: [letter-spacing: 0.03vw, font-size: 2vw]
  extra_styles: |
    #temperature {
      font-size: 1vw;
      letter-spacing: 0.05vw;
    }
    /* portrait */
    @media screen and (max-width: 1200px) {
      #temperature {
        font-size: 5vw;
        letter-spacing: 0.05vw;
      }
    } 
    /* phone */
    @media screen and (max-width: 800px) {
      #temperature {
        font-size: 6vw;
        letter-spacing: 0.03vw;
      }
    }
  custom_fields:
    temperature: >
      [[[
        const temp = entity.attributes.temperature 
        return `${temp}°`
      ]]]
    icon: >
      [[[
        const hoy = new Date();
        var hora = hoy.getHours() + ':' + hoy.getMinutes()
        if (variables.state === 'cloudy')     
          if (states['sun.sun'].state === "above_horizon")
            return '<img src="/local/img/forecast/mostly_sunny_light_color_96dp.png">'; 
          else
            return '<img src="/local/img/forecast/mostly_clear_night_light_color_96dp.png">'; 
        else if (variables.state === 'sunny')     
          return '<img src="/local/img/forecast/sunny_light_color_96dp.png">'; 
        else if (variables.state === 'clear-night')     
          return '<img src="/local/img/forecast/clear_night_dark_color_96dp.png">'; 
        else if (variables.state === 'rainy')     
          return '<img src="/local/img/forecast/showers_rain_light_color_96dp.png">'; 
        else if (variables.state === 'partlycloudy')     
          if (states['sun.sun'].state === "above_horizon")    
            return '<img src="/local/img/forecast/partly_cloudy_light_color_96dp.png">'; 
          else
            return '<img src="/local/img/forecast/partly_cloudy_night_light_color_96dp.png">'; 
        else if (variables.state === 'lightning-rainy')     
          if (states['sun.sun'].state === "above_horizon")      
            return '<img src="/local/img/forecast/scattered_showers_day_dark_color_96dp.png">'; 
          else
            return '<img src="/local/img/forecast/scattered_showers_night_dark_color_96dp.png">'; 
        else if (variables.state === 'lightning')     
          return '<img src="/local/img/forecast/isolated_scattered_tstorms_day_dark_color_96dp.png">'; 
        else if (variables.state === 'pouring')     
          return '<img src="/local/img/forecast/heavy_rain_dark_color_96dp.png">'; 
        else if (variables.state === 'snowy')     
          return '<img src="/local/img/forecast/snow_showers_snow_dark_color_96dp.png">'; 
        else if (variables.state === 'snowy-rainy')     
          return '<img src="/local/img/forecast/wintry_mix_rain_snow_dark_color_96dp.png">'; 
        else if (variables.state === 'fog')     
          return '<img src="/local/img/forecast/haze_fog_dust_smoke_dark_color_96dp.png">'; 
        else if (variables.state === 'exceptional')
          return ''; 
        else 
          return variables.state;         
      ]]]


I can’t look into this at the moment but, this might help you out, this is a post with the code for the weather card that I use

Hi All

This is really nice and all. Love and way above my knowledge skill.
May I ask one thing, I have made a copy of this and its working and all. but could someone please tell me how to create custom icons for card. I have installed hacs: Hass Hue Icons and will like to use those. If possible a Step by Step. Would greatly appreciate it.

Also: if some one is able to tell me how the sidebar battery works it will be awsome.
Thx

I have posted a guid on how to create custom icons, I understand that the thread is long but try searching before posting.

You are amazing. I do appreciate the post. Tried to go thought it . But failed misrable looking for somthing …this thread is very long. lol

1 Like

Ok …alot of tinkering got it to work becuase I wanted to use hacs: Hass Hue Icons.
Some SVG editing on Photoshop to get top parts of lights svg code. Copied his animation settings per icon and boom it works. Animation + Color + Custom Icons . your help was invaluble. Thank you again

1 2

1 Like

nice work looks amazing, you should share the code if you are finished so others can benefit

Yeah need to make a step by step will do. Maybe somone else can show me quicker ways once I do becuase …I know I took the long way :slight_smile:

Hello everyone, I have been following the tutorial step by step, and I have always been unable to display the cover of plex, and other entities cannot display it on plex’s card when playing videos. I hope that some of the code can be shared by the big shots so that I can refer to and modify it. Thank you, here are some of my code, and I don’t know which yaml I still need to configure.

configuration.yaml

sensor:
- platform: plex_recently_added
  token: MaHb4Vrb3nttW-kfqAY_
  host: 192.168.50.254
  port: 32400

ui-lovelace.yaml

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

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

          - type: custom:swipe-card
            parameters:
              speed: 550
              spaceBetween: 40
              threshold: 5
            cards:

              - type: horizontal-stack
                cards:

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state_not: Plex Movies (Offline)

                      - entity: select.conditional_media
                        state_not: jellyfin

                      - entity: select.conditional_media
                        state_not: emby

                      - entity: select.conditional_media
                        state_not: google
                    card:
                      type: custom:button-card
                      entity: sensor.plex_recently_added
                      name: Plex Movies
                      tap_action:
                        action: none
                      template:
                        - conditional_media
                        - icon_plex
                        

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: jellyfin
                    card:
                      type: custom:button-card
                      entity: media_player.plex_plex_web_chrome_osx
                      name: Plex Movies (Offline)
                      template:
                        - conditional_media
                        - icon_jellyfin

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: jellyfin
                    card:
                      type: custom:button-card
                      entity: media_player.chrome
                      triggers_update: sensor.youtube_watching
                      template:
                        - conditional_media
                        - icon_plex

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: emby
                    card:
                      type: custom:button-card
                      entity: media_player.emby_chrome_macos_2
                      template:
                        - conditional_media
                        - icon_emby

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: google
                    card:
                      type: custom:button-card
                      entity: media_player.chromecast
                      template:
                        - conditional_media
                        - icon_google

              - type: grid
                columns: 2
                cards:

                  - type: custom:button-card
                    entity: media_player.plex_plex_web_chrome_osx_2
                    triggers_update: sensor.youtube_watching
                    name: plex
                    template:
                      - media
                      - icon_plex2

                  - type: custom:button-card
                    entity: media_player.chromecast
                    triggers_update: sensor.youtube_watching
                    name: google
                    template:
                      - media
                      - icon_google

                  - type: custom:button-card
                    entity: media_player.emby_chrome_macos_2
                    name: emby
                    template:
                      - media
                      - icon_emby

                  - type: custom:button-card
                    entity: media_player.chrome
                    name: jellyfin
                    template:
                      - media
                      - icon_jellyfin


sensor.yaml

template:
  select:
    - name: conditional_media
      state: >
        {% set recently_added = 'Plex Movies' %}
        {% set recently_added_backup = 'Plex Movies (Offline)' %}
        {% set paused_timeout_minutes = 15 %}
        {% set media_players = [
          states.media_player.chrome,
          states.media_player.plex_plex_web_chrome_osx,
          states.media_player.emby_chrome_macos_2,
          states.media_player.chromecast ] %}
        
        {% macro media(state) %}
        {% set state = media_players | selectattr('state','eq',state) | list %}
        {% set last_changed = recently_added if state | length == 0 else state | map(attribute='last_changed') | list | max %}
          {{ state | selectattr('last_changed','eq', last_changed) | map(attribute='name') | list | join }}
        {% endmacro %}

        {% set recently_added = recently_added_backup if is_state('media_player.plex_plex_web_chrome_osx','Active') else recently_added %}
        
        {% set playing = media_players | selectattr('state','eq','playing') | list %}
        {% set timeout_playing = False if playing | length == 0 else
          (as_timestamp(now()) - as_timestamp(playing | map(attribute='last_changed') | list | max)) < paused_timeout_minutes * 60 %}
        
        {% set paused = media_players | selectattr('state','eq','paused') | list %}
        {% set timeout_paused = False if paused | length == 0 else
          (as_timestamp(now()) - as_timestamp(paused | map(attribute='last_changed') | list | max)) < paused_timeout_minutes * 60 %}
        
        {% if playing %}
          {{ media('playing') if timeout_playing else media('paused') if timeout_paused else media('playing') }}
        {% elif paused %}
          {{ media('paused') if timeout_paused else recently_added }}
        {% else %}
          {{ recently_added }}
        {% endif %}
      options: >
        {% set recently_added = ['Plex Movies'] %}
        {% set recently_added_backup = ['Plex Movies (Offline)'] %}
        {% set media_players = [
          states.media_player.chrome,
          states.media_player.plex_plex_web_chrome_osx,
          states.media_player.emby_chrome_macos_2,
          states.media_player.chromecast ] %}
        {{ recently_added + recently_added_backup + media_players | map(attribute='name') | list }}
      select_option:
        service: select.select_option
        target:
          entity_id: select.conditional_media
        data:
          option: >
            {{ option }}


  sensor:
  
    # SENSOR - PLEX RECENTLY ADDED (BACKUP)
    - unique_id: recently_added_backup
      name: 'Plex Movies (Offline)'
      state: >
        {% if not is_state('sensor.recently_added_movies', 'Online') %}
          Active
        {% else %}
          Passive
        {# Waiting for 'Plex Movies' to fail #}
        {% endif %}
      attributes:
        data: >
          {% if this.state not in ['unavailable','undefined','unknown','none','null','0'] %}
            {% set data = states('input_text.backup_recently_added_movies') %}
            {% set return = namespace(state=[]) %}
            {% set items = data.split("|") %}
            {% for item in items %}
              {% set object = item.split(":") %}
              {% set return.state = return.state + [{object[0]:object[1]}] %}
            {% endfor %}
            {{ return.state }}
          {% endif %}
        title: >
          {% if this.state not in ['unavailable','undefined','unknown','none','null','0'] %}
            {% set data = this.attributes.data %}
            {% set year = data[0].aired.split('-')[0] %}
            {% if data | count == 4 %}
              {% set title = data[1].title + ' (' + year + ')' %}
            {% else %}
              {% set title = data[1].title + ' · ' + data[2].number %}
            {% endif %}
            {{ title }}
          {% endif %}
        poster: >
          {% if this.state not in ['unavailable','undefined','unknown','none','null','0'] %}
            {% set data = this.attributes.data %}
            {% if data | count == 4 %}
              {% set poster = data[3].poster %}
            {% else %}
              {% set poster = data[4].poster %}
            {% endif %}
            {{ poster }}
          {% endif %}
        fanart: >
          {% if this.state not in ['unavailable','undefined','unknown','none','null','0'] %}
            {% set data = this.attributes.data %}
            {% if data | count == 4 %}
              {% set fanart = data[2].fanart %}
            {% else %}
              {% set fanart = data[3].fanart %}
            {% endif %}
            {{ fanart }}
          {% endif %}

automations.yaml

- id: '1675415708652'
  alias: System - Plex Recently Added
  description: Sensor attribute backup
  trigger:
  - platform: state
    entity_id:
    - sensor.plex_recently_added
    to: Online
  condition:
  - condition: template
    value_template: '{{ trigger.to_state.state not in [trigger.from_state.state, ''cannot
      be reached'', ''unavailable'', ''undefined'',''unknown'',''none'',''null'']
      }}'
  action:
  - service: input_text.set_value
    data:
      value: "{% if not states('sensor.plex_recently_added') in ['unavailable','undefined','unknown','none','null','0']
        %}\n  {% set state = namespace(return='') %}\n  {% set data = state_attr('sensor.plex_recently_added','data')
        %}\n  {%- for value in data %}\n    {%- if not loop.first and value is defined
        and state.return == '' %}\n      {%- if not value.number is defined %}\n        {%
        set state.return = \n          \"aired:\" + value.aired + \"|\" +\n          \"title:\"
        + value.title  + \"|\" +\n          \"fanart:\" + value.fanart + \"|\" +\n
        \         \"poster:\" + value.poster\n        %}\n      {%- else %}\n        {%
        set state.return = \n          \"aired:\" + value.aired + \"|\" +\n          \"title:\"
        + value.title  + \"|\" +\n          \"number:\" + value.number  + \"|\" +\n
        \         \"fanart:\" + value.fanart + \"|\" +\n          \"poster:\" + value.poster\n
        \       %}\n      {%- endif %}\n    {%- endif %}\n  {%- endfor %}\n  {{ state.return
        }}\n{% endif %}"
    target:
      entity_id: input_text.backup_plex_recently_added
  mode: single

“Currently, I have only modified the code in these three yaml files, but it has not worked. I have been struggling for this for several days. Please help me, thank you.”

Hi there, @zs2766.

I can start by pointing out some things:

The conditional_media select sensor looks incorrect:

{% set recently_added = recently_added_backup if is_state('media_player.plex_plex_web_chrome_osx','Active') else recently_added %}

This should check the state of a different sensor, like this:

{% set recently_added = recently_added_backup if is_state('sensor.recently_added_offline','Active') else recently_added %}

There are some other things missing in your post, I think. Please read this.

1 Like

Looks nice! Can u share the code? I and others could use it for hue lights.

Thank you very much for your answer. Currently, I have only modified these few items, and I don’t know how to modify the rest. I can’t find the relevant tutorials. Can you help me?

Well, I just pointed you to the tutorial I made for this.
Have you read it? (A different take on designing a Lovelace UI - #4536 by Laffer)

What you are trying to achieve is a modification of what Mattias made.
This includes a backup solution that I made for when the “Plex Recently Added” sensor fails.

Thank you. I will follow your tutorial and try it later. If it is still not available, I can send the file to you. Can you help me take a look at it? “If I need those files to send you, I hope you can list the names. Thank you.”

“I followed your tutorial and did it again, but it didn’t take effect. It’s still the same problem as before. Please help me, thank you.”

Send me screenshots and code from all the components mentioned in the tutorial and we’ll see if we can figure it out.

2 Likes

Okay, thank you very much. Here are some of my configuration files. If you need a complete config file, I can send it to you