Template not working as expected vs error not supported .. ‘str’ and ‘int’

while i found some solutions so far, I am confused by how a template is working or not working as i get the error above and so far I have not found a solution

{{ states 
| selectattr('entity_id', 'search', '^(binary_sensor|sensor).*temperature.*_temperature|d1_z')  
| selectattr('state' , '<', '8' ) 
| list  }}

(note “” .temperature._temperature|d1_z"" i know is a bit strange but so far it is the best way I have found to ensure I get all the different sensors I have tied to temp)

so for the weird part (i think)
as It is I get some results

[<template TemplateState(<state sensor.temperature_humidity_1_temperature=7.7; state_class=measurement, unit_of_measurement=°C, device_class=temperature, friendly_name=Temperature & Humidity 1 Temperature @ 2025-02-20T16:58:09.129980+01:00>)>]

BUT if i set the ‘8’ to say ‘22’ it gives me nothing which should not be the case… in fact it should give me more sensors (anyting more than “9.9999999” seems to error).
So I tried to set it equal to 22 as a number and I get the error … so I guess I should convert the states to ints or floats (?) but I have so far not found out how to do this either and my tries of including variations of
| float(0)
or
| int(0)
that I have seen around but which so far have been unsuccessful

any tips are appreciated!

It is strange. Post examples of the entity_ids you’re trying to match. We will try to find the optimal regex pattern.

It’s doing exactly what it should because what you specified is not an numeric comparison but a string comparison.

selectattr('state' , '<', '8' ) 

We can fix that after we determine the best regex pattern for your application.

not sure the entity_id’s is the issue - so I would appreciate to focus on the real issue of converting the results to numeric so I can instead of using ‘8’ just use 8 or 10 or 22 (without the quotes)

if you really want to look at the entity_id’s then they include:
sensor.temperature_combined_d1_z
sensor.temperature_humidity_1_temperature
sensor.temperature_humidity_0_temperature
sensor.esphome_web_14637b_temperature_ds18b20_d1_z
the reason for the double temperature is to avoid the humidity sensors :embarrassed: which end in “_humidity” and i did not remember how to specify the end of the regex string.

You can’t because every entity’s state value is a string (it may appear to be a number but it’s stored as a string). It requires converting the numeric strings to numbers (which cannot be done within selectattr but as a separate step). The technique I have in mind requires two passes, both relying on the regex pattern which is why I wanted to optimize it (if feasible).

Please post an example of the humidity sensors that should be excluded.

Alternatively, do you simply want to include every binary_sensor and sensor whose entity_id ends with temperature or d1_z? If so, let me know if this selects only the desired entities and then we can move on to fixing the comparison.

{{ states 
| selectattr('entity_id', 'search', '^(binary_sensor|sensor).*temperature.*(temperature|d1_z)$'
| map(attribute='entity_id")
| list  }}

hi, the selection is working, as it is - and I am ok with it remaining for now. There are other various sensors with temperature in the name that I am avoiding as well by keeping it like this.

I got the code you included to work by changing slightly

{{ states 
| selectattr('entity_id', 'search', '^(binary_sensor|sensor).*temperature.*(temperature$|d1_z)')
| map(attribute='entity_id')
| list  }}

just to change a " to ’ and a missing )

I am very curious how to fix the type for comparison and appreciate your help!

OK, the difference with your version

(temperature$|d1_z)

is that the entity_id can either end with temperature or include d1_z but not necessarily at the end. If that works for you then let’s go with that.

The following template will produce a list of entity_ids and their state values provided the value is less than 22. Each item in the list is a tuple containing an entity_id and its associated state value.

{% set e = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set eid = e | map(attribute='entity_id') | list %}
{% set val = e | map(attribute='state') | map('round', 0) | list %}
{{ zip(eid, val) | selectattr(1, 'lt', 22) | list }}

Test it and I can refine it to meet your exact needs. For example, what do you want the output to look like (because I imagine you didn’t expect a list of tuples). It can be as simple as replacing the last line with this:

{% for x in zip(eid, val) | selectattr(1, 'lt', 22) -%}
{{ x[0] }}: {{ x[1] }}
{% endfor -%}

Or even simpler if you only want the entity_ids.

{{ zip(eid, val) | selectattr(1, 'lt', 22) | map(attribute=0) | list | join('\n') }}

Reference

Templating - zip function

WOW

this is incredible.
I am not sure how you have learned this and but it is amazing and now that I see it I get it I think … i did a search on the map function and found something from sometime ago that you had written :slight_smile:

anyway, I wanted the date as well so I added an extra line/variable

{% set e = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set eid = e | map(attribute='entity_id') | list %}
{% set lup = e | map(attribute='last_updated') | map('format') | list %}
{% set val = e | map(attribute='state') | map('round', 2) | list %}
{{ zip(eid, lup, val) | selectattr(2, 'lt', 10) | list }}

so… the big plan with this is to combine it with other sensors … my ultimate goal is to provide set values for different sensors where if this is not empty it will trigger notifications and save the output value somewhere so i can figure out later what has happened especially when i have intermittent issues (eg temp drops for a short time, or humidity gets too high, or there is moisture detected, or mold levels are high or some other sensor goes off shortly, etc… . and then i want to set warning levels and alarm levels (=DANGER!!))

how would you recommend going about putting it together with a hodge podge of sensors with varying warning/alarm levels of state ouputs?

ok, this is what i did just now and it is almost there it seems… but i will need to store the variable for warning / alarm for each (warning level temp is like 10 and humidity is 60)

{% set eT = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set e1 = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% for e in [eT, e1] %} 
{% set eid = e | map(attribute='entity_id') | list %}
{% set lup = e | map(attribute='last_updated') | map('format') | list %}
{% set val = e | map(attribute='state') | map('round', 2) | list %}
{{ zip(eid, lup, val) | selectattr(2, 'gt', 1) | list }}
{% endfor %}

for now i put in gt 1 just to get it to show the outputs (with that said it puts a bunch of lines between for some reason?)

woohoo… getting closer!!!

{% set eT = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set eH = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set lvls = [[eT, 'lt', 10, 6], [eH, 'gt', 60, 65]] %} 
{% set count = namespace(value=0) %} 
{% for e in [eT, eH] %} 
{% set eid = e | map(attribute='entity_id') | list %}
{% set lup = e | map(attribute='last_updated') | map('format') | list %}
{% set val = e | map(attribute='state') | map('round', 2) | list %}
{{ zip(eid, lup, val) | selectattr(2, lvls[count.value][1], lvls[count.value][2]) | list }}
{% set count.value = count.value + 1 %}
{% endfor %}

this lets me put the warning and alarm levels into the list lvls and use them to get values later on! maybe not the best way (the whole namespace thing was a head scratcher) but it seems to be mostly working … just to put it all into a single string I think.

ok… so i have continued and i think i now have it … i have put this trimmed value as a sensor (limit seems to be 255 characters…so i am trying to see if this will be enough)

{% set eT = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set eH = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set lvls = [[eT, 'lt', 7, 6], [eH, 'gt', 60, 65]] %} 
{% set count = namespace(value=0) %} 
{% set results = namespace(items=[]) %}
{% for e in [eT, eH] %} 
{% set eid = e | map(attribute='entity_id') | list %}
{% set val = e | map(attribute='state') | map('round', 2) | list %}
{% set result = zip(eid, val) | selectattr(1, lvls[count.value][1], lvls[count.value][2]) | list %}
{% set count.value = count.value + 1 %}
{% set results.items = results.items + result %}
{% endfor %}
{% if results.items | count == 0  %}
  {{ 'ok' }}
{% else %}
  {% set count = namespace(value=0) %} 
  {% set resultsfinal = namespace(items=[]) %}
  {% for itm in results.items %}
    {% set resultsfinal.items = resultsfinal.items + [itm[0].split('.')[1]] %}
    {% set count.value = count.value + 1 %}
  {% endfor %}
  {{ resultsfinal.items }}
{% endif %}

this with me messing with the set warning levels gives me changes that I want to see and then can then use (hopefully) to follow up with later, but i max out on characters quickly (5 sensors :frowning: ) , eg:

questions for anyone more knowledgeable

  1. is there a way to get more than 255 characters (in the wost case i may have 20 sensors on this list once i have built it all out! … so given that 2 warnings is like 75-100… that is like 2000 characters! … and now i max out with like 4 or 5
  2. is there a more elegant way to code this maybe?

@123 I feel like you really have helped me, I really appreciate it!!! Thank you!

and i read some articles now that it should be possible with more characters in an attribute … so instead of using the template sensor helper i tried loading it into configuration.yaml … but it just outputs unknown, any ideas?

      - name: flag sensor status warning
        state: >
            {% set eT = states
              | selectattr('domain', 'in', '(sensor|binary_sensor)')
              | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
              | selectattr('entity_id', 'has_value') 
              | list %}
            {% set eH = states
              | selectattr('domain', 'in', '(sensor|binary_sensor)')
              | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
              | selectattr('entity_id', 'has_value') 
              | list %}
            {% set lvls = [[eT, 'lt', 7, 6], [eH, 'gt', 60, 65]] %} 
            {% set count = namespace(value=0) %} 
            {% set results = namespace(items=[]) %}
            {% for e in [eT, eH] %} 
            {% set eid = e | map(attribute='entity_id') | list %}
            {% set val = e | map(attribute='state') | map('round', 2) | list %}
            {% set result = zip(eid, val) | selectattr(1, lvls[count.value][1], lvls[count.value][2]) | list %}
            {% set count.value = count.value + 1 %}
            {% set results.items = results.items + result %}
            {% endfor %}
            {% if results.items | count == 0  %}
              {{ 0 }}
            {% else %}
              {% set count = namespace(value=0) %} 
              {% set resultsfinal = namespace(items=[]) %}
              {% for itm in results.items %}
                {% set resultsfinal.items = resultsfinal.items + [itm[0].split('.')[1]] %}
                {% set count.value = count.value + 1 %}
              {% endfor %}
              {{ resultsfinal.items | count }}
            {% endif %}
        attributes:
            detail: >-
                {{ resultsfinal.items | list }}

?

The Jinja2 variable named resultsfinal is defined in the Template Sensor’s state option. It’s undefined outside of the state option. In other words, its scope is limited to the option where it is defined.

There are two ways to circumvent this restriction (to avoid having to duplicate the template).

  1. You can create a Jinja2 macro. When you call the macro, it is evaluated at that moment. Currently, your template is being automaticallly evaluated whenever an entity’s state changes (subject to rate limitations, once per minute, because your template uses states which represents all entities in the state machine). Given that a macro does nothing until it’s called, you would have to switch from using a Template Sensor to a Trigger-based Template Sensor and have it employ a Time Pattern Trigger (set to trigger periodically like, say, once a minute).

  2. You can use a Trigger-based Template Sensor (like in the first suggestion) but instead of using a macro, you simply define a script variable in the action section of the Trigger-based Template Sensor. A script variable can be referenced in state and attributes.

1 Like

thank you!

question… as something is not going as expected… as I understood your advice to avoid doubling the code I could create a macro, right? so as a first step I tried to just copy the code and it still just returns “unknown” - is this to be expected?

code I have copied to the attribute section that I am attempting to call “detail” is slightly different to output instead of count the list of entities - please see below:

      - name: flag sensor status warning
        state: >
            {% set eT = states
              | selectattr('domain', 'in', '(sensor|binary_sensor)')
              | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
              | selectattr('entity_id', 'has_value') 
              | list %}
            {% set eH = states
              | selectattr('domain', 'in', '(sensor|binary_sensor)')
              | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
              | selectattr('entity_id', 'has_value') 
              | list %}
            {% set lvls = [[eT, 'lt', 7, 6], [eH, 'gt', 60, 65]] %} 
            {% set count = namespace(value=0) %} 
            {% set results = namespace(items=[]) %}
            {% for e in [eT, eH] %} 
            {% set eid = e | map(attribute='entity_id') | list %}
            {% set val = e | map(attribute='state') | map('round', 2) | list %}
            {% set result = zip(eid, val) | selectattr(1, lvls[count.value][1], lvls[count.value][2]) | list %}
            {% set count.value = count.value + 1 %}
            {% set results.items = results.items + result %}
            {% endfor %}
            {% if results.items | count == 0  %}
              {{ 0 }}
            {% else %}
              {% set count = namespace(value=0) %} 
              {% set resultsfinal = namespace(items=[]) %}
              {% for itm in results.items %}
                {% set resultsfinal.items = resultsfinal.items + [itm[0].split('.')[1]] %}
                {% set count.value = count.value + 1 %}
              {% endfor %}
              {{ resultsfinal.items | count }}
            {% endif %}
        attributes:
            detail: >-
                {% set eT = states
                  | selectattr('domain', 'in', '(sensor|binary_sensor)')
                  | selectattr('object_id', 'search', '.*temperature.*(temperature$|d1_z)')
                  | selectattr('entity_id', 'has_value') 
                  | list %}
                {% set eH = states
                  | selectattr('domain', 'in', '(sensor|binary_sensor)')
                  | selectattr('object_id', 'search', '.*temperature.*(humidity$)')
                  | selectattr('entity_id', 'has_value') 
                  | list %}
                {% set lvls = [[eT, 'lt', 7, 6], [eH, 'gt', 60, 65]] %} 
                {% set count = namespace(value=0) %} 
                {% set results = namespace(items=[]) %}
                {% for e in [eT, eH] %} 
                {% set eid = e | map(attribute='entity_id') | list %}
                {% set val = e | map(attribute='state') | map('round', 2) | list %}
                {% set result = zip(eid, val) | selectattr(1, lvls[count.value][1], lvls[count.value][2]) | list %}
                {% set count.value = count.value + 1 %}
                {% set results.items = results.items + result %}
                {% endfor %}
                {% if results.items | count == 0  %}
                  {{ 'ok' }}
                {% else %}
                  {% set count = namespace(value=0) %} 
                  {% set resultsfinal = namespace(items=[]) %}
                  {% for itm in results.items %}
                    {% set resultsfinal.items = resultsfinal.items + [itm[0].split('.')[1]] %}
                    {% set count.value = count.value + 1 %}
                  {% endfor %}
                  {{ resultsfinal.items | list }}
                {% endif %}

shouldn’t this work?

Just to clarify, when you look in Developer Tools → States, you see sensor.flag_sensor_status_warning
and it has a valid state value but the value of its detail attribute is unknown?

here:

I checked the two pieces separately in the template tool and both seem to output as I should expect a number and a string respectively

---- edit:
boneheaded me put it after a sensor… that had a trigger ahead of it… when I set it correctly in the config.yaml it is now working it seems!

deleted … see edit above … i made a mistake in the config…yaml so it had been in the context of a trigger sensor :S

Can you summarize what your lengthy template is computing?

Is it a count of all temperature and humidity sensors that are below/above a threshold value?

the idea is now to output a count and the actual sensors that have met the criteria and the idea is to add a bunch more sensors and split between those meeting the criteria of warning and alarm levels.

more detail:well, it started as I really liked the easy of combining things in the dashboard with auto-entities which I could not figure out how to make trigger a notification… and I thought it would be even better if the even relatively momentary output could be tracked (now working but ultimately I would like to constantly build up all entiteis that have warned/alarmed until cleared so I get a to-do list of warnings/alarms to check and analyze and decide to do something or not about it).

i want to get a flag with sensors that meet two values (currently I am just checking warning level)

  1. warning level -
  2. alarm level - act now!
    (the reason I have two values in each list related to it the first is warning the second alarm)
    sensors have varying values and priority … some are always alarms (eg leaks)

it will include

  • temperature
  • humidity
  • mold
  • motion
  • leaks (always alarm)
  • septic alarm
  • water filter system sensors
  • battery levels of sensors
  • solar warnings/alarms
  • solar battery warnings/alarms

My hope has been also to use this to learn and to automate the adding of sensors as I build out the system and learn more

if you have any advice let me know!

OK, I think I now have a better understanding of your requirements (a bit more complex than what was stated in the first post :wink:).

Copy-paste the following into the Template Editor and confirm it reports correct results.

{% set all = states
  | selectattr('domain', 'in', '(sensor|binary_sensor)')
  | selectattr('entity_id', 'has_value') 
  | list %}
{% set ref = [
  {'name': 'temperature',
   'pattern': '.*temperature.*(temperature$|d1_z)',
   'operator': 'lt',
   'threshold': 7},
  {'name': 'humidity',
   'pattern': '.*temperature.*(humidity$)',
   'operator': 'gt',
   'threshold': 60} ] %}
{% set ns = namespace(e=[]) %}
{% for r in ref -%}
  {% set e = all | selectattr('object_id', 'search', r.pattern) | list -%}
  {% set eid = e | map(attribute='entity_id') | list -%}
  {% set val = e | map(attribute='state') | map('round', 2) | list -%}
  {% set ns.e = ns.e + zip(eid, val) | selectattr(1, r.operator, r.threshold) | list -%}
{% endfor -%}

Qty: {{ ns.e | count }}
Entities: {{ ns.e | map(attribute=0) | list }}

The variable ref contains a list with two dictionary values (key-value pairs). You can add dictionary values for other type of entities (mold, motion, etc). You can also add more keys to each dictionary value should you have additional requirements.

wow, that is incredible it defiantly works. I even flexed it by changing the threshold values … as you are probably well aware it allows for more than 255 characters as well.

one thing I had done on the side but had not shared was the managing of on/off state alarms … I solved it with an if else (as an inline-if I was unable to solve the syntax on to avoid the rounding :embarassed: ) :

{% if e != eSW %}
    {% set val = e | map(attribute='state') | map('round', 2) | list %}
  {% else %}
    {% set val = e | map(attribute='state') | list %}
  {% endif %}

If you do not suggest something better I will adjust to integrate based on instead the threshold being “on” or “off”?

example of what I think such a sensor group would like like in the dictionary format here :

,
  {'name': 'septic and water',
   'pattern': '.*septic_tank|_uv_relay_off|filter_flow',
   'operator': 'eq',
   'threshold': 'on'} 
   ] %}