Lovelace: Button card

Legend, thank you! That worked a treat. Now to try and learn templates so I can apply that to all my buttons!

I ended up going with the elements layering because of the refreshing. It was visibly noticeable. Anyways, I have a working card that changes based on sensor type. I think Iā€™m happy with it now. I just need to deploy it off my testing page.

image

5 Likes

Nice stuff :slight_smile:

Your new changes with triggering, does last_changed still update? Iā€™m assuming yes because youā€™re using it your cards.

Yes, itā€™s unrelated

1 Like

Could you share your config for the fan?

Sure, it may not be helpful because I use lovelace_gen

# lovelace_gen

{% set color = color|default('var(--paper-item-icon-active-color)') %}

type: custom:button-card
aspect_ratio: 1/1
entity: {{ entity }}
size: 60%
name: {{ name }}
show_state: true
show_name: true
show_label: false
styles:
  icon:
  - height: auto
  img_cell:
  - justify-content: start
  - align-items: start
  grid:
  - grid-template-areas: '"i info" "n n" "s s" "l l"'
  - grid-template-columns: 1fr 35%
  - grid-template-rows: 1fr 0.min-content min-content min-content
  - position: relative
  card:
    - border-radius: 15px
    - padding: 10px
  name:
  - justify-self: start
  - align-self: end
  - font-weight: bold
  - font-family: Helvetica 
  - font-size: 12px
  - text-align: start
  - background-image: linear-gradient(to right, white 0%, white 80%, rgba(0,0,0,0))
  - -webkit-background-clip: text
  - -webkit-text-fill-color: transparent
  - position: relative
  - display: inline-block
  - width: 100%
  - align-content: start
  - text-align: start
  - text-overflow: unset
  state:
  - justify-self: start
  - align-self: end
  - font-weight: bold
  - font-family: Helvetica 
  - font-size: 12px
  - text-align: start
  custom_fields:
    info:
    - align-self: start
custom_fields:
  info: >
      [[[
        function capitalizeFirstLetter(string) {
          return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
        }
        
        const length = 41;
        const width = 3;

        if (entity.state === 'on' && entity.attributes.brightness) {
          const radius = length / 2;
          const brightness = Math.round(entity.attributes.brightness / 2.54);
          const circumference = radius * 2 * Math.PI;
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="${radius}" fill="none" stroke="var(--paper-item-icon-color)" opacity="0.5" stroke-width="${width}" />
              <circle style="
                  transform: rotate(-90deg);
                  transform-origin: 50% 50%;
                  stroke-dasharray: ${circumference};
                  stroke-dashoffset: ${circumference - brightness / 100 * circumference};
                "
                id="c_brightness" cx="25" cy="25" r="${radius}" stroke="var(--paper-item-icon-active-color)" stroke-width="${width}" fill="none" stroke-linecap="round" />
              <text x="50%" y="54%" fill="var(--primary-text-color)" font-size="14" text-anchor="middle" alignment-baseline="middle">${brightness}<tspan font-size="10">%</tspan>
              </text>
            </svg>
            `;
          }
        else if (entity.state === 'on' && entity.attributes.speed && entity.attributes.speed_list)  {
          const text = capitalizeFirstLetter(entity.attributes.speed);
          const gap = 5;
          const edge = (50 - length) / 2;
          const y = 50 - edge;
          var items = entity.attributes.speed_list;
          if (items.indexOf('off') !== -1){
            items.splice(items.indexOf('off'), 1);
          }
          const current = items.indexOf(entity.attributes.speed)
          var i;
          var x1 = edge;
          var ret = `<svg  viewBox="0 0 50 50">`;
          var l = (length - gap * (items.length - 1)) / items.length;
          for (i = 0; i < items.length; i++) {
            var x2 = x1 + l;
            var color = (i <= current) ? "var(--paper-item-icon-active-color)" : "var(--paper-item-icon-color)";
            var opacity = (i <= current) ? "1.0" : "0.5";
            ret += `<line x1="${x1}" y1="${y}" x2="${x2}" y2="${y}" stroke="${color}" stroke-width="${width}" opacity="${opacity}" stroke-linecap="round" />`;
            x1 = x2 + gap;
          }
          ret += `<text x="50%" y="54%" fill="var(--primary-text-color)" font-size="14" text-anchor="middle" alignment-baseline="middle">${text}</text></svg>`
          return ret;
        }
      ]]]
state:
- value: 'on'
  styles:
    card:
    - opacity: 1.0
    icon:
    - color: |
        [[[
          var [domain, object_id] = entity.entity_id.split('.');
          if (domain === "light")
            return 'var(--button-card-light-color)';
          return '{{ color }}';
        ]]]
    name:
      - color: white
    state:
      - color: gray
    lock:
      - color: white 
    label:
      - color: gray
- value: 'off'
  styles:
    card:
    - opacity: 0.5
    icon:
    - color: var(--paper-item-icon-color)
    name:
    - color: var(--primary-text-color)
    state:
    - color: var(--primary-text-color)
    label:
    - color: var(--primary-text-color)
    lock:
    - color: var(--paper-item-icon-color)
- value: "unavailable"
  styles:
    card:
    - opacity: 0.2
    icon:
    - color: var(--paper-item-icon-color)')
    name:
    - color: var(--primary-text-color)
    state:
    - color: hsl(0, 100%, 50%)
    label:
    - color: var(--primary-text-color)
    lock:
    - color: var(--paper-item-icon-color)
tap_action:
  action: toggle
  haptic: light
hold_action:
  action: more-info
  haptic: heavy
1 Like

Helped a lot, thanks :wink:
image

1 Like

I have a question. With the latest button card update that introduced triggers_updateā€¦if Iā€™m using decluttering card to reduce code repetition, so entity is a variable not explicitely ā€˜switch.myswitchā€™ in the button card configā€¦I need to manually add triggers_update because it wonā€™t be auto parsed, correct?

No, thatā€™s fine. decluttering-card replaces the value before assigning the config to the card so thereā€™s no difference. So actually button-card sees the actual value, not the [[variable_name]]

Oh, great! I was wondering if I have it setup like so

  air_purifier_control_button_template:
    card:
      color: 'rgba(255, 255, 255, 0)'
      color_type: card
      icon: 'mdi:[[icon]]'
      state:
        - operator: template
          styles:
            card:
              - color: var(--primary-color)
          value: |
            [[[ return [[condition]] ]]]
        - operator: default
          styles:
            card:
              - color: 'rgba(150,150,150, 1.0)'
      styles:
        card:
          - height: 50px
          - color: 'rgba(150, 150, 150, 1.0)'
          - box-shadow: none
      tap_action:
        action: call-service
        service: '[[service]]'
        service_data:
          entity_id: '[[entity]]'
      type: 'custom:button-card'

is it actually replacing the variable when rendering so it will be picked up by this new feature or it will be like in the example with JavaScript. I think I got mislead by the ā€˜variableā€™ name :wink:

It depend on how your [[condition]] is written

All of them are more or less like this:

variables:
  - icon: circle-slice-6
  - condition: >-
	  (states['fan.xiaomi_miio_device'].attributes.speed === 'Favorite'
	  && states['fan.xiaomi_miio_device'].attributes.favorite_level ==
	  12)
  - service: script.turn_on
  - entity: script.air_purifier_set_favorite_12

That will match states['fan.xiaomi_miio_device'].attributes.speed with fan.xiaomi_miio_device

Decluttering card just literally replaces the [[variable]] with the value youā€™ve set and then the result of that replacement is the config that is given to button-card. So thereā€™s no difference.

Iā€™m glad it worked for you with 4 speeds. I tried to make it dynamically scale based on the speed count. Iā€™m happy to see it works.

Great, so Iā€™m all set and using the new triggers_update :+1:

Hi All
Just started using this card and must say the amount of configuration options is immense.
Iā€™m trying to uniform my lights to look the same, which contain light and switch entities. Iā€™ve managed to get one switch entity how iā€™d like it, but i canā€™t seem to get the colour options correct for a light entity.
I want it to be colour of the card when off, and then the card goes darker with a border when on, with the icon changing to yellow (or ideally auto for my colour lights). For a light entity though i can only seem to format either the icon or the card, and not both. Can someone help please? See below the switch card which is doing what iā€™m trying to do on lights.

type: 'custom:button-card'
entity: switch.some_generic_name
color: auto
color_type: card
icon: 'mdi:patio-heater'
name: Back Garden
aspect_ratio: 3/1
state:
  - color: 'rgba(7, 17, 51,1)'
    styles:
      icon:
        - color: 'rgba(222, 211, 13)'
      card:
        - border: 'solid 2px rgba(222,211,13,0.4)'
    value: 'on'
styles:
  card:
    - font-size: 80%
  icon:
    - color: white

3.3.1 triggers_update

@RomRider very very very thanks!
No more load on the browser

Stupid question, but Iā€™ve noticed that when I use layout-card, the custom button card will grow in height even thought Iā€™ve set a height for the button card. I think the layout card does some scaling. Any idea how to force the height of the button card?

Iā€™ve tried ā€œ!importantā€ and it had no effect:
style: |
ha-card {
height: 36px !important;
}

Donā€™t use card-mod on button-card. Use directly the configuration of button-card. Everything is in the documentation on github.

styles:
  card:
    - height: 36px