šŸ“ 100% Templatable Lovelace Configurations

Sorry I know you are busy @Ildar_Gabdullin but I just want to know if have I hit a dead end with this redraw thing now as I short of reading the code I donā€™t know where to go with it, and no other card seems to claim to do it so it rather kills the project Iā€™m doing if I canā€™t solve this. The only other option is to reload the whole dashboard every minute and that will look awful.

Cheers
ā€”Chris

Chris, I am leaving tomorrow for my next shift, so rather limited with timeā€¦
Letā€™s continue this later after a couple of weeks.
I will give you a ready example of a graph card with a dynamic title then.
Please ping me then.

As a starting point:

type: custom:stack-in-card
cards:
  - type: markdown
    content: >-
      Weather is {{states('weather.home_gismeteo')}}
    card_mod:
      style: |
        ha-card {
          font-size: var(--ha-card-header-font-size, 24px)
        }
  - type: history-graph
    entities:
      - entity: sensor.system_monitor_processor_use

Just place ā€œapexhartsā€ instead of ā€œhistory-graphā€ card.
Then figure out how to re-write your js-code to jinja.

No worries, will do, thank you! I actually already have it in Jinja so thatā€™s quite quick to do. Iā€™m not sure how that will hide the chart dynamically when the data becomes zero using CSS but Iā€™ll have a play with this all and see if it can have templated styles or something (the main purpose of what Iā€™m doing, the heading is just me being lazy)

I have also just discovered that apex charts has an update interval configuration item (I knew the main apexcharts.js library had an update method but as itā€™s wrapped up in a card I canā€™t run it), but I suspect this just redraws the data bars on the chart and doesnā€™t redraw the card/chart itself (and thus doesnā€™t reevaluate the css style applied in the card config)

But that might provide me with a workaround if I am wrong on how I think it works.

Thanks again

Chris

Interesting, does it mean that the card updates itself not on every entityā€™s change - but periodically? (I mean the graph itself, not the scale which is supposed to be ā€œshifted leftā€)

As for the ā€œhide dynamicallyā€ part - do you need to hide the whole card (with a title) or the graph only? Alternatively you may want to show smth different instead of the graph card.

And also discussing card-mod seems to be off-topic here.
In general:

type: entity
entity: sun.sun
card_mod:
  style: |
    {% if .... -%}
    ha-card {display: none}
    {%- endif %}

Yes that does apparently update content periodically. Itā€™s supposed to update when the entity updates but itā€™s not, same as CTC isnā€™t. But this seems to force a refresh at a time

I want the title and the graph to disappear. Iā€™m using card mod inside apex chart card as the apex chart card doesnā€™t have its own style configuration option so if you want to play with css you use that (it has hundreds of styling configurations but nowhere can you set css display to none, itā€™s all line colours and stuff)

Update in case you see it / to save you testing. After a couple of days it just started refreshing, and hiding/unhiding as it is supposed to. I will check it properly over this week (I need the rain to start and stop a few times!) but my suspicion is that I have been fighting browser cache issues. I usually dev in private browsing to avoid these issues but just realised that I havenā€™t been recently, my tabs are accidentally normal tabs.

I just noticed today that it had started working as expected (I think) so fingers crossed I have resolved the no-redraw problems I had!

when will I learn that complex dashboards in Lovelace must have browser cache clear before bug hunting

Will update when sure either way

Chris

Iā€™m trying to convert a float value from a input_number helper to int without success.

I tried $( parseInt(states[ā€˜input_number.xā€™].state) ) but Iā€™m not obtaining anything on the mushroom chip content. I also tried ~~ and Ā¦ 0, some of those just break my card. It seems like I cannot use those regular js functions for some reason :confused:

Any advise on what to try? Iā€™m running the latest version on the config template card as per HACS.

Suggest you to post a SHORT simplified code with your mushroom card.
I am not using mushrooms but may be someone else is.

Sorry I was too tired yesterday to post the code, lol

I figured it out this morning (thanks to you helping me consider it was a mushroom card thing), since the issue arised in fact due to the mushroom card, the same thing worked on a simple button.

This is what I was doing:

type: custom:config-template-card
variables:
PAGE: states[ā€˜input_number.xā€™]
entities:

  • input_number.x
    card:
    type: custom:mushroom-chips-card
    alignment: end
    chips:
    • type: template
      content: ${ parseInt(PAGE.state) }

But the mushroom chip card was just not spawning, today I figured out that the card needs a string in order to work, it cannot be an integer, so I just changed the last line for this one:

  content: ${ parseInt(PAGE.state).toString() }

And now it works, thanks!

New question!

This works (recognized as an [object Object] which is fine):

type: custom:config-template-card
variables:
  X: states['media_player.office_sonos']
entities:
  - media_player.office_sonos
card:
  type: button
  name: ${ X }

but this doesnā€™t (recognized as string ā€œstates[ā€˜media_player.office_sonosā€™]ā€)

type: custom:config-template-card
variables:
  X:
    - x: states['media_player.office_sonos']
entities:
  - media_player.office_sonos
card:
  type: button
  name: ${ X[0].x }

even wrapping it inside ${ } doesnā€™t work. What am I missing here? I already got a WA for it but I want to know why it doesnā€™t work lol

Iā€™ve discovered a funny thingā€¦

tl;dr Wrap config-template-card with card-templater and put sun.sun in the entities list ā†’ it will work like magic without manually listing entities xDDD

The goal: a dynamic list of lights, grouped by their areas. I want a vertical-stack card containing multiple entities cards, each representing an area. And I want it ALL to be dynamic, including the areas.

My first attempt was with the custom:card-templater ā†’ I wanted to replace the cards key of vertical-stack with cards_template and thus generate the the list of cards with Jinja templates, but Iā€™ve run into an issueā€¦

So, Iā€™ve decided to try custom:config-template-card, so I can generate vertical-stackā€™s cards list using the Javascript templates. Iā€™ve managed to do that! But, unfortunately Iā€™d also need to generate the config-template-cardā€™s entities key, and that canā€™t be doneā€¦

We need to go deeper :smiley: Final try: Wrap config-template-card with card-templater and generate config-template-cardā€™s entities by using a Jinja template in form of the entities_template keyā€¦ ACTUALLY NO NEED!

After I wrapped config-template-card with card-templater, listing ANY existing entity inside the config-template-cardā€™s entities list ā†’ WORKS. I donā€™t why. It just does xDDD Every state is updated correctly.

# THIS WORKS
type: custom:card-templater
card:
  type: custom:config-template-card
  entities:
    # ANY existing entity will work,
    # doesn't need to be one of the used in the JS generated content
    - sun.sun
  card:
    type: vertical-stack
    cards: |-
      ${ generate_cards() }

The whole code to display a dynamic list of lights grouped by areas:

type: custom:card-templater
card:
  type: custom:config-template-card
  entities:
    - sun.sun
  card:
    type: vertical-stack
    cards: |-
      ${
        const hass = this.hass;

        function getEntityDomain(entity) {
          return entity.entity_id.split('.')[0];
        }

        function getEntityAreaIdWithDeviceInheritance(entity) {
          return entity.area_id || hass.devices[entity.device_id].area_id;
        }

        function getEntityAreaWithDeviceInheritance(entity) {
          const areaId = getEntityAreaIdWithDeviceInheritance(entity);

          if (undefined === areaId) {
            return undefined;
          }

          return hass.areas[areaId];
        }

        let areasWithLights = {};

        for (const [, entity] of Object.entries(hass.entities)) { 
          if ('light' === getEntityDomain(entity)) {
            const area = getEntityAreaWithDeviceInheritance(entity);
            
            if (area) {
              if (!areasWithLights[area.area_id]) {
                  areasWithLights[area.area_id] = {
                    'area': area,
                    'entities': [],
                  };
              }

              areasWithLights[area.area_id].entities.push(entity);
            }
          }
        }

        let cards = [];

        for (const [areaId, areaAndEntities] of Object.entries(areasWithLights)) {
          cards.push({
            'type': 'entities',
            'state_color': 'true',
            'show_header_toggle': 'true',
            'title': areaAndEntities.area.name,
            'entities': areaAndEntities.entities.map(entity => { 
              return { 
                'entity': entity.entity_id,
                'secondary_info': 'last-changed'
              };
            })
          });
        }

        cards = cards.sort((card1, card2) => new Intl.Collator().compare(card1.title, card2.title));

        cards;
      }

The result:

  • everything is dynamic ā†’ areas and lights belonging to them
  • everything is updated properly ā†’ without the wrapping hack, the buttons would be ā€œstuckā€
  • iā€™m listing only lights which belong to any area
  • iā€™m listing only areas which actually contain lights

Could be achieved by auto-entities using jinja.

Does your stack of cards update states when light entities are updated in background?

Not exactly, I forgot to mention that I actually started with that.

With auto-entities I can list entities belonging to an area, BUT I cannot have a vertical-stack with dynamic list of areas ā†’ I used to list the areas manuallyā€¦ Soā€¦ by looking for a solution, Iā€™ve stumbled upon config-template-card and card-templater.

Yes :slight_smile:

Well, you can actually, like this simple case:

type: custom:auto-entities
card:
  type: grid
  columns: 2
  square: false
card_param: cards
filter:
  template: |-
    {% for AREA in areas() -%}
      {{
        {
          'type': 'area',
          'area': AREA
        }
      }},
    {%- endfor %}
1 Like

So, you claim that CTC placed inside card-templater DOES NOT require the ā€œentitiesā€ option defined with all used entities? (in your example you listed only ā€œsun.sunā€)

Yes, I donā€™t know why. Magic xD

At least in my example. Maybe there is something specific here, maybe itā€™s universal, idk xD

Not using card-templaterā€¦
I agree that this is an interesting educational issue.
And probably the explanation is simple:

  1. CTC needs to be ā€œpushedā€ - and on every push CTC updates (fully redraws) an inner card(s).
  2. Traditionally an update of monitored entity causes a ā€œpushā€. ā€œMonitoredā€ - means defined in ā€œentitiesā€ option.
  3. Card-templater listens to hass & updates the inner card on ā€œeveryā€ change of hass. ā€œEveryā€ probably means ā€œonly neededā€ - i.e. the card listens to entities defined in ā€œ_templateā€ options.
  4. Since here there is no ā€œ_templateā€ options - the card-templater probably updates the inner card on EVERY change of hass - even unrelated to your lights. Guess this is a waste of resources.

I would suggest not to place CTC into card-templater.
Use CTC only for small applications. Replace it with auto-entities or card-templater where possible.

As for your lights - check this quick demo (could be enriched ofc):

type: custom:auto-entities
card:
  type: grid
  columns: 2
  square: false
card_param: cards
filter:
  template: |-
    {% for AREA in areas() -%}
      {%- set ENTITIES = area_entities(AREA) | select('search','light.') | list -%}
      {{
        {
          'type': 'entities',
          'title': AREA,
          'entities': ENTITIES
        }
      }},
    {%- endfor %}
1 Like

Hah! Youā€™re right! Iā€™ve asked how to do it on discord, but nobody answered ā†’ so Iā€™ve just wasted a few good hours on that. At least Iā€™ve learnt a lot and discovered the ā€œhackā€ :wink:

Here is the full auto-entities version: working like a charm as well, much simpler, with no hacks and JS:

type: custom:auto-entities
card:
  type: vertical-stack
card_param: cards
filter:
  template: |-
    {% for AREA in areas()|sort -%}
      {{
        {
          'type': 'custom:auto-entities',
          'card': {
            'type': 'entities',
            'state_color': true,
            'show_header_toggle': true,
            'title': area_name(AREA)
          },
          'show_empty': false,
          'filter': {
            'include': [
              {
                'domain': 'light',
                'area': AREA,
                'options': {
                  'secondary_info': 'last-changed'
                }
              }
            ]
          }
        }
      }},
    {%- endfor %}

The inner auto-entities not needed (even a harmful complication).
You can do everything in one template.
Here you got a template card inside a template card, like dream within a dream in ā€œInceptionā€