Person Cards - Show Off Yours

Thanks! I did set it in configuration.yaml, and in a subsequent comment I found code that works for my Lovelace view.

I’ve commented out the sensor for now, though; I’m not finding it to be very responsive to movement or accurate enough for my interests. I also had the tolerance set to 50, and I haven’t experimented with other values for that setting… but I don’t expect that to make much difference.

Hi John,

I’m testing your code on my system, but I get some strange results and I (as a n00b) can’t find where my errror is (or are).

This is what I see in my card:

location hass

The location is correct, it’s my work location, but the card thinks I’m at home (‘Jos is thuis’ means I’m home). The location on the map also correct.

My sensor (sensor_jos_2) and its attributes are okay and contain the correct values.

The code of my card:

type: custom:stack-in-card
mode: vertical
card_mod: null
style: |
  ha-card {
  background-color: rgba(255, 255, 255, .1);
  }
cards:
  - type: custom:stack-in-card
    mode: horizontal
    cards:
      - type: custom:mushroom-person-card
        entity: device_tracker.iphone_x_jos_2
        icon_type: entity-picture
        hide_name: true
        layout: vertical
        secondary_info: state
  - type: custom:mushroom-chips-card
    chips:
      - type: entity
        entity: binary_sensor.shellymotionsensor_60a423935ad4_motion
        content_info: none
      - type: template
        content: '{{ states(''sensor.temperatuur_woonkamer'')| round (0)}}°C'
        tap_action:
          action: none
      - type: template
        content: '{{ states(''climate.toon_thermostaat'')}}'
        tap_action:
          action: none
  - type: custom:mushroom-template-card
    entity: sensor.jos_2
    primary: >
      {% if (state_attr('sensor.jos_2', 'direction_of_travel') == 'stationary')
      and (state_attr('sensor.jos_2','home_zone') == 'zone.home') %} Jos is
      thuis: {% elif (state_attr('sensor.jos_2', 'direction_of_travel') ==
      'stationary')%} Jos is hier: {% else %} Jos is {% endif %}
    secondary: >
      {% if (state_attr('sensor.jos_2','direction_of_travel') == 'stationary')
      %} {{ state_attr('sensor.jos_2','street_number') }} {{
      state_attr('sensor.jos_2','street') }}, {{
      state_attr('sensor.jos_2','city') }}, {{
      state_attr('sensor.jos_2','postal_code') }} {% else %} Onderweg... {%
      endif %}
    icon: >-
      {% if (state_attr('sensor.jos_2','direction_of_travel') == 'stationary')
      and (states('device_tracker.iphone_x_jos_2') == 'home') %}
      mdi:home-account {% elif (state_attr('sensor.jos_2','direction_of_travel')
      == 'stationary') and (states('device_tracker.iphone_x_jos_2') ==
      'not_home') %} mdi:domain {% else %} mdi:car {% endif %}
    icon_color: >-
      {% if (state_attr('sensor.jos_2','direction_of_travel') == 'stationary')
      and (states('device_tracker.iphone_x_jos_2') == 'home') %} green {% elif
      (state_attr('sensor.jos_2','direction_of_travel') == 'stationary') and
      (states('device_tracker.iphone_x_jos_2') == 'not_home') %} blue {% else %}
      cyan {% endif %}
    multiline_secondary: true
  - type: map
    default_zoom: 16
    entities:
      - device_tracker.iphone_x_jos_2
    aspect_ratio: 1.95:1

Hope you (or anyone else) can take a look where my mistake is? Thanks in advance!

2 Likes

Try change in primary: state_attr('sensor.jos_2','home_zone') == 'zone.home') to states('device_tracker.iphone_x_jos_2') == 'home' :slight_smile:

1 Like


I’m experimenting, but I can’t choose, in a large card the left one seems to be better, on small cards the right one …

It now says I’m on the road, underway to…

Will try experimenting with several other settiings the comming days, still find it strange that the sensor sewttings are all good, so the error comes from my formatting of the formulas and formulas are my weak spot.

    primary: >
      {% if (states('device_tracker.iphone_x_jos_2') == 'home') %} Jos is
      thuis: {% elif (state_attr('sensor.jos_2', 'direction_of_travel') ==
      'stationary')%} Jos is hier: {% else %} Jos is {% endif %}
1 Like

what card is that to the right please?
I am looking fir something like that exactly: have a picture with 2 small overlay areas to show some entities… For my Rooms, not person :wink:

if you could, Id appreciate the yaml config for that card a lot.

In capital letters, this is what needs to be changed, either to your sensors, or to some kind of static data, or there are possible options in the same place.

type: custom:button-card
entity: person.PERSON
triggers_update: all
variables:
  battery: |
    [[[
      return states['sensor.BATTERY']?.state;
    ]]]
  charging: |
    [[[
      return states['binary_sensor.CHARGE']?.state == 'on';
    ]]]
  battery_threshold: |
    [[[
      return states['input_number.scale_minimal_battery']?.state; // OR ...
      return 10;
    ]]]
  battery_color: |
    [[[
      if (Number(variables?.battery) < Number(variables?.battery_threshold))
        return "var(--label-badge-red)";
      else if (Number(variables?.battery) < Number(variables?.battery_threshold) + 20)
        return "var(--label-badge-yellow)";
      else
        return "var(--label-badge-green)";
    ]]]
  battery_icon: |
    [[[
      if (variables?.charging) return "mdi:battery-charging";
      else if (Number(variables?.battery) < 10) return "mdi:battery-outline";
      else if (Number(variables?.battery) < 20) return "mdi:battery-10";
      else if (Number(variables?.battery) < 30) return "mdi:battery-20";
      else if (Number(variables?.battery) < 40) return "mdi:battery-30";
      else if (Number(variables?.battery) < 50) return "mdi:battery-40";
      else if (Number(variables?.battery) < 60) return "mdi:battery-50";
      else if (Number(variables?.battery) < 70) return "mdi:battery-60";
      else if (Number(variables?.battery) < 80) return "mdi:battery-70";
      else if (Number(variables?.battery) < 90) return "mdi:battery-80";
      else if (Number(variables?.battery) < 100) return "mdi:battery-90";
      else return "mdi:battery";
    ]]]
  proximity: |
    [[[
      return states['proximity.PROXIMITY']?.state; // OR
      return 'SOME TEXT'; // OR
      return '&nbsp';
    ]]]
  direction: |
    [[[
      var dir = states['proximity.PROXIMITY']?.attributes['dir_of_travel'];
      if (dir == 'arrived' || dir == 'towards')
        return "mdi:home-import-outline";
      else if (dir == 'away_from')
        return "mdi:home-export-outline";
      else
        return "mdi:map-marker-radius";
    ]]]
  travel_time: |
    [[[
      return states['sensor.TRAVEL']?.state; // OR
      return 'SOME TEXT'; // OR
      return '&nbsp';
    ]]]
  wifi_off: |
    [[[
      return states['sensor.WIFI']?.state == '<not connected>' ;
    ]]]
  zone_icon: |
    [[[
      if (states[entity.entity_id].state == "unknown")
        return "mdi:comment-question";
      var icon = "mdi:map-marker-radius";
      for (var s in states) 
      {
        if (s.includes('zone.') && states[s].attributes['friendly_name'] == states[entity.entity_id].state)
        {
          icon = states[s].attributes['icon'];
          break;
        }
      }
      return icon;
    ]]]
  meeting: |
    [[[
      return states['binary_sensor.MEETING']?.state == 'on'; // OR
      return false;
    ]]]
  css_big_size: |
    [[[
      return 200;
    ]]]
  css_font_size: |
    [[[ 
      if (Number(this.clientWidth) > Number(variables?.css_big_size))
        return "15px";
      else
        return "10px"; 
    ]]]
  css_padding: |
    [[[ 
      if (Number(this.clientWidth) > Number(variables?.css_big_size))
        return "10px";
      else
        return "3px"; 
    ]]]
  css_border: |
    [[[ 
      if (Number(this.clientWidth) > Number(variables?.css_big_size))
        return "5px solid";
      else
        return "3px solid"; 
    ]]]
  css_panel_height: |
    [[[ 
      if (Number(this.clientWidth) > Number(variables?.css_big_size))
        return "40px";
      else
        return "25px"; 
    ]]]
aspect_ratio: 1/1
show_entity_picture: true
show_name: true
hold_action:
  action: none
state:
  - value: home
    styles:
      custom_fields:
        icon:
          - filter: none
        panel-bottom:
          - border: '[[[ return variables?.css_border; ]]]'
          - border-left-style: hidden
          - border-right-style: hidden
          - border-bottom-style: hidden
          - border-color: var(--label-badge-blue)
  - value: not_home
    styles:
      custom_fields:
        icon:
          - filter: grayscale(1)
        panel-bottom:
          - border: '[[[ return variables?.css_border; ]]]'
          - border-left-style: hidden
          - border-right-style: hidden
          - border-bottom-style: hidden
          - border-color: gray
  - value: unknown
    styles:
      custom_fields:
        icon:
          - filter: grayscale(1) blur(2px)
        panel-bottom:
          - border: '[[[ return variables?.css_border; ]]]'
          - border-left-style: hidden
          - border-right-style: hidden
          - border-bottom-style: hidden
          - border-color: gray
  - value: ZONE1
    styles:
      custom_fields:
        icon:
          - filter: brightness(90%) sepia(100%) hue-rotate(15deg)
        panel-bottom:
          - border: '[[[ return variables?.css_border; ]]]'
          - border-left-style: hidden
          - border-right-style: hidden
          - border-bottom-style: hidden
          - border-color: var(--label-badge-green)
  - value: ZONE2
    styles:
      custom_fields:
        icon:
          - filter: brightness(90%) sepia(70%) hue-rotate(0deg) saturate(200%)
        panel-bottom:
          - border: '[[[ return variables?.css_border; ]]]'
          - border-left-style: hidden
          - border-right-style: hidden
          - border-bottom-style: hidden
          - border-color: var(--label-badge-yellow)
  - value: ZONE3
    styles:
      custom_fields:
        icon:
          - filter: brightness(60%) sepia(50%) hue-rotate(0deg) saturate(200%)
Стоматологstyles:
  card:
    - padding: 0%
    - color: gray
    - font-size: '[[[ return variables?.css_font_size; ]]]'
    - text-shadow: 0px 0px 1px black
  grid:
    - grid-template-areas: '"status n" "icon icon" "batterydistance wifidrivetime"'
    - grid-template-columns: 1fr 1fr
    - grid-template-rows: min-content 1fr min-content
  name:
    - position: absolute
    - top: '[[[ return variables?.css_padding; ]]]'
    - right: '[[[ return variables?.css_padding; ]]]'
    - color: white
    - z-index: 2
  custom_fields:
    icon:
      - width: 100%
      - pointer-events: none
      - display: grid
      - margin: 0
      - justify-self: center
      - opacity: 1
      - z-index: 0
    status:
      - position: absolute
      - top: '[[[ return variables?.css_padding; ]]]'
      - left: '[[[ return variables?.css_padding; ]]]'
      - color: white
      - text-align: left
      - width: 80%
      - z-index: 2
    wifidrivetime:
      - position: absolute
      - right: '[[[ return variables?.css_padding; ]]]'
      - bottom: '[[[ return variables?.css_padding; ]]]'
      - color: white
      - z-index: 2
    batterydistance:
      - position: absolute
      - left: '[[[ return variables?.css_padding; ]]]'
      - bottom: '[[[ return variables?.css_padding; ]]]'
      - color: white
      - z-index: 2
    panel-top:
      - top: 0px
      - left: 0px
      - right: 0px
      - position: absolute
      - width: auto
      - height: '[[[ return variables?.css_panel_height; ]]]'
      - background-color: black
      - opacity: 0.5
      - z-index: 1
    panel-bottom:
      - left: 0px
      - right: 0px
      - bottom: 0px
      - position: absolute
      - width: auto
      - height: '[[[ return variables?.css_panel_height; ]]]'
      - background-color: black
      - opacity: 0.5
      - z-index: 1
    meeting:
      - bottom: '[[[ return variables?.css_padding; ]]]'
      - left: 0px
      - right: 0px
      - position: absolute
      - z-index: 2
name: |
  [[[
    if (Number(this.clientWidth) > Number(variables?.css_big_size))
      return `<span>${states[entity.entity_id].attributes['friendly_name']}</span>
              <ha-icon icon="${states[entity.entity_id].attributes['icon']}" 
               style="width: 20px; height: 20px; color: white;">
              </ha-icon>`;
    else
      return `<ha-icon icon="${states[entity.entity_id].attributes['icon']}" 
               style="width: 20px; height: 20px; color: white;">
              </ha-icon>`;
  ]]]
custom_fields:
  panel-top: ''
  panel-bottom: ''
  meeting: |
    [[[
      if (variables.meeting)
      {
        return `<ha-icon icon="mdi:phone-voip" 
                 style="width: 20px; height: 20px; color: red;">
                </ha-icon>`;
      }
      return '';
    ]]]
  icon: |
    [[[ 
      return entity === undefined ? null : `<img src="${states[entity.entity_id].attributes['entity_picture']}" width="100%">`;
    ]]]
  status: |
    [[[
      if (states[entity.entity_id].state == 'not_home') 
      { 
        return `<ha-icon icon="${variables?.direction}" 
                 style="width: 20px; height: 20px; color: white;"> 
                </ha-icon>
                <span>Не дома</span>`;
      } 
      if (states[entity.entity_id].state == 'home') 
      {
        return `<ha-icon icon="mdi:home-circle-outline"
                 style="width: 20px; height: 20px; color: white;">
                </ha-icon>
                <span>Дома</span>`;
      }
      return `<ha-icon icon="${variables?.zone_icon}"
               style="width: 20px; height: 20px; color: white;">
              </ha-icon>
              <span>${states[entity.entity_id].state}</span>`;
    ]]]
  batterydistance: |
    [[[
      if (!isNaN(variables?.battery) && Number(variables?.battery) < Number(variables?.battery_threshold))
      { 
        return `<ha-icon icon="${variables?.battery_icon}"
                 style="width: 20px; height: 20px; color: ${variables?.battery_color};">
                </ha-icon><span>${variables?.battery}%</span>`;
      }
      if (states[entity.entity_id].state != 'home')
      { 
        if (isNaN(variables?.proximity))
        {
          return `<ha-icon icon="mdi:math-compass"
                   style="width: 20px; height: 20px; color: white;">
                  </ha-icon><span>${variables?.proximity}</span>`;
        }
        if (variables?.proximity <= 500)
        {
          return `<ha-icon icon="mdi:map-marker-distance"
                   style="width: 20px; height: 20px; color: var(--label-badge-green);">
                  </ha-icon><span>${variables?.proximity}m</span>`;
        }
        else
        {
          return `<ha-icon icon="mdi:map-marker-distance"
                   style="width: 20px; height: 20px; color: white;">
                  </ha-icon><span>${(variables?.proximity/1000).toFixed(1)}km</span>`;
        }
      }
      return `<ha-icon icon="${variables?.battery_icon}"
               style="width: 20px; height: 20px; color: ${variables?.battery_color};">
               </ha-icon><span>${variables?.battery}%</span>`;
    ]]]
  wifidrivetime: |
    [[[
      if (states[entity.entity_id].state != 'home')
      { 
        if (isNaN(variables?.travel_time))
        {
          return `<span>${variables?.travel_time}</span>
                  <ha-icon icon="mdi:tree-outline"
                   style="width: 20px; height: 20px; color: white;">
                  </ha-icon>`;
        }
        if (variables?.travel_time <= 15)
        {
          return `<span>${variables?.travel_time}min</span>
                  <ha-icon icon="mdi:camera-timer"
                   style="width: 20px; height: 20px; color: var(--label-badge-green);">
                  </ha-icon>`;
        }
        else
        { 
          return `<span>${variables?.travel_time}min</span>
                   <ha-icon icon="mdi:camera-timer"
                   style="width: 20px; height: 20px; color: white;">
                  </ha-icon>`;
        }
      }
      if (variables?.wifi_off)
      {
        return `<ha-icon icon="mdi:wifi-off"
                 style="width: 20px; height: 20px; color: white;">
                </ha-icon>`;
      }
      return `<ha-icon icon="mdi:wifi"
               style="width: 20px; height: 20px; color: white;">
              </ha-icon>`;
    ]]]
1 Like

thx! appreciated.

I’ll rewrite that to my needs, and see if the outcome looks just as cool as yours :wink:

Hey @benm7 can you share the code for getting the fuel prices? I’m trying to build something similar to get nearby EV charger details and display it neatly. Thanks

Thanks! That did the trick for me, the primary information is now showing the correct information so I can change the formula of the secondary entry. Appreciate your feedback!

1 Like

I created a template sensor which compares the location of my car with the locations of a group of petrol sensors, and then returns the value of the closest one. Like the below. The downside is though that you need to predefine the list of petrol stations and the zones, which means it won’t necessarily tell you the closest one but the closest one from the list only if that makes sense??

      closest_kia:
        friendly_name: Closest Kia
        icon_template: 'mdi:clock'
        value_template: >
            {% set closest_name = closest('device_tracker.kia','group.petrol').name|string %}
            {{ state_attr("sensor." + closest_name + "_pdl", 'friendly_name') }} - ${{ states("sensor." + closest_name + "_pdl") }}
        unit_of_measurement: c/L
 petrol:
    name: Petrol
    entities:
      - zone.bp_caringbah
      - zone.bp_cronulla
      - zone.bp_runway
      - zone.bp_gymea
      - zone.bp_sans_souci
1 Like

We use very simple ones:
image
Top right Icon shows if someone is home :house:, work (:office:), or unknown (:x:)
Bottom shows battery percentage, and if device is charging or not (charging :zap:, not charging :battery:)

Excellent design! That contains all the info I am wanting. Could you share code? How did you create the two person pictures? Great!

Very nice! Could you share the code please?

It’s quite a collection of separate pieces of code :sweat_smile: But let me see if I can get all of them in here:

You need:

  • Custom Button Card
  • Custom Stack in Card
  • Card Mod

The cards in the sidebar:

cards:
      - type: custom:stack-in-card
        mode: horizontal
        style: |
          ha-card {
            background: none;
            border: none;
            box-shadow: none;
            bottom: 0;
          }
        cards:
          # MARCIANO
          - type: custom:button-card
            entity: person.marciano
            triggers_update:
              - sensor.marciano_last_changed
            double_tap_action: !include ../popup/marciano.yaml
            variables:
              retain: sensor.marciano_last_changed
              battery: sensor.s22u_battery_level
              batt_s: sensor.s22u_battery_state
            template:
              - person_alt
          # BERTA
          - type: custom:button-card
            entity: person.berta
            triggers_update:
              - sensor.berta_last_changed
            double_tap_action: !include ../popup/berta.yaml
            variables:
              retain: sensor.berta_last_changed
              battery: sensor.berta_phone_battery_level
              batt_s: sensor.berta_phone_battery_state
            template:
              - person_alt

POPUP:

action: fire-dom-event
browser_mod:
  service: browser_mod.popup
  data:
    title: Marciano
    card_mod:
      style:
        #popup header
        .:
    style: >
      --popup-max-width: 400px;
    content:
      type: vertical-stack
      cards:
        - type: entities
          card_mod:
            class: content
          entities:
            - entity: person.marciano
              secondary_info: last-changed
              name: Marciano

        - type: history-graph
          card_mod:
            style: |
              ha-card > div {
                padding: 0 2em 1em 1.6em !important;
              }
          entities:
            - entity: person.marciano
              name: Marciano

        - type: glance
          card_mod:
            style: |
              ha-card > div {
                padding: 1em 1.5em 0.2em 1em !important;
                box-sizing: content-box;
              }
          show_state: false
          entities:
            - entity: device_tracker.s22u
              name: Router
              icon: mdi:wifi
              card_mod:
                style: &state |
                  state-badge {
                    color: {{ is_state(config.entity, 'home') | iif('#3182b7', '#3c3f3f') }};
                  }

            - entity: device_tracker.s22u
              name: Bluetooth
              icon: mdi:bluetooth
              card_mod:
                style: *state

            - entity: device_tracker.s22u
              name: Position
              icon: cil:iphone-modern
              card_mod:
                style: *state

        - type: custom:mod-card
          card_mod:
            style:
              hui-horizontal-stack-card$: |
                #root {
                  justify-content: space-evenly !important;
                  padding: var(--tablet-popup-button-padding);
                }
          card:
            type: horizontal-stack
            cards:
              - type: custom:button-card
                name: Play sound on phone
                icon: mdi:volume-high
                template: icon_name
                tap_action:
                  action: call-service
                  service: notify.mobile_app_s22u
                  service_data:
                    title: Find my phone
                    message: Here I am!
                    data:
                      push:
                        sound:
                          name: findmy.wav
                          critical: 1
                          volume: 1

        - type: map
          default_zoom: 16
          dark_mode: true
          entities:
            - device_tracker.s22u
          card_mod:
            style:
              .: |
                #root {
                  height: 25em;
                  padding-bottom: 0 !important;
                }
                ha-icon-button {
                  color: var(--primary-color);
                  zoom: 140%;
                  margin-left: -0.2em;
                }
                ha-card {
                  border-top: 2px solid #1a1a1a;
                  border-radius: 0;
                  transition: none;
                  margin-bottom: -4px !important;
                  height: 25em !important;
                }
              ha-map$: |
                #map {
                  background-color: #191919 !important;
                }
                .leaflet-control-attribution {
                  display: none;
                }
                .leaflet-bar a {
                  background-color: rgba(115, 123, 124, 0.2) !important;
                  color: #9da0a2 !important;
                  backdrop-filter: blur(0.25em);
                  zoom: 140%;
                }
                a.leaflet-control-zoom-in {
                  border-bottom: 1px solid #181818 !important;
                }
                .leaflet-pane.leaflet-tile-pane {
                  filter: invert(0.95) grayscale(0.95) contrast(95%);
                }

Templates:
person_alt.yaml:
There is a “triggers_update” in here which is overridden in the card. You could hardcode it in here instead.

---
person_alt:
  template:
    - dark-base
  state_display: >
      [[[
        if (entity) {
            return variables.state === 'home'
                ? variables.translate_home
                : variables.state === 'not_home'
                    ? variables.translate_not_home
                    : variables.state;
        }
        return variables.translate_unknown;
      ]]]
  show_state: false
  show_name: false
  triggers_update: sensor.time
  tap_action:
    action: none
  styles:
    grid:
      - grid-template-areas: |
          "si"
          "icon"
          "bi"
      - grid-template-columns: 1fr
      - grid-template-rows: auto
      - gap: 1.3%
      - align-items: center
      - will-change: transform
    card:
      - padding: 1em
      - box-shadow: none
      - background-color: none
      - position: relative
    name:
      - z-index: 998
      - position: absolute
      - top: -5rem
      - text-shadow: 0 4px 3px rgba(0,0,0,1)
      - justify-self: center
      - font-size: 1.5em
      - font-family: "var(--secondary-font-family)"
      - padding: 0 .3em 0 .3em

    state:
      - justify-self: start
      - font-size: .8em
      - align-self: center
      - font-family: "var(--primary-font-family)"
      - text-transform: uppercase

    custom_fields:
      icon:
        - z-index: 0
        - clip-path: circle()
        - width: 125%
        - pointer-events: none
        - display: grid
        - justify-self: center
        - border: none
        - border-radius: 50%
        - border-color: >
            [[[
              return variables.state === 'home' || variables.state === 'Home'
                  ? '#89b455'
                  : '#693633';
            ]]]
        - margin-bottom: .5em
      bi:
        - justify-self: center
        - font-size: 1rem
        - font-family: Raleway, sans-serif
      si:
        - position: fixed
        - top: -.1em
        - right: -1rem
        - font-size: 1rem
        - clip-path: circle()
        - padding: .3rem
        - pointer-events: none
        - border: none
        - display: grid
        - justify-self: center
        - border-radius: 50%
        - background-color: >
            [[[
              return variables.state === 'home' || variables.state === 'Home'
                  ? '#89b455'
                  : '#693633';
            ]]]
  custom_fields:
    icon: >
      [[[
        return entity && variables.entity_picture
            ? `<img src="${variables.entity_picture}" width="100%">`
            : null;
      ]]]
    bi: > 
      [[[
        let batt_s = states[variables.batt_s].state
        if (entity) {
          return batt_s === 'charging' || batt_s === 'Charging' || batt_s === 'full' || batt_s === 'Full'
            ? `⚡ ${states[variables.battery].state}%`
            : batt_s === 'discharging' || batt_s === 'Not Charging' 
              ?  `🔋  ${states[variables.battery].state}%`
              :  `❓  ${states[variables.battery].state}%`;
        }
        return variables.translate_unknown;
      ]]]
    si: >
      [[[
        if (entity) {
            return variables.state === 'home' || variables.state === 'Home'
                ? `🏠`
                : variables.state === 'not_home'
                    ? "❌"
                    : variables.state === 'work'
                      ? "🏢"
                      : variables.state;
        }
        return variables.translate_unknown;
      ]]]

dark_base.yaml (adjusted from matt’s base.yaml):

dark-base:
  template:
    - settings
  variables:
    state_on: >
      [[[ return ['on', 'home', 'cool', 'fan_only', 'playing', 'unlocked'].indexOf(!entity || entity.state) !== -1; ]]]
    state: >
      [[[ return !entity || entity.state; ]]]
    entity_id: >
      [[[ return !entity || entity.entity_id; ]]]
    entity_picture: >
      [[[ return !entity || entity.attributes.entity_picture; ]]]
    timeout: >
      [[[ return !entity || Date.now() - Date.parse(entity.last_changed); ]]]

  show_state: true
  show_icon: false
  state_display: >
    [[[ if (variables.state === true) return variables.translate_unknown; ]]]
  tap_action:
    ui_sound_tablet: |
      [[[
        let screensaver = states[variables.entity_tablet] === undefined ||
            states[variables.entity_tablet].state;

        if (variables.state === 'off' && screensaver === 'off') {
            hass.callService('media_player', 'play_media', {
                entity_id: variables.entity_browser_mod,
                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: variables.entity_browser_mod,
                media_content_id: '/local/sound/off.m4a',
                media_content_type: 'music'
            });
        }
      ]]]
    card_bounce: |
      [[[
        // add animation
        if (this.getElementsByTagName("style").length === 0) {

            // phone condition
            let mq = window.matchMedia('(max-width: 800px)').matches;

            let style = document.createElement('style');

            style.innerHTML = `
                @keyframes card_bounce {
                    0%   { transform: scale(1); }
                    10%  { transform: scale(${ mq ? '0.92' : '0.94' }); }
                    25%  { transform: scale(1); }
                    30%  { transform: scale(${ mq ? '0.96' : '0.98' }); }
                    100% { transform: scale(1); }
                }
            `;

            this.appendChild(style);
        }

        // duration
        let duration = 800;

        // animate
        this.style.animation = `card_bounce ${duration}ms cubic-bezier(0.22, 1, 0.36, 1)`;

        // reset
        window.setTimeout(() => { this.style.animation = "none"; }, duration + 100)
      ]]]
    action: toggle
    haptic: medium
  double_tap_action:
    haptic: success
  hold_action:
    action: block
  styles:
    grid:
      - grid-template-areas: |
          "icon  circle"
          "n     n"
          "s     s"
      - grid-template-columns: .5fr auto
      - grid-template-rows: auto
      - gap: 0%
      - align-items: start
      - will-change: transform
    name:
      - justify-self: start
      - line-height: 119%
    state:
      - justify-self: start
      - line-height: 102%
    card:
      - border-radius: var(--button-card-border-radius)
      - border-width: 0

      - -webkit-tap-highlight-color: rgba(0,0,0,0)
      - transition: none
      - --mdc-ripple-color: >
          [[[
            return variables.state_on
                ? '#97989c'
                : 'rgb(0, 0, 0)';
          ]]]
      - color: >
          [[[
            return variables.state_on
                ? 'var(--primary-text-color)'
                : 'var(--secondary-text-color)';
          ]]]
      - background-color: >
          [[[
            return variables.state_on
                ? 'rgba(255, 255, 255, 0.85)'
                : 'rgba(115, 115, 115, 0.25)';
          ]]]

settings.yaml (again adjusted from matt’s settings.yaml):
You might be able to go without this as the translation isn’t really necessary when you stay in English as I did…

settings:
  variables:
    entity_tablet: switch.galaxy_tab_a_screensaver
    entity_browser_mod: media_player.LenTab
    translate_unknown: Unknown
    translate_idle: Idle
    translate_home: Home
    translate_not_home: Not Home
    translate_available: Available
    translate_no_updates: No Updates
    translate_update_available: Update available
    translate_updates_available: Updates available
    translate_armed_home: Armed - Home
    translate_armed_away: Armed - Away
    translate_arming: Arming
    translate_disarmed: Disarmed
    translate_pending: Pending
    translate_triggered: TRIGGERED
3 Likes

Oh also, the pictures are the iPhone characters (my partner created those on her phone).
I saved them and then added a background + shadow to them in Photoshop.

Popup looks like this:

How do you link to the entity_picture?

Funny things is I JUST noticed that on mine too…

Sorry for the late reponse… I’ll have to dive into it to figure it out.

I really love the idea off this card, I want to create something like this for the rooms in my house.
Top card I would like to have the things for easy access to control the lights in that room and some sensor data.
the second one I would like to put the status of that room, like the status from media players, plants, temp, humidity enz.

I started editing the top card and made a basic setup, but when I try to edit the second one (maps card) I cannot make it work. maybe you can give me some pointers, this is the code so far.

ps.when is put two card on one page they both slide when I push either one of the, is it possible to only slide the one I push on?

card: null
type: custom:button-card
show_icon: false
entity: input_boolean.edwin_present
show_state: false
show_name: false
tap_action:
  action: toggle
styles:
  custom_fields:
    graph:
      - position: absolute
      - left: 10px
      - top: 210px
      - width: 60px
      - opacity: 75%
    woonkamer-temperatuur:
      - position: absolute
      - left: 325px
      - top: 10px
      - width: 60px
      - opacity: 75%
    woonkamer-spotjes:
      - position: absolute
      - left: 10px
      - top: 10px
      - width: 60px
      - opacity: 75%
    woonkamer-sfeerverlichting:
      - position: absolute
      - left: 10px
      - top: 45px
      - width: 60px
      - opacity: 75%
    woonkamer-koofverlichting:
      - position: absolute
      - left: 10px
      - top: 80px
      - width: 60px
      - opacity: 75%
    woonkamer-luchtvochtigheid:
      - position: absolute
      - left: 325px
      - top: 45px
      - width: 60px
      - opacity: 75%
    woonkamer-lichtinval:
      - position: absolute
      - left: 325px
      - top: 80px
      - width: 60px
      - opacity: 75%
  grid:
    - grid-template-areas: '"i" "n" "s"'
    - grid-template-columns: 1fr
    - grid-template-rows: 1fr min-content min-content
  card:
    - background: >-
        url('/local/2013-Harley-Davidson-VRSCDX-Night-Rod-Special-1250-ABS-R-800x490.png')
    - background-size: 100%
    - border-radius: 10px
    - box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.2)
    - height: 250px
    - width: 400px
  img_cell:
    - padding-top: 75px
  icon:
    - width: 50px
    - padding-bottom: 50px
  name:
    - color: var(--secondary-text-color)
    - padding-bottom: 0px
  state:
    - font-size: 20px
    - padding-bottom: 2px
    - line-height: 20px
    - color: white
state:
  - value: 'on'
    styles:
      card:
        - animation:
            - mymove 0.5s linear
        - animation-fill-mode: forwards
  - value: 'off'
    styles:
      card:
        - animation:
            - moving 0.5s linear
        - animation-direction: reverse
extra_styles: |
  @keyframes mymove {
  0% { transform: translate(0px) ; }
  10% { transform: translate(-40px) ; }
  20% { transform: translate(-80px) ; }
  30% { transform: translate(-120px) ; }
  40% { transform: translate(-160px) ; }
  50% { transform: translate(-220px) ; }
  60% { transform: translate(-260px) ; }
  70% { transform: translate(-300px) ; }
  80% { transform: translate(-340px) ; }
  90% { transform: translate(-380px) ; }
  100% { transform: translate(-400px) ; }
  }

  @keyframes moving {
  0% { transform: translate(0px) ; }
  10% { transform: translate(-40px) ; }
  20% { transform: translate(-80px) ; }
  30% { transform: translate(-120px) ; }
  40% { transform: translate(-160px) ; }
  50% { transform: translate(-220px) ; }
  60% { transform: translate(-260px) ; }
  70% { transform: translate(-300px) ; }
  80% { transform: translate(-340px) ; }
  90% { transform: translate(-380px) ; }
  100% { transform: translate(-400px) ; }
  }
custom_fields:
  graavi:
    card:
      type: custom:mini-graph-card
      card_mod:
        style: |
          ha-card {
          --ha-card-background: transparent; 
          color: var(--secondary-text-color);
          width: 400px;
          border-radius: 1px;
          box-shadow: none;
          }
      entities:
        - entity: sensor.woonkamer_temperatuur
      show:
        icon: false
        name: false
        points: false
        state: false
      font_size: 0
      color_thresholds:
        - value: 0
          color: '#f0c35b'
        - value: 40
          color: '#f0ca4d'
        - value: 80
          color: '#ebbf23'
  woonkamer-temperatuur:
    card:
      type: custom:button-card
      entity: sensor.woonkamer_temperatuur
      tap_action:
        action: more-info
      show_state: true
      show_name: false
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 15px
        card:
          - width: 70px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 3px
          - font-weight: null
          - text-transform: lovercase
          - align-self: null
          - padding-bottom: null
  woonkamer-spotjes:
    card:
      type: custom:button-card
      entity: light.woonkamer_spotjes
      color: auto
      tap_action:
        action: toggle
      hold_action:
        action: more-info
      show_state: false
      show_name: false
      show_icon: true
      icon: mdi:lightbulb-spot
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 25px
        card:
          - width: 60px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 3px
          - font-weight: null
          - text-transform: lovercase
          - align-self: null
          - padding-bottom: null
  woonkamer-luchtvochtigheid:
    card:
      type: custom:button-card
      entity: sensor.woonkamer_luchtvochtigheid
      tap_action:
        action: null
      show_state: true
      show_name: false
      show_icon: true
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 20px
        card:
          - width: 70px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 2px
          - font-weight: null
          - text-transform: lovercase
          - align-self: right
          - padding-bottom: null
  woonkamer-lichtinval:
    card:
      type: custom:button-card
      entity: sensor.woonkamer_lichtinval
      tap_action:
        action: more-info
      show_state: true
      show_name: false
      show_icon: true
      icon: mdi:sun-wireless
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 20px
        card:
          - width: 70px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 10px
          - font-weight: null
          - text-transform: lovercase
          - align-self: right
          - padding-bottom: null
  woonkamer-sfeerverlichting:
    card:
      type: custom:button-card
      entity: light.woonkamer_sfeerverlichting
      color: auto
      tap_action:
        action: toggle
      hold_action:
        action: more-info
      show_state: false
      show_name: false
      show_icon: true
      icon: mdi:lamps
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 25px
        card:
          - width: 60px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 3px
          - font-weight: null
          - text-transform: lovercase
          - align-self: null
          - padding-bottom: null
  woonkamer-koofverlichting:
    card:
      type: custom:button-card
      entity: switch.woonkamer_koof_verlichting_wcd
      tap_action:
        action: toggle
      hold_action:
        action: more-info
      show_state: false
      show_name: false
      show_icon: true
      icon: mdi:led-strip-variant
      styles:
        grid:
          - grid-template-areas: '"i s s"'
          - grid-template-columns: 1fr
          - grid-template-rows: 1fr min-content min-content
        icon:
          - width: 25px
        card:
          - width: 60px
          - height: 30px
        state:
          - font-size: 15px
          - justify-self: null
          - padding-right: 3px
          - font-weight: null
          - text-transform: lovercase
          - align-self: null
          - padding-bottom: null