Code question: CSS variables vs template variables

This is my thermostat card:
thermostat card
It’s using the custom:button card template you’ll find here: GitHub - custom-cards/button-card: :sparkle: Lovelace button-card for home assistant which I can’t say enough good about.
The full code for the thermostat is as follows:

              - entity: climate.thermostat_2
                type: 'custom:button-card'
                icon: 'mdi:thermostat'
                aspect_ratio: 3/2
                name: Thermostat
                variables:
                  mode_icon: |
                    [[[
                      if (states["climate.thermostat_2"].state == "heat") {
                        return "hass:fire"; }
                      if (states["climate.thermostat_2"].state == "cool") {
                        return "hass:snowflake"; }
                      else return "hass:thermostat";
                    ]]]
                styles:
                  card:
                    - background-color: |
                        [[[
                          if (states['climate.thermostat_2'].state == 'heat') return 'darkRed';
                          if (states['climate.thermostat_2'].state == 'cool') return 'darkBlue';
                          if (states['climate.thermostat_2'].state == 'off') return 'darkSlateGrey';
                          else return 'yellow';
                        ]]]
                    - border-radius: 0%
                    - padding: 1%
                    - color: ivory
                    - font-size: 12px
                    - text-transform: capitalize
                  grid:
                    - grid-template-areas: >-
                        "n n n n" "i temp temp temp" "stat stat stat stat" "fan
                        fan fan fan"
                    - grid-template-columns: 1fr 1fr 1fr 1fr
                    - grid-template-rows: min-content 1fr min-content min-content
                  name:
                    - font-weight: bold
                    - font-size: 13px
                    - color: white
                    - align-self: middle
                    - justify-self: start
                    - padding-bottom: 0px
                  img_cell:
                    - justify-content: start
                    - align-items: start
                    - margin: 0%
                  icon:
                    - color: yellow
                    - width: 100%
                    - margin-top: 0%
                  custom_fields:
                    temp:
                      - font-size: 13px
                      - align-self: middle
                      - justify-self: start
                    stat:
                      - padding-bottom: 2px
                      - align-self: middle
                      - justify-self: start
                      - '--icon-color-sensor': |
                          [[[
                            if (states["climate.thermostat_2"].state == "heat") {
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "heating") return "orange";
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "fan") return "yellow";
                              return "white"; }
                            if (states["climate.thermostat_2"].state == "cool") {
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "cooling") return "lightSkyBlue";
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "fan") return "lightGreen";
                              return "white"; }
                            else return "lightGrey";
                          ]]]
                    fan:
                      - align-self: middle
                      - justify-self: start
                      - '--icon-color-sensor': |
                          [[[
                            if (states["climate.thermostat_2"].attributes["fan_mode"] == "on") {
                              if (states['climate.thermostat_2'].attributes['fan_action'] == "running") return "lightSkyBlue";
                              return "white"; }
                            if (states["climate.thermostat_2"].attributes["fan_mode"] == "auto") {
                              if (states['climate.thermostat_2'].attributes['fan_action'] == "running") return "lightSkyBlue";
                              return "white"; }
                            else return "lightGrey";
                          ]]]
                custom_fields:
                  temp: |
                    [[[
                      return `<span style="font-size: 24px;">${states['climate.thermostat_2'].attributes['current_temperature']}°F </span>
                      <span>Set:${states['climate.thermostat_2'].attributes['temperature']}°F</span>`
                    ]]]
                  stat: |
                    [[[
                      return `<ha-icon icon="${variables.mode_icon}"
                      style="width: 14px; height: 14px; color: var(--icon-color-sensor);">
                      </ha-icon><span> mode: <span>${states['climate.thermostat_2'].state} | </span>
                      <span>${states['climate.thermostat_2'].attributes['hvac_action']}</span>`
                    ]]]
                  fan: |
                    [[[
                      return `<ha-icon icon="mdi:fan"
                      style="width: 14px; height: 14px; color: var(--icon-color-sensor);">
                      </ha-icon><span> fan: <span>${states['climate.thermostat_2'].attributes['fan_mode']} | </span>
                      <span>${states['climate.thermostat_2'].attributes['fan_action']}</span>`
                    ]]]

My question is simple: Is it more efficient to use the CSS variables like I do in the “stat” field:

                    stat:
                      - padding-bottom: 2px
                      - align-self: middle
                      - justify-self: start
                      - '--icon-color-sensor': |
                          [[[
                            if (states["climate.thermostat_2"].state == "heat") {
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "heating") return "orange";
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "fan") return "yellow";
                              return "white"; }
                            if (states["climate.thermostat_2"].state == "cool") {
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "cooling") return "lightSkyBlue";
                              if (states['climate.thermostat_2'].attributes['hvac_action'] == "fan") return "lightGreen";
                              return "white"; }
                            else return "lightGrey";
                          ]]]
                  stat: |
                    [[[
                      return `<ha-icon icon="${variables.mode_icon}"
                      style="width: 14px; height: 14px; color: var(--icon-color-sensor);">
                      </ha-icon><span> mode: <span>${states['climate.thermostat_2'].state} | </span>
                      <span>${states['climate.thermostat_2'].attributes['hvac_action']}</span>`
                    ]]]

or would it be more efficient to use template variables as I do here:

                variables:
                  mode_icon: |
                    [[[
                      if (states["climate.thermostat_2"].state == "heat") {
                        return "hass:fire"; }
                      if (states["climate.thermostat_2"].state == "cool") {
                        return "hass:snowflake"; }
                      else return "hass:thermostat";
                    ]]]
                  stat: |
                    [[[
                      return `<ha-icon icon="${variables.mode_icon}"
                      style="width: 14px; height: 14px; color: var(--icon-color-sensor);">
                      </ha-icon><span> mode: <span>${states['climate.thermostat_2'].state} | </span>
                      <span>${states['climate.thermostat_2'].attributes['hvac_action']}</span>`
                    ]]]

Both work well with the coding above. It’s really just a matter of consistency to use only one of them. What is the assembled wisdom of you folks that are more familiar with CSS and templates?

All the code is executed the same way every time, what you’re posting is basically just a different execution order. There’s no real benefit going one way or the other.

Personally, I like to keep all my code together. Also, entity used in templates reference what’s in the entity field on the button card. You don’t need to keep using states['climate.thermostat_2'] everywhere.

I.e.

                    stat:
                      - padding-bottom: 2px
                      - align-self: middle
                      - justify-self: start
                  stat: |
                    [[[
                      var hvac_action = entity.attributes['hvac_action'];
                      var color = "lightGrey";
                      if (entity.state == "heat")
                        if (hvac_action == 'heating')
                          color = 'orange';
                        else if (hvac_action == 'fan')
                          color = 'yellow';
                        else
                          color = 'white';
                      else if (entity.state == 'cool')
                        if (hvac_action == 'cooling')
                          color = 'lightSkyBlue';
                        else if (hvac_action == 'fan')
                          color = 'lightGreen';
                        else
                          color = 'white';
                      return `<ha-icon icon="${color}"
                      style="width: 14px; height: 14px; color: var(--icon-color-sensor);">
                      </ha-icon><span> mode: <span>${states['climate.thermostat_2'].state} | </span>
                      <span>${states['climate.thermostat_2'].attributes['hvac_action']}</span>`
                    ]]]

Oh yes. This is what I get for “borrowing code.” I knew about “entity,” but hadn’t yet worked that into the borrowed code.
Just to be clear, states[‘climate.thermostat_2’] becomes states[entity]?

no, it becomes entity

ok. That’s not exactly intuitive. :slight_smile: I’ll go with it though.
Does that work for entity.attributes[‘hvac_action’] and other contstructions? (Use it like a text macro?)

It’s a variable in js. This is how javascript works. If you don’t know object oriented programing, it’s not going to be intuitive. However, if you do know object oriented programming, is very intuitive.

Yes, see the code I posted above, you’ll notice I use exactly what you just asked about

I guess “intuitive” is in the mind of the beholder. I would have thought that entity would be a stand-in for exactly what’s in the entity field. Every OOP implementation I’ve seen (even my own) has a few things like this. You just need to learn what they are and remember them.
I am sorry that I hadn’t noticed that you reposted the adjusted code. (And I’m one who tends to call people on “reading for content”.)
And now you’ve thrown in yet another variable variable :slight_smile: in the use of var.
I really like keeping the code together as you’ve done. It simplifies looking through it months later and trying to figure out what I did. (Now I really have to go back and rework that code.)
As a meta aside, one of the things I like about this forum is that I can ask a question and get the answer to the question that I didn’t quite know enough to ask. Thanks.

Well, this is all JS (JavaScript). If you really want to know what you’re doing with templates on the custom button card, take up an online tutorial on JavaScript. It’ll make your life easier. Also, it would be good for you to just read up on object orientation if you plan on doing a JavaScript tutorial.

Been there. Done that. I think the problem is that I’ve learned so many programming languages, I find that some of the time I’m just trying to focus on the specific syntax of the particular one I’m using right now. (Although, to be sure in HA, we’re talking JavaScript, CSS/HTML, and a little Jinja all at the same time.)
To be honest, I wish I could just forget RPG, COBOL, and FORTRAN and free up that memory space for languages that are actually used today.

1 Like

For you folks that might want the finished code, here it is with all the "entity"s in place and with variables used for “calculating” the icons as well as the colors:

              - entity: climate.thermostat_2
                type: 'custom:button-card'
                icon: 'mdi:thermostat'
                aspect_ratio: 3/2
                name: Thermostat
                styles:
                  card:
                    - background-color: |
                        [[[
                          if (entity.state == 'heat') return 'darkRed';
                          if (entity.state == 'cool') return 'darkBlue';
                          if (entity.state == 'off') return 'darkSlateGrey';
                          else return 'yellow';
                        ]]]
                    - border-radius: 0%
                    - padding: 1%
                    - color: ivory
                    - font-size: 12px
                    - text-transform: capitalize
                  grid:
                    - grid-template-areas: >-
                        "n n n n" "i temp temp temp" "stat stat stat stat" "fan
                        fan fan fan"
                    - grid-template-columns: 1fr 1fr 1fr 1fr
                    - grid-template-rows: min-content 1fr min-content min-content
                  name:
                    - font-weight: bold
                    - font-size: 13px
                    - color: white
                    - align-self: middle
                    - justify-self: start
                    - padding-bottom: 0px
                  img_cell:
                    - justify-content: start
                    - align-items: start
                    - margin: 0%
                  icon:
                    - color: yellow
                    - width: 100%
                    - margin-top: 0%
                  custom_fields:
                    temp:
                      - font-size: 13px
                      - align-self: middle
                      - justify-self: start
                    stat:
                      - padding-bottom: 2px
                      - align-self: middle
                      - justify-self: start
                    fan:
                      - align-self: middle
                      - justify-self: start
                custom_fields:
                  temp: |
                    [[[
                      return `<span style="font-size: 24px;">${entity.attributes['current_temperature']}°F </span>
                      <span>Set:${entity.attributes['temperature']}°F</span>`
                    ]]]
                  stat: |
                    [[[
                      var hvac_action = entity.attributes['hvac_action'];
                      var icon = "hass:thermostat";
                      var color = "lightGrey";
                      if (entity.state == "heat") {
                        icon = "hass:fire";
                        if (hvac_action == 'heating')
                          color = 'orange';
                        else if (hvac_action == 'fan')
                          color = 'yellow';
                        else
                          color = 'white';
                      } else if (entity.state == 'cool') {
                        icon = "hass:snowflake";
                        if (hvac_action == 'cooling')
                          color = 'lightSkyBlue';
                        else if (hvac_action == 'fan')
                          color = 'lightGreen';
                        else
                          color = 'white';
                      }
                      return `<ha-icon icon="${icon}"
                      style="width: 14px; height: 14px; color: ${color};">
                      </ha-icon><span> mode: <span>${entity.state} | </span>
                      <span>${hvac_action}</span>`
                    ]]]
                  fan: |
                    [[[
                      var fan_mode = entity.attributes['fan_mode'];
                      var fan_action = entity.attributes['fan_action'];
                      var color = "lightGrey";
                      if (fan_mode == "on")
                        if (fan_action == "running")
                          color = "lightSkyBlue";
                        else
                          color = "white";
                      else if (fan_mode == "auto")
                        if (fan_action == "running")
                          color = "lightSkyBlue";
                        else
                          color = "white";
                      return `<ha-icon icon="mdi:fan"
                      style="width: 14px; height: 14px; color: ${color};"></ha-icon>
                      <span> fan: ${fan_mode} | ${fan_action}</span>`
                    ]]]

Much, much easier to read. Thanks, petro.

1 Like

Very nice dynamic multi-attribute-state display. I like it and the formatting tutorial the code provides. It’s well worth a mention on the custom-button man page.

Do you have *_actions: as well to change the setpoint and mode, etc, or is that another card?

not so much another card as simply click on the card and it brings up the “more info” dialog which allows you to change set points and modes.
On my “family presence” tile, which is using a similar formatting, I set the tap action to bring up a map card with all three device trackers locations marked on it.
I’ve also just now converted all three of my “tile” cards to templates so I can use them on multiple views without duplicating tons of code.
I’m usually reticent to “cross-post”. Do you recommend just a link in the Lovelace: Button card - Share your Projects! / Lovelace & Frontend - Home Assistant Community (home-assistant.io) thread or should I post the code for one or all three “tiles”?