šŸ“ 100% Templatable Lovelace Configurations

The CTC supports templates in JS, not jinja.

1 Like

Is there a website with a bunch of examples and templates in Javascript for Home Assistant?
I have a few jinja templates that I would like to ā€œconvertā€ to Javascript so I can use it with config-template-card.
Kind of like a Javascript equivalent of the Templating - Home Assistant site?

Having a little bit of an issue with one of my cards; I think itā€™s related to 2 characters contained in the URL (ā€™#ā€™ and ā€˜,ā€™. If anyone has any ideas, please let me know. I think my goal is fairly obvious, but if not: Iā€™m trying to create an iframe card that dynamically updates a URL with the reported location. Have tried several variations of this, but the card does not render.

One attempt used the person entity directly:

type: custom:config-template-card
entities:
  - person.main
card:
  type: iframe
  url: >-
    ${"https://www.theweekendest.com/trains#"+states['person.main'].attributes['latitude']","states['person.main'].attributes['longitude']"/12/29"}
  aspect_ratio: 100%

Another attempt, where I created a separate sensor entity in templates.yaml (the state reports as the person.main ā€œā€˜latitudeā€™,ā€˜longitudeā€™ā€ as a string). There is no issue with the sensor, or the output, but the card again fails to render:

type: custom:config-template-card
variables:
  - states['sensor.latlong'].state
entities:
  - sensor.latlong
card:
  type: iframe
  url: ${"https://www.theweekendest.com/trains#"+vars[0]"/12.260497255506714/29"}
  aspect_ratio: 100%

A few other things Iā€™ve tried:

  1. Defining variables (variables:) with names (i.e. LAT:), then referencing the named variables.
  2. Using multiple variables (vars[0]; vars[1], etc.).

Any ideas/suggestions/fixes would be appreciated!

A wrong code, should be like

${ā€œsome stringā€ + states[ā€œsensor.xxxā€].state + ā€œsome stringā€}

I.e. strings are concatenated by ā€œ+ā€

1 Like

And that is why this community is so amazing. I spent a few hours troubleshooting, and was missing the basics. Appreciate the help, and the quick response. Itā€™s working, and dynamically updating the URL to reflect the current location.

Thank you.

1 Like

Thanks @iantrich. Iā€™m very happy with this card. Was looking for something to generate ~30 cards. This one saved the day. My card is still a work in progress. But these are the results so far.

views:
  - title: Energie
    path: energie
    type: sidebar
    badges: []
    cards:
      - type: custom:config-template-card
        entities:
          - sensor.100_import_kwh_since_last_reset
        variables:
          DEVICES: [
            {"address_id": 100, "type": "eastron sdm630", "title": "Hoofdgroep"},
            {"address_id": 101, "type": "abb ev1", "title": "1 - Gang, Douche, Logeerkamer"},
            {"address_id": 102, "type": "abb ev1", "title": "2 - Kantoor, Slaapkamers"},
            {"address_id": 103, "type": "abb ev1", "title": "3 - Keuken 1, bijkeuken, garage"},
            {"address_id": 104, "type": "abb ev1", "title": "4 - Keuken 2"},
            {"address_id": 105, "type": "abb ev1", "title": "Groep 5"},
            {"address_id": 106, "type": "abb ev1", "title": "Groep 6"},
            {"address_id": 107, "type": "abb ev1", "title": "Groep 7"},
            {"address_id": 108, "type": "abb ev1", "title": "Groep 8"},
            {"address_id": 109, "type": "abb ev1", "title": "Groep 9"},
            {"address_id": 110, "type": "abb ev1", "title": "Groep 10"},
            {"address_id": 111, "type": "abb ev1", "title": "11 - Woonkamer 2"},
            {"address_id": 112, "type": "abb ev1", "title": "12 - Zolder"},
            {"address_id": 113, "type": "eastron sdm630", "title": "Warmtepomp binnen"},
            {"address_id": 115, "type": "eastron sdm630", "title": "Warmtepomp buiten"},
            {"address_id": 117, "type": "eastron sdm630", "title": "Kookplaat"},
            {"address_id": 201, "type": "abb ev1", "title": "Servers"},
            {"address_id": 245, "type": "abb ev1", "title": "Vaatwasser"},
            {"address_id": 244, "type": "abb ev1", "title": "Oven"},
            {"address_id": 243, "type": "abb ev1", "title": "Koelkast"}
          ]
        card:
          type: vertical-stack
          title: Actueel overzicht
          cards: |-
            ${
            let cards = [];
            const getDivider = ( title ) => {
                return {
                    'type': 'custom:text-divider-row',
                    'text': title,
                    'align': 'centre',
                    'text-divider-font-size': '20',
                    'text-divider-line-size': '3',
                    'text-divider-margin': '1em 0'
                }
            }

            const getCard = ( state, unit ) => {

                const getColor = () => {
                    let color = '';

                    switch (true) {
                      case (unit === "A"):
                        switch (true) {
                            case (state == 0):
                                color = 'lightgray';
                                break;
                            case (state < q):
                                color = 'green';
                                break;
                            case (state < 6):
                                color = 'blue';
                                break;
                            case (state < 9):
                                color = 'orange';
                                break;
                            case (state => 9):
                                color = 'red';
                                break;
                            default:
                                color = 'purple';
                        }
                        break;

                      default:
                        switch (true) {
                            case (state == 0):
                                color = 'lightgray';
                                break;
                            case (state < 100):
                                color = 'green';
                                break;
                            case (state < 500):
                                color = 'blue';
                                break;
                            case (state < 1000):
                                color = 'orange';
                                break;
                            case (state < 2000):
                                color = 'red';
                                break;
                            default:
                                color = 'purple';
                        }
                    }
                    return color;
                }

                return {
                    'type': 'custom:html-card',
                    'content': `
                                  <div style="display:flex; justify-content:center; color:${ getColor() }" >
                                    <span style="font-size:24px; text-align:ricght;">${ state }</span>
                                    <span style="font-size:20px; opacity:0.5; padding-left:0.5rem;">${ unit }</span>
                                  </div>
                                              `
                }
            }

            const getRow = (index, id) => {
                let entityCards = [];

                entityCards.push( getCard( this.hass.states[`sensor.${id}_phase_${index}_power`].state, 'W' ) );
                entityCards.push( getCard( this.hass.states[`sensor.${id}_phase_${index}_current`].state, 'A' ) );

                return {
                   'type': 'horizontal-stack',
                   'cards': entityCards
               }
            }

            DEVICES.forEach( device => {

                cards.push( getDivider( device.title ) );

                // ------------------------------------------------ //
                if ( device.type === "abb ev1" ) {
                  cards.push( getRow(1, device.address_id) );
                }
                // ------------------------------------------------ //
                if ( device.type === "eastron sdm630" ) {
                    let subCards = [];

                    for ( let i = 1; i < 3 + 1; i++ ) {
                        subCards.push(getRow(i, device.address_id ));
                    }

                    cards.push( {
                        'type': 'vertical-stack',
                        'cards': subCards
                    } );

                }
            } )
            ;

            cards
            }

If anyone has any suggestions. Iā€™m more than open to it, since itā€™s my first try.

I am having issues with the config-template card
I have installed it through hacs and I am trying to create a bin card like in this video https://www.youtube.com/watch?v=RpwAhy7f52I but nothing displays in the preview if i remove lines 1 - 6 the picture entity displays so im guessing there is something wrong with my yaml or the installation of the config-template-card. any help would be great

type: custom:config-template-card
entities:
  - sensor.black_bin_days
variables:
  DAYS: states['sensor.black_bin_days'].atrributes['days']+'d'
card:
  type: picture-entity
  entity: sensor.black_bin_days
  name: ${DAYS}
  show_name: true
  show_state: false
  state_image:
    '0': /local/garbage/general_today.png
    '1': /local/garbage/general_tomorrow.png
    '2': /local/garbage/general_off.png

Post a screenshot from Dev tools ā†’ state for this sensor.

Here you go

Do you see anything after pressing a SAVE button?

do you mean on the edit UI screen? nope just this

Well, I am a bit happier.

type: vertical-stack
cards:
  - type: entities
    entities:
      - input_number.test_number
      - input_number.test_number_2
      - type: section
      - entity: sensor.test_ctc
        name: state
      - entity: sensor.test_ctc
        type: attribute
        attribute: days
        name: attribute
  - type: custom:config-template-card
    entities:
      - sensor.test_ctc
    variables:
      DAYS: states['sensor.test_ctc'].attributes['days'] + ' days'
    card:
      type: picture-entity
      entity: sensor.test_ctc
      name: ${DAYS}
      show_name: true
      show_state: false
      state_image:
        '0': /local/images/test/blue.jpg
        '1': /local/images/test/orange.jpg
        '2': /local/images/test/pink.jpg
template:
  - sensor:
      - name: test_ctc
        state: >-
          {{ states("input_number.test_number")|int(0) }}
        attributes:
          days: >-
            {{ states("input_number.test_number_2")|int(0) }}

Gotta be something with the installation then. Did you install it through hacs?

Hi all, probably doing something stupid here but I canā€™t figure it out. I want to detect the hass.user and then pass a url variable to an iframe card. My config below is not working. I have tried a few different configs but no success:

  - type: "custom:config-template-card"
    variables:
      biuser: |
        biuser => {
          if (hass.user.name == 'officedashboard') {
            return 'user=officepc'
          } else if (hass.user.name == 'Sebastian') {
            return 'user=Sebastian'
          } else {
            return 'user=ipad'
          }
        }
    entities:
      - hass.user.name
    card:
      type: iframe
      url: ${"http://192.168.20.100:81/ui3.htm?" + biuser + "&maximize=1"}

Solved with the below:

  - type: "custom:config-template-card"
    variables:
      biuser: |
        user.name == 'officedashboard' ? 'user=officepc : (user.name == 'Sebastian' ? 'user=sebastian' : ' ')
    entities:
      - user.name
    card:
      type: iframe
      url: ${"http://192.168.20.100:81/ui3.htm?" + biuser + "&maximize=1"}

Hello,

The code for the card is working, but i have a strange thing happening.

Whenever i change the message in the input helper, this card keeps sending previous message one more time, and after that it sends the new message.

When i check in develop tools, the status of the: input_txt.tss is giving the new message. But this card sends first the old message, and after that the second time, it sends the new message.

Someone any idea what this could be?

type: custom:config-template-card
variables:
  Message: states['input_text.tts'].state
entities:
  - media_player.junior
card:
  type: button
  show_name: true
  show_icon: false
  entity: media_player.junior
  name: TTS SEND
  tap_action:
    action: call-service
    service: tts.cloud_say
    target: {}
    data:
      message: ${Message}
      entity_id: media_player.junior

Why am entity which is used inside the CTC is not defined as ā€œmonitoredā€ inside the ā€œentitiesā€ option?

A note about using macros in config-template-card (CTC):

Consider this card:

type: config-template-card
entities:
  - sun.sun
  - sensor.some_sensor
card:
  type: ....
  ... something with sun.sun & sensor.some_sensor

All entities used in an ā€œinner cardā€ should be defined as ā€œmonitoredā€ in the ā€œentitiesā€ option - otherwise the ā€œinner cardā€ will be not updated when some of these entities are changed (unless a user have not defined them as ā€œmonitoredā€ by some purpose).

In HA 2023.4 a support for macros was added.
Consider this (useless) macro:

{% macro DO_SOMETHING(input_SENSOR) -%}
  {{ state_attr(input_SENSOR,'elevation') | float(default=0) + states('zone.home') | int(default=0) }}
{%- endmacro %}

The ā€œinner cardā€ uses this macro like:

DO_SOMETHING('sun.sun')

Here the macro uses the ā€œzone.homeā€ entity - and this entity is not defined as ā€œmonitoredā€.
Means - if the ā€œzone.homeā€ is changed, the ā€œinner cardā€ will be not updated.

Conclusion: when using macros inside CTC - check if any entities are used inside these macros; all (or some) of them should be defined as ā€œmonitoredā€.

Hiā€¦

Trivial question, I want to add this manually, but I canā€™t find ā€œconfig-template-card.jsā€ within the repository on git? ā€¦ Iā€™ve added quite a few custom Lovelace packages, all manually by copying the .jsā€¦ yet I canā€™t find config-template-card.js as per the readme / instructions?

yeeeaaā€¦ where did this come from? ā€¦ Iā€™m not keen to add a random .js from a random link, from a random guy :smiley:

but I appreciate you going to the effort of providing a link if itā€™s legit.