A different take on designing a Lovelace UI

I think you are after something like this, climate.climate_office is just an input boolean can can work with any entity you will just need to change if statement’s, when that is toggled the icon animates but it will not animate on the normal state change .

I dont think this is the best approach but it is possible.

entity: light.test_light
name: Test
type: custom:button-card
styles:
  grid:
    - grid-template-areas: >-
        "n n" "mot window" "icon icon"
triggers_update:
    - climate.climate_office
custom_fields:
    icon: >
        [[[ const state = states[this._config.triggers_update].state === 'on' ? 'animate' : null;  const style
              = '<style>@keyframes animate_on{from{transform: scaleY(0);}to{transform:
              scaleY(1);}}.animate_on{animation: animate_on 1s; transform-origin:
              -100% 46%; animation-fill-mode: forwards;}@keyframes
              animate_off{from{transform: scaleY(1);}to{transform:
              scaleY(0);}}.animate_off{animation: animate_off 1s; transform-origin:
              -100% 46%; animation-fill-mode: forwards;}</style>'; const path = '<path
              d="M46 9.2v27.5H4.1V9.2H46m2.4-2.4H1.6v32.3h46.7c.1 0
              .1-32.3.1-32.3zM11.9 43.2h26.3c.6 0 1.1-.4
              1.1-1v-.3c0-.6-.4-1.1-1-1.1H11.9c-.6 0-1.1.4-1.1 1v.3a1.11 1.11 0 0 0
              1.1 1.1z"/>'; const gradient = '<linearGradient id="A"
              gradientUnits="userSpaceOnUse" x1="5.401" y1="34.714" x2="43.817"
              y2="11.74"><stop offset="0" stop-color="#64acb7"/><stop offset="1"
              stop-color="#7fdbe9"/></linearGradient>'; if (states[this._config.triggers_update].state === 'off'){
              return `<svg fill="var(--button-card-light-color-no-temperature)"
              viewBox="0 0 50 50"> ${style} ${gradient} <path class="animate_off"
              d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path} </svg>`; } if
              (states[this._config.triggers_update].state === 'on'){ return `<svg  fill="#9da0a2" viewBox="0 0 50
              50"> ${style} ${gradient} <path d="M2.9,8h44.3v29.9H2.9V8z"
              fill="#20262890"/><path class="animate_on" d="M2.9,8h44.3v29.9H2.9V8z"
              fill="url(#A)"/> ${path} </svg>`; } if (states[this._config.triggers_update].state === 'on'){ return
              `<svg viewBox="0 0 50 50"> ${gradient} <path d="M2.9,8h44.3v29.9H2.9V8z"
              fill="url(#A)"/> ${path} </svg>`; } else if (states[this._config.triggers_update].state === 'off') {
              return `<svg viewBox="0 0 50 50"> ${path} </svg>`; } ]]]

1 Like

wow it’s working. Thank you soooooooo much! and I think this is the best approach because is a small chance and adition in code…:grinning::grinning::grinning::grinning::ok_hand::ok_hand::ok_hand:

My plex recently added suddenly stopped.
It still shows something when i watch a movie/show, but when it goes back to the recently added, it’s just a grey image and saying “Recently added unknown”.

I also encountered it, but after restarting the system, it returned to normal again. I don’t know what caused it

In addition, my air conditioning card has not yet been completed. I have been reporting errors using the climate template, indicating that the template does not exist, but in my button_ card_ There is a climate.yaml template file in the templates folder. If you have any information, please let me know. Thank you very much

give this a look

I can not understand what you are trying to say. if you would like help can you provide the following;

  1. the broken yaml
  2. screenshots of the entities
  3. the error message
  4. screenshots of your File Structure
1 Like

“I encountered an error while trying to add a card to my air conditioner. I used the climate template to add the card, but the card prompted the button that the card template was missing. I have confirmed that the template exists. On the button,”_ card_ There is a climate.yaml template file in the templates folder, button_ card_ The templates.yaml file also contains the card information for climate, but I don’t know why it indicates that the card template is missing. The following is my configuration code. Please help me take a look, thank you

button_card_templates.yaml

  base:
    aspect_ratio: 1/1
    show_state: true
    show_icon: false
    state:
      - value: 'on'
        styles:
          card: [background-color: 'rgba(255, 255, 255, 0.8)']
          name: [color: 'rgba(0, 0, 0, 0.6)']
          state: [color: 'rgba(0, 0, 0, 0.6)']
    tap_action:
      ui_sound: |
        [[[ if (entity.state === 'off' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/on.m4a', media_content_type: 'music'}); }
        else if (entity.state === 'on' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/off.m4a', media_content_type: 'music'}); } ]]]
      action: toggle
      haptic: light
    styles:
      name:
        [top: 57.7%, left: 11%, line-height: 2vw, position: absolute]
      state:
        [top: 74%, left: 11%, line-height: 2vw, position: absolute]
      card:
        [font-family: Sf Display, letter-spacing: 0.05vw, font-weight: 400, color: 'rgba(255, 255, 255, 0.3)', font-size: 1.34vw, 
        background-color: 'rgba(115, 115, 115, 0.2)', border-radius: 0.8vw, box-shadow: none, transition: none]
      custom_fields:
        circle:
          [top: 8.5%, left: 56.2%, width: 3.5vw, position: absolute, letter-spacing: 0.03vw]

  loader:
    custom_fields:
      loader: >
        [[[ if (states[entity.entity_id.replace(entity.entity_id.split('.')[0], 'input_boolean')].state === 'on') { 
        return '<img src="/local/loader.svg" width="100%">'; } ]]]
    styles:
      custom_fields:
        loader:
          [filter: "[[[ return entity.state === 'off' ? 'invert(1)' : 'none'; ]]]", 
           top: 3%, left: 60%, width: 3.7vw, position: absolute, opacity: 0.6]

  person:
    template: ['base']
    show_entity_picture: true
    state_display: >
      [[[ return entity.state === 'home' ? 'Ja' : 'Nej'; ]]]
    state:
      - value: 'home'
        styles:
          card: [background-color: 'rgba(255, 255, 255, 0.8)']
          name: [color: 'rgba(0, 0, 0, 0.6)']
          state: [color: 'rgba(0, 0, 0, 0.6)']
    styles:
      entity_picture: 
        [clip-path: circle(50% at center), top: 7.5%, left: 11.2%, width: 3vw, position: absolute]
    custom_fields:
      circle: >
        [[[ function time(c) {
        var s = (c / 1000); var m = (c / (1000 * 60)); var h = (c / (1000 * 60 * 60)); var d = (c / (1000 * 60 * 60 * 24));
        if (s < 60) { return parseInt(s) + 's'; } else if (m < 60) { return parseInt(m) + 'm'; }
        else if (h < 24) { return parseInt(h) + 'h'; } else { return parseInt(d) + 'd'; }
        }
        const last_changed = time(Date.now() - Date.parse(states[entity.entity_id].last_changed));
        const stroke_color = entity.state === 'home' ? '#b2b2b2' : '#313638'; 
        const fill_color = entity.state === 'home' ? 'none' : '#FFFFFF08';
        return `<svg viewBox="0 0 50 50"><circle cx="25" cy="25" r="20.5" stroke="${stroke_color}" stroke-width="1.5" fill="${fill_color}" />
        <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle">${last_changed}</text></svg>`; ]]]

  light:
    template: ['base']
    custom_fields:
      circle: >
        [[[ if (entity.state === 'on' && entity.attributes.brightness) {
        const brightness = Math.round(entity.attributes.brightness / 2.54);
        const radius = 20.5; const circumference = radius * 2 * Math.PI; 
        return `<svg viewBox="0 0 50 50"><circle cx="25" cy="25" r="${radius}" stroke="#b2b2b2" stroke-width="1.5" fill="none" style="
        transform: rotate(-90deg); transform-origin: 50% 50%; stroke-dasharray: ${circumference}; stroke-dashoffset: ${circumference - brightness / 100 * circumference};" />
        <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle">${brightness}<tspan font-size="10">%</tspan></text></svg>`; } ]]]
    hold_action:
      action: call-service
      service: browser_mod.popup
      service_data:
        title: '[[[ return entity.attributes.friendly_name ]]]'
        deviceID: this
        card:
          type: entities
          entities:
            - type: custom:light-popup-card
              entity: '[[[ return entity.entity_id ]]]'
              icon: none
              fullscreen: false
              brightnessWidth: 130px
              brightnessHeight: 360px
              borderRadius: 1.7em
              sliderColor: '#c7c7c7'
              sliderTrackColor: rgba(25, 25, 25, 0.9)
              actionSize: 4.5em
              actionsInARow: 2
              actions:
                - service: light.turn_on
                  service_data:
                    entity_id: '[[[ return entity.entity_id ]]]'
                    color_temp: 153
                  color: "#d8d9e1"
                - service: light.turn_on
                  service_data:
                    entity_id: '[[[ return entity.entity_id ]]]'
                    color_temp: 326
                  color: "#d5b08d"
                - service: light.turn_on
                  service_data:
                    entity_id: '[[[ return entity.entity_id ]]]'
                    color_temp: 500
                  color: "#ce944b"
                - service: browser_mod.popup
                  service_data:
                    title: '[[[ return entity.attributes.friendly_name ]]]'
                    deviceID: this
                    card:
                      type: entities
                      show_header_toggle: false
                      entities:
                        - entity: '[[[ return entity.entity_id ]]]'
                          secondary_info: last-changed
                        - type: custom:light-entity-card
                          entity: '[[[ return entity.entity_id ]]]'
                          brightness: false
                          color_temp: true
                          full_width_sliders: true
                          hide_header: true
                          show_slider_percent: true
                          smooth_color_wheel: true
                          consolidate_entities: true

  shared_media:
    tap_action:
      action: >
        [[[ if (entity.state === 'off' || entity.state === 'idle' || entity.state === 'standby') {
        return 'none'; } else { return 'call-service'; } ]]]
      service: media_player.media_play_pause
      service_data:
        entity_id: '[[[ return entity.entity_id ]]]'
    double_tap_action:
      action: call-service
      service: >
        [[[ if (entity.state === 'off' || entity.state === 'idle' || entity.state === 'standby') {
        return 'media_player.turn_on'; } else { return 'media_player.turn_off'; } ]]]
      service_data:
        entity_id: '[[[ return entity.entity_id ]]]'
    styles:
      card:
        [color: "[[[ if (entity.state === 'off' || entity.state === 'idle' || entity.state === 'standby' || 
        entity.state === 'unknown' || entity.state === 'unavailable') { return 'rgba(255, 255, 255, 0.3)'; }
        if ((entity.state != 'off' && entity.state != 'idle' && entity.state != 'standby') && (entity.attributes.entity_picture == null)) {
        return 'rgba(0, 0, 0, 0.6)'; } else { return '#efefef'; } ]]]", 
        text-shadow: "[[[ if (entity.attributes.entity_picture == null) return 'none'; 
        else return '1px 1px 5px rgba(18, 22, 23, 0.9)' ; ]]]"]

  media:
    template: ['base', 'shared_media']
    styles:
      custom_fields:
        icon:
          [opacity: "[[[ return entity.attributes.entity_picture == null ? 1 : 0; ]]]", 
          top: 11.5%, left: 11.5%, width: 2.9vw, position: absolute, fill: '#9da0a2']
      card:
        [background-color: none, background-size: cover,
        background-image: 
        "[[[ if (entity.state === 'off' || entity.state === 'idle' || entity.state === 'standby' || 
        entity.state === 'unknown' || entity.state === 'unavailable') {
        return 'linear-gradient(0deg, rgba(115, 115, 115, 0.2) 0%, rgba(115, 115, 115, 0.2) 100%)'; }
        if ((entity.state != 'off' && entity.state != 'idle' && entity.state != 'standby') && (entity.attributes.entity_picture == null)) {
        return 'linear-gradient(0deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.8) 100%)'; }
        else { return 'linear-gradient(0deg, rgba(0,0,0,.8) 0%, rgba(0,0,0,0) 100%), url(' + entity.attributes.entity_picture + ')'; } ]]]"]

  conditional_media:
    template: ['base', 'shared_media']
    state_display: >
      [[[ if (entity.attributes.media_title === 'Nothing playing' || entity.attributes.media_title === 'No title' && entity.state === 'paused' ) { return 'Inget spelas'; }
      if (entity.attributes.media_title === 'No title' && entity.state === 'playing') { return 'Ingen titel'; }
      else { return entity.attributes.media_title; } ]]]
    custom_fields:
      media_image: >
        <svg viewBox="0 0 50 50" />
      blur: >
        [[[ if (entity.attributes.entity_picture != null) {
        return '<svg viewBox="0 0 50 50" />'; } ]]]
      overlay: >
        [[[ if (entity.state != 'off' && entity.state != 'idle' && entity.state != 'standby' && entity.state != 'unavailable') {
        return '<svg viewBox="0 0 50 50" />'; } ]]]
      play_pause: >
        [[[ const style = `<style>.scale-up { animation: scale-up 0.3s; cubic-bezier(.05,.5,.3,1) 1; transform-origin: center center; }
        @keyframes scale-up { 0% { opacity: 0; transform: scale(0); } 100% { opacity: 1; transform: scale(1); } }</style>`;
        if (entity.state === 'playing') { return `<svg viewBox="0 0 166 166">${style}<path class="scale-up" d="M0 0h59.9v166H0zm106.1 0H166v166h-59.9z"/></svg>`; }
        if (entity.state === 'paused') { return `<svg viewBox="0 0 166 166">${style}<path class="scale-up" d="M0 0l166 83L0 166z"/></svg>`; } ]]]
    styles:
      custom_fields:
        media_image:
          [background-image:
          "[[[ return entity.attributes.entity_picture == null ? 'linear-gradient(0deg, rgba(115, 115, 115, 0.2) 0%, rgba(115, 115, 115, 0.2) 100%)' 
          : 'linear-gradient(0deg, rgba(13,17,19,0.9) 0%, rgba(13,17,19,0) 50%), url(' + entity.attributes.entity_picture + ')'; ]]]", 
          background-size: cover, top: 0%, left: 0%, width: 100%, position: absolute]
        blur:
          [background-image:
          "[[[ return entity.attributes.entity_picture == null ? 'none' : 'url(' + entity.attributes.entity_picture + ')'; ]]]", 
          background-size: cover, top: 0%, left: 0%, width: 100%, filter: blur(4px), clip-path: inset(16vw 0 0 0), position: absolute]
        overlay:
          [background:
          "[[[ return entity.attributes.entity_picture == null ? 'rgba(255, 255, 255, 0.8)' : 'rgba(0, 0, 0, 0.4)'; ]]]", 
          background-size: cover, z-index: 0, top: 16vw, left: 0%, width: 100%, opacity: 1, position: absolute]
        play_pause:
          [filter: 
          "[[[ return entity.attributes.entity_picture == null ? 'none' : 'drop-shadow(0 0 1.3vw rgba(0,0,0,0.7))'; ]]]", 
          fill: '#dedede', top: 0, right: 0, bottom: 0, left: 0, margin: auto, width: 21%, height: 21%, position: absolute]
        icon:
          [fill:
          "[[[ if (entity.state === 'off' || entity.state === 'idle' || entity.state === 'standby' || 
          entity.state === 'unknown' || entity.state === 'unavailable') return '#9da0a2'; 
          else return 'rgba(255, 255, 255, 0.8)'; ]]]", 
          top: 5.35%, left: 5.35%, width: 2.95vw, position: absolute]
      name:
        [top: 79.8%, left: 5.3%, position: absolute, line-height: 2vw, z-index: 10]
      state:
        [top: 87.5%, left: 5.3%, position: absolute, line-height: 2vw, z-index: 10, 
        white-space: nowrap, overflow: hidden, text-overflow: ellipsis, max-width: 90%]

  icon_action:
    color: '#9da0a2'
    styles:
      card:
        [background: '#FFFFFF10', border-radius: 0.6em, box-shadow: none, 
        transition: none, width: 4em, height: 3.7em]

  name_action:
    styles:
      name:
        [display: flex, align-items: center, justify-content: center, margin-top: 0.5px]
      card:
        [background: '#FFFFFF10', color: '#9da0a2', border-radius: 0.6em, box-shadow: none, 
        transition: none, width: 100%, padding: 1em 1.4em 1em 1.2em, font-size: 1.06em, 
        font-weight: 500, letter-spacing: 0.015em]
    style: '#name > ha-icon {width: 1.4em; margin-right: 0.3em; }'
    




  #################################################
  #                                               #
  #                    CLIMATE                    #
  #                                               #
  #################################################

  climate_base:
    show_icon: false
    styles:
      name:
        - padding: 12px 13px
        - font-size: 0.8em
        - font-weight: 600
      card:
        - border-radius: 10px

  climate_fan_mode:
    show_icon: false
    variables:
      fan_mode: false
    tap_action:
      action: call-service
      service: climate.set_fan_mode
      service_data:
        entity_id: >
          [[[
            return !entity || entity.entity_id;
          ]]]
        fan_mode: >
          [[[
            return variables.fan_mode;
          ]]]
    styles:
      card:
        - background-color: >
            [[[
              return !entity || entity.attributes.fan_mode === variables.fan_mode ? "rgba(158, 158, 158, 0.2)" : "rgba(189, 189, 189, 0.05)";
            ]]]
    template:
      - climate_base

  climate_swing_mode:
    tap_action:
      action: call-service
      service: climate.set_swing_mode
      service_data:
        entity_id: >
          [[[
            return !entity || entity.entity_id;
          ]]]
        swing_mode: >
          [[[
            return !entity || entity.attributes.swing_mode === 'off' ? 'on' : 'off';
          ]]]
    styles:
      card:
        - background-color: >
            [[[
              return !entity || entity.attributes.swing_mode === "on" ? "rgba(158, 158, 158, 0.2)" : "rgba(189, 189, 189, 0.05)";
            ]]]
    template:
      - climate_base

  climate:
    template:
      - circle
    state_display: >
      [[[
        if (variables.state == 'heat_cool') {
          return 'Auto';
        }
      ]]]
    variables:
      circle_input: >
        [[[
          if (states['sensor.temperature_average_upstairs'].state) {
            return (Math.round(states['sensor.temperature_average_upstairs'].state));
          }
        ]]]
      circle_input_unit: '°C'
    styles:
      custom_fields:
        circle:
          - display: initial
          - width: 90%
          - letter-spacing: 0.03vw
          - margin: -6% -6% 0 0
          - justify-self: end
          - opacity: 1


ui-lovelace.yaml

                  - type: custom:button-card
                    entity: climate.acn05_cloud_419957
                    name: ac
                    template:
                      - base
                      - icon_climate
                      - climate

climate.yaml

climate_base:
  show_icon: false
  styles:
    name:
      - padding: 12px 13px
      - font-size: 0.8em
      - font-weight: 600
    card:
      - border-radius: 10px

climate_fan_mode:
  variables:
    fan_mode: false
  tap_action:
    action: call-service
    service: climate.set_fan_mode
    service_data:
      entity_id: >
        [[[ return !entity || entity.entity_id; ]]]
      fan_mode: >
        [[[ return variables.fan_mode; ]]]
  styles:
    card:
      - background-color: >
          [[[
            return !entity || entity.attributes.fan_mode === variables.fan_mode
                ? "rgba(158, 158, 158, 0.2)"
                : "rgba(189, 189, 189, 0.05)";
          ]]]
  template:
    - climate_base

climate_swing_mode:
  tap_action:
    action: call-service
    service: climate.set_swing_mode
    service_data:
      entity_id: >
        [[[ return !entity || entity.entity_id; ]]]
      swing_mode: >
        [[[
          return !entity || entity.attributes.swing_mode === 'off'
              ? 'on'
              : 'off';
        ]]]
  styles:
    card:
      - background-color: >
          [[[
            return !entity || entity.attributes.swing_mode === "on"
                ? "rgba(158, 158, 158, 0.2)"
                : "rgba(189, 189, 189, 0.05)";
          ]]]
  template:
    - climate_base

in climate.yaml
you don’t have a template named climate
there was a template named climate but that looks to been removed see the climate section in the main post link

try using climate_base or climate_fan_mode or climate_swing_mode

I have not updated so I can give you what I have but it might not work

#################################################
#                                               #
#                    CLIMATE                    #
#                                               #
#################################################

climate:
  template:
    - base
    - circle
  variables:
    state: >
      [[[
        if (entity) {
          return entity.attributes.hvac_action 
        }
      ]]]
    state_on: >
      [[[ 
        return ['cooling','heating'].indexOf(!entity || entity.attributes.hvac_action) !== -1; 
      ]]]
    circle_input: >
      [[[
        if (entity) {
            return entity.state === 'off'
                ? Math.round(entity.attributes.current_temperature).toString()
                : entity.attributes.hvac_action === "cooling"
                  ? Math.round(entity.attributes.target_temp_low).toString()
                  : Math.round(entity.attributes.target_temp_high).toString();
        }
      ]]]
    circle_input_unit: '°C'
  state_display: |
    [[[
        return variables.state.charAt(0).toUpperCase() + variables.state.substr(1).toLowerCase();
    ]]]

“I am using the author’s template directly, and I don’t know why it was deleted from his template. Let me try S”

I copied your code to climate.yaml, but it still reported an error and lost the template

Can I share all your code? So that I can troubleshoot the problem

yes @Mattias_Persson removed the template, I assume the reason it was removed is that he is no longer using it.

As I said I did not my template would work, “an error” is not helpful.

No you may not have my code, I do not share my full config and I do not plan to any time soon.

@Laffer has made his config available based off of this one, if you think that well help.

if you have errors provide the following details and I or someone else might help;

  1. the broken yaml
  2. screenshots of the entities
  3. the error message

@zs2766 @masoncrawford1994

Thanks for your replies.
I figured out why it stopped working, apparently the plex token had changed. So in the end, all I had to do was replace the token in secrets.yaml.

Hello, in the past two days, I have been continuously learning and solving the problem of Plex card not being able to automatically switch between playing media cards. However, it has encountered a new problem. When I played a video using Chromecast, it displayed two cards on the Plex card. Recently, Plex added blank cards with Chromecast. I believe that Chromecast was unable to obtain the media background image, which caused both cards to appear at the same time because I was playing EMBY, It displays the background image of EMBY normally.


Another issue with plex cards is that after other media stops playing, the recently added card by plex will retain the media information and background image that was just playing for 15 minutes. After 15 minutes, there will be no activity and automatically switch back to the recently added image by plex. However, when I stop playing, the recently added card by plex does not display a thumbnail, it only displays information about the media, such as the movie name, I thought I needed to manually run the automatic steps, but unfortunately, after I finished running the automatic script, the status information of “sensor. recently_added_offline” did not display any content in the attributes. When I didn’t run the automatic script, its data could display the information of the currently playing video and the name of the background image.

In addition, I have also resolved the issues with the Climate card and the pop-up card. Please help me improve the plex card. thank you

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: Recently Added (Offline)

                      - entity: select.conditional_media
                        state_not: plex

                      - entity: select.conditional_media
                        state_not: emby

                      - entity: select.conditional_media
                        state_not: jellyfin
                    card:
                      type: custom:button-card
                      entity: sensor.plex_recently_added_movies
                      name: Recently Added
                      tap_action:
                        action: none
                      template:
                        - conditional_media
                        - icon_plex
                        

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: Recently Added (Offline)
                    card:
                      type: custom:button-card
                      entity: sensor.recently_added_offline
                      name: Recently Added (Offline)
                      template:
                        - conditional_media
                        - icon_plex

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: plex
                    card:
                      type: custom:button-card
                      entity: media_player.plex_plex_web_chrome_osx
                      name: plex
                      template:
                        - conditional_media
                        - icon_plex

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: jellyfin
                    card:
                      type: custom:button-card
                      entity: media_player.chrome
                      template:
                        - conditional_media
                        - icon_jellyfin

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

                  - type: conditional
                    conditions:
                      - entity: select.conditional_media
                        state: chromecast
                    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
                    name: plex
                    template:
                      - media
                      - icon_plex2

                  - type: custom:button-card
                    entity: media_player.chromecast
                    name: chromecast
                    template:
                      - media
                      - icon_google

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

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

template.yaml

    # SENSOR - PLEX RECENTLY ADDED (BACKUP)
    - unique_id: recently_added_backup
      name: 'Recently Added (Offline)'
      state: >
        {% if not is_state('sensor.plex_recently_added_movies', 'Online') %}
          Active
        {% else %}
          Passive
        {# Waiting for 'Recently Added' to fail #}
        {% endif %}
      attributes:
        data: >
          {% if this.state not in ['unavailable','undefined','unknown','none','null','0'] %}
            {% set data = states('input_text.backup_plex_recently_added') %}
            {% 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 %}

 
  select:
    - name: conditional_media
      state: >
        {% set recently_added = 'Recently Added' %}
        {% set recently_added_backup = 'Recently Added (Offline)' %}
        {% set paused_timeout_minutes = 15 %}
        {% set media_players = [
          states.media_player.plex_plex_web_chrome_osx,
          states.media_player.chrome,
          states.media_player.emby_chrome_macos_4,
          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('sensor.recently_added_offline','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 = ['Recently Added'] %}
        {% set recently_added_backup = ['Recently Added (Offline)'] %}
        {% set media_players = [
          states.media_player.plex_plex_web_chrome_osx,
          states.media_player.chrome,
          states.media_player.emby_chrome_macos_4,
          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 }}

automations.yaml

- id: '1675415708652'
  alias: System - Plex Recently Added
  description: Sensor attribute backup
  trigger:
  - platform: state
    entity_id:
    - sensor.plex_recently_added_movies
    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_movies') in ['unavailable','undefined','unknown','none','null','0']
        %}\n  {% set state = namespace(return='') %}\n  {% set data = state_attr('sensor.plex_recently_added_movies','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


4 Likes

Could you please share the code that added the weather forecast?

Of course, I asked ChatGPT to help me write this code. You only need to modify the physical and stylistic reminders of the weather. I come from China, please change the Chinese to English

        weather: >
         {% set entity = 'weather.forecast_wo_de_jia' %}
         {% if not is_state(entity, 'unknown') %}
           {% set temp = state_attr(entity, 'temperature') | round %}
           {% set precip = state_attr(entity, 'forecast')[0]['precipitation'] | round %}
           {% set is_rain = precip > 45 and temp > 1 %}
           {% set is_snow = precip > 45 and temp <= -1 %}
           {% set rain_emoji = '\U0001F327' if is_rain else '' %}
           {% set snow_emoji = '\u2744\uFE0F' if is_snow else '' %}
           {% set coat_emoji = '\U0001F9E5' if is_snow else '' %}
           {{'\U0001F31F'}}外出提醒:
             现在室外温度为 {{ temp }}°c,{{ rain_emoji }}{{ snow_emoji }}当前{{ '降雪' if is_snow else '降雨' }}概率为{{ precip }}%,
             {% if temp >= 27 and temp <= 32 %}
               {% if precip <= 45 %}
                 {{'\U0001F630'}}今天天气比较闷热{{rain_emoji}}
               {% else %}
                 {{'\U0001F630'}}今天天气比较闷热,可能会下雨,出门{{'\U0001F6B6'}}记得带雨伞{{'\u2614\uFE0F'}}
               {% endif %}
             {% elif temp > 33 %}
               {% if precip <= 45 %}
                 {{'\U0001F525'}}外面太过炎热,请打开空调待在室内,外出请带遮阳伞{{'\U0001F302'}}
               {% else %}
                 {{'\U0001F525'}}外面太过炎热,可能会下雨,请打开空调待在室内{{'\U0001F3E0'}}
               {% endif %}
             {% elif temp >= 12 and temp <= 27 %}
               {% if precip <= 45 %}
                 今天天气不错,气温舒适{{'\U0001F60E'}},适合外出走走{{'\U0001F6B6'}}
               {% else %}
                 {{'\U0001F60E'}}今天气温舒适,可能会下雨,出门{{'\U0001F6B6'}}请带雨伞{{'\u2614\uFE0F'}}
               {% endif %}
             {% elif temp >= 3 and temp < 12 %}
               {% if precip <= 45 %}
                 {{'\U0001F914'}}今日气温偏低,适当添衣外出{{ '\U0001F9E5' }}
               {% else %}
                 {{'\U0001F976'}}今日气温偏低,有可能会下雨,外出请带雨伞{{'\u2614\uFE0F'}}
               {% endif %}
             {% elif temp >= -15 and temp < 3 %}
               {% if precip <= 45 %}
                 {{'\U0001F976'}}今日外面比较寒冷,请尽量待在家里{{'\U0001F3E0'}}
               {% else %}
                 {{'\U0001F976'}}今日外面非常冷,有可能会下雪,外出请多穿衣服{{ '\U0001F9E5' }}
               {% endif %}
           {% endif %}
         {% else %}
           无法加载天气信息...
         {% endif %}

Thank you.
Great that you were able to use ChatGPT for this. Technology marches ahead of us.

Something is unclear to me.

Is this code of weekly display of weather forecast? Because the code you sent is not true.

You’re welcome, I think there’s an omission in this code, which may be related to the weather entity. When it rains, the “precision” index will become very low. Yesterday, it rained here, and its index was between 1 and 2, which will affect the probability of current rainfall and thus affect the text reminder. I think the “precision” index should be very high when it rains, but I don’t know why the index of the weather entity is so low, Perhaps this index will become very low when it rains? I don’t know, perhaps a judgment should be added to this code. When the “precision” index remains between 0 and 2, a reminder will be given based on the temperature. If the temperature is above 5 degrees Celsius, a probability of rainfall will be given, and if it is below 5 degrees Celsius, a probability of snowfall will be given. Additionally, when the “precision” index is between 0 and 2, a reminder will be given that it is currently raining or snowing

No, this text represents that the temperature is on the high side today. It suggests that the weather is very hot today, so try to stay at home and turn on the air conditioning as much as possible