Entities with low battery template, state of some entities are strings rather than integers, help!

Hi, I’m using the following template with the auto-entities card to display a list of devices with low battery:

type: custom:auto-entities
card:
  type: entities
  title: Low Battery
filter:
  template: |-
    {{ states.sensor | selectattr("entity_id", "search", ".*_battery_level") 
      | selectattr("state", "is_number")
      | selectattr("state", "le", "20")
      | rejectattr("state", "in", ["unavailable", "unknown"])
      | rejectattr("entity_id", "search", ".*_zwave")
      | rejectattr("entity_id", "search", ".*iphone*")
      | map(attribute="entity_id") | list }}
show_empty: false

The issue I’m having is that I’m seeing some entities in the resulting list with a state of 100% or 100.0%. I think this is because the state of these sensors are strings, rather than integers:

My question is, how could I modify the template above so that I’m testing if the integer of the state of selected entities is less than 20?

Thank you!

It’s not that some are strings and others are integers. The state value of all entities is a string.

The problem is that your template isn’t performing a numeric comparison, it’s doing a string comparison.

| selectattr ("state", "le", "20")

When you compare strings, it’s actually performing an alphanumeric comparison of each character in the string (based on the character’s ASCII code value). In other words the letter A is less than the letter B because A comes before B in the ASCII table. This means if you perform a string comparison of numeric strings, you can get seemingly nonsensical arithmetic results like "100" is less than "20".

Compare the difference between numeric and string comparisons:

The simplest way to fix your template is to reject all sensors whose state value equals "100".

| rejectattr("state", "eq", "100")
| selectattr("state", "le", "20")

If some sensor values are "100" and others are "100.0" then this should eliminate both:

| rejectattr("state", "in", ["100", "100.0"])

Thank you, for the clear and detailed explanation - I learn something new every day :+1:

Modified template now working as expected:

    {{ states.sensor | selectattr("entity_id", "search", ".*_battery_level") 
      | selectattr("state", "is_number")
      | selectattr("state", "le", "20")
      | rejectattr("state", "in", ["100", "100.0"]
      | rejectattr("entity_id", "search", ".*_zwave")
      | rejectattr("entity_id", "search", ".*iphone*")
      | map(attribute="entity_id") | list }}
1 Like

You’re welcome!

Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title which signals to other users that this topic has been resolved. This helps users find answers to similar questions.

For more information about the Solution tag, refer to guideline 21 in the FAQ.