Template with custom_templates import does not update correctly

Yes I can see/do that.

My point is the sensor does not return the same output as the dev template with the exact same yaml . I don’t understand why that is, or how to fix that

seems the template: engine is just not properly evaluating those in the backend, and the dev tools template is.
(btw, this is a regular template sensor, not a trigger based template, so that cause can be ruled out)

I’ve already explained it. A set does not execute code. It’s already set. When you import it, it does not run it. It just gets the value that it has. You have to use a macro to run anything. And because you have to use a macro, you have to account for the output always being a string when you use the macro.

You can also doe | to_json at the end of the macro, and then | from_json when using it in a template

eg:

{%- macro alerts -%}
{{- expand(state_attr('binary_sensor.alerts','entity_id'))
               |selectattr('state','eq','on')|map(attribute='name')|list | to_json -}}
{%- endmacro -%}
{% from 'alerts.jinja' import alerts %}
{{ alerts | from_json }}

I would also reccomend to add hyphens everywhere you can in the macro, to avoid whitespace issues.

Yes but that’s running potentially expensive operations when a split on a comma separated list isn’t too expensive.

Personally, I use to/from json as a last resort. I make all my macros perform the operations with simple returned values.

1 Like

wasn’t aware that there is such a difference in these operations

To_json has to touch every object inside what your turning into json and from_json does as well.

so I changed that to:

{% macro alerts_macro() %}
{{ expand(state_attr('binary_sensor.alerts','entity_id'))
               |selectattr('state','eq','on')|map(attribute='name')|list }}
{% endmacro %}

but that makes

{% from 'alerts.jinja' import alerts_macro %}
{{ alerts_macro }}

return
<Macro ‘alerts_macro’>

maybe I am just better off using the this variable in these type of templates.

at least this works:

      - unique_id: alerts_notifying_this
        state: >
          {{this.attributes.alerts|count}}
        name: >
          {% set count = this.state|int(default=-1) %}
           {% set phrase = 'Alert' if count == 1 else 'Alerts' %}
           {{count}} {{phrase}} actief
        icon: >
          {% set count = this.state|int(default=-1) %}
          mdi:numeric-{{count}}-box
        attributes:
          alerts: >
            {{ expand(state_attr('binary_sensor.alerts','entity_id'))
               |selectattr('state','eq','on')|map(attribute='name')|list }}
          message: >-
            {% set count = this.state|int(default=-1) %}
            {% set alerts = this.attributes.get('alerts') %}
            {%- if count == 0 -%} Ok, geen alerts, alles is in orde
            {%- elif count == 1 -%}{{count}} Alert: {{alerts[0]}}
            {%- elif count == 2 -%}
              {{count}} Alerts: {{alerts[0]}} en {{alerts[1]}}
            {%- else -%}
              {{count}} Alerts:{{alerts[:-1]|join(', ')}}, en {{alerts[-1]}}
            {%- endif %}

… I am not sure though if this is just as efficient as using the custom_templates. as in, whether the attribute is evaluated only once, and not in every single config option of the template sensor

You’re missing () in your macro call

a yes that helps

but nw I have no way to count or iterate…

what should I change in the macro:

{% macro alerts_macro() %}
{{ expand(state_attr('binary_sensor.alerts','entity_id'))
               |selectattr('state','eq','on')|map(attribute='name')|list }}
{% endmacro %}

to be able to do that?

Yes that will work but then you have to split the output…

arghh, getting better, not quit there yet…

{% from 'alerts.jinja' import alerts_macro %}
{{ alerts_macro().split(',') }}


{% set count = alerts_macro().split(',')|count %}
{% set alerts = alerts_macro().split(',') %}
{%- if count == 0 -%} Ok, geen alerts, alles is in orde
{%- elif count == 1 -%}{{count}} Alert: {{alerts[0]}}
{%- elif count == 2 -%}
  {{count}} Alerts: {{alerts[0]}} en {{alerts[1]}}
{%- else -%}
  {{count}} Alerts:{{alerts[:-1]|join(', ')}}, en {{alerts[-1]}}
{%- endif %}

native the odd new lines, and the listing notation in the bottom part

yes I did that now, and still producing:

["['Hall'", " 'Humidity Living low'", " 'Climate living alert']"]



3 Alerts:['Hall',  'Humidity Living low', en  'Climate living alert']

Ensure your macro template ends with join(',')

{%- macro alerts_macro() -%}
{{ expand(state_attr('binary_sensor.alerts','entity_id'))
  |selectattr('state','eq','on')|map(attribute='name')|list|join(',') }}
{%- endmacro -%}
1 Like

that is getting better again:

{% from 'alerts.jinja' import alerts_macro %}
{{ alerts_macro().split(',')}}


{% set count = alerts_macro().split(',')|count %}
{% set alerts = alerts_macro().split(',') %}
{%- if count == 0 -%} Ok, geen alerts, alles is in orde
{%- elif count == 1 -%}{{count}} Alert: {{alerts[0]}}
{%- elif count == 2 -%}
  {{count}} Alerts: {{alerts[0]}} en {{alerts[1]}}
{%- else -%}
  {{count}} Alerts: {{alerts[:-1]}}, en {{alerts[-1]}}
{%- endif %}

adding

  {{count}} Alerts: {{alerts[:-1]|join(', ')}}, en {{alerts[-1]}}

finally resulting in:

Please, can you go back to my original response and reread it? I already explained everything you need to do in the first post. End your macro with a join, and split the macros result.

This post here

1 Like

yes, thanks Petro and 123, sometimes one has to go over things oneself to truly grasp.

for the sake of completeness/reference:

wat is your opinion on this final template sensor using the macro in the custom_templates, compared to the version with the this variable, from an efficiency perspective?

I started this whole migration with that in mind after all…

Tip:

If you use join(', ') at the end of your macro’s template (that’s a comma and a space) then you can use this:

{% set alerts = alerts_macro().split(', ') %}
{% set count = alerts|count %}
{%- if count == 0 -%} Ok, geen alerts, alles is in orde
{%- else -%}
{{count}} Alert{{iif(count > 1, 's','')}}: {{' en '.join(alerts_macro().rsplit(', ', 1))}}
{%- endif %}

It takes advantage of the template in this post:

1 Like

not yet there just yet…

consider this macro:

{%- macro critical_off() -%}
{{- expand(state_attr('switch.critical_switches','entity_id'))
                       |selectattr('state','eq','off')
                       |map(attribute='name')
                       |list|join(',') -}}
{%- endmacro -%}

and then no switches are off. this results in:


using:

      - unique_id: critical_switches_offline
        state: >
          {% from 'alerts.jinja' import critical_off %}
          {{critical_off().split(',')|count}}
        name: >
          {% from 'alerts.jinja' import critical_off %}
          {% set count = critical_off().split(',')|count %}
          {% set phrase = 'switch' if count == 1 else 'switches' %}
          {{count}} Critical {{phrase}} offline
        icon: >
          {% from 'alerts.jinja' import critical_off %}
          {% set count = critical_off().split(',')|count %}
           mdi:numeric-{{count}}-box
        attributes:
          message: >-
            {% from 'alerts.jinja' import critical_off %}
            {% set critical = critical_off().split(',') %}
            {% set count = critical_off().split(',')|count %}
            {%- if count == 0 -%} Ok, all critical switches are online
            {%- elif count == 1 -%}{{count}} Critical switch offline: {{critical[0]}}
            {%- elif count == 2 -%}
              {{count}} Critical switches offline: {{critical[0]}} and {{critical[1]}}
            {% else  %}
              {{count}} Critical switches are offline: {{critical[:-1]|join(', ')}}, and {{critical[-1]}}
            {% endif %}

cant it handle an empty list?, and the split there causing the empty list to be [''] which returns 1 when |count that. Note there is NO switch listed after the 1 Critical switch offline: (and that is actually correct)

It’s ok when I actually turn off 1:

Note the Koelkast keuken as listing of the entity