Show sensor with battery level below a threshold

I’m trying to get a list of Sonoff sensors with battery level lower than a threshold.

Battery level is stored in sensor entities like: sensor.sonoff_a48430ce1b_battery.

If I create a template like this:

{{states.sensor  | selectattr('entity_id', 'search', 'sensor.sonoff') 
                  | selectattr('entity_id', 'search', 'battery') 
                  | map(attribute='state') | list}}

I obtain an output like this:

['unavailable', '8', '100', '100', '100', '99', '100', '100', '74', '81', '100', '56', '100', '100', '81', '100', '73', '100', '83', '75', '85', '82', '100', '80', '100', '100', '76', '100', 'unavailable', '65', '70', '68', '71', 'unavailable', 'unavailable', '76', '81', 'unavailable', '100', '100', '100', '80']

What I’d like is to filter and only obtain the sensor with battery level below some fixed threshold.

I’ve tried something like:

{{states.sensor  | selectattr('entity_id', 'search', 'sensor.sonoff') 
                  | selectattr('entity_id', 'search', 'battery') 
                  | selectattr('state', '<=', '50') 
                  | map(attribute='state') | list}}

But it doesn’t work as intended. The oputput is:

['100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100', '100']

I suppose that the problem is that the comparison is made between strings and not ints.

How can I make the comparison between ints?

Thank you!

Try this:

{{states.sensor  | selectattr('entity_id', 'search', 'sensor.sonoff') 
                  | selectattr('entity_id', 'search', 'battery') 
                  | rejectattr('state', 'eq', 'unknown') 
                  | selectattr('state', 'lt', '50') 
                  | map(attribute='state') | list}}
1 Like

I get the same output with all the '100’s.

The problem is that within strings:

{{ '100' > '10' }}
True

But

{{'100' > '50'}}
False
{{'100' > '2'}}
False

Yeah ok, comparing strings not numbers. Fortunately you only have one number that is a problem child (100%), so:

{{states.sensor  | selectattr('entity_id', 'search', 'sensor.sonoff') 
                  | selectattr('entity_id', 'search', 'battery') 
                  | rejectattr('state', 'eq', 'unknown') 
                  | rejectattr('state', 'eq', '100') 
                  | selectattr('state', 'lt', '50') 
                  | map(attribute='state') | list}}

The other way to do it is to iterate, like at the end of this:

Which would be advantageous if you had more than one two digit number in your list.

1 Like

I think I’ll have to iterate as you suggest, because ‘8’ (‘9’, ‘7’, ‘6’) is “bigger” than ‘50’.

I’ll look at iteration tomorrow.

Thank you!

1 Like

Ah yeah. So they are.

Hold up. Try this:

{{states.sensor | selectattr('entity_id', 'search', 'sonoff.*battery') 
                | map(attribute='state')
                | map('int', 101)
                | select('lt', 50)
                | list}}

If there is anything that can’t be converted to an integer it will be replaced with 101 and thus will not be selected by the less than test.

Shamelessly adapted from this:

1 Like

Thank you!

This works perfectly :slight_smile:

1 Like

I also wanted to get the name or entity_id of the sensors with low battery. In this case, the solution as you said in your first message, is to iterate:

{% set entities = states.sensor | selectattr('entity_id', 'search', pattern)
  | list %}
{% for x in entities if x.state|int(101) < 50 %}
  {%- if not loop.first %}, {% endif -%}
  {{- x.name -}}
{% endfor %}
{% set entities = states.sensor | selectattr('entity_id', 'search', pattern)
  | list %}
{% for x in entities if x.state|int(101) < 50 %}
  {%- if not loop.first %}, {% endif -%}
  {{- x.entity_id -}}
{% endfor %}

Hi,
i’m trying this code with no luck for a telegram notification:

service: telegram_bot.send_message
data:
  message: >
    {{states.sensor | selectattr('entity_id', 'search',
    'cover.rolling_shutter_switch_1_window_covering') 
                    | map(attribute='current_position')
                    | map('int', 101)
                    | select('lt', 100)
                    | list}}

Sensors are these, highlighted the attribute which I want to filter (lower than 10% of opening):

Thanks!