How to filter outliers from espHome / Template sensor

Hi all,

Very much enjoying getting stuck into HA and I’ve recently been getting into the espHome stuff. I’ve got a esp8266 board running in the cellar which reads an ultrasonic sensor and controls a relay. I applied some filters to the sensor to remove the outliers which is working nicely. Here’s the code I’m using in espHome:

sensor:
  - platform: ultrasonic
    trigger_pin: D6
    echo_pin: D5
    name: "Dehumid Tank Ultrasonic Sensor"
    update_interval: 20s
    accuracy_decimals: 4
    filters:
      - median: 
          window_size: 3
          send_every: 3
          send_first_at: 3
      - lambda: |-
          float MIN_VALUE = 0.05;
          float MAX_VALUE = 0.4;
          if (MIN_VALUE <= x && x <= MAX_VALUE) return x;
          else return {};
      - sliding_window_moving_average:

As I wanted to keep the ‘raw’ distance data coming into HA as well as monitoring the tank fill level I added a template sensor with this code:

template:
    - sensor:
        - name: "dehumid_tank_percentage"
          unit_of_measurement: "%"
          filters:
            - lambda:
          state: >
            {% set range = states('sensor.dehumid_tank_ultrasonic_sensor') | float %}
            {% set full = 0.05 | float %}
            {% set empty = 0.4 | float %}
            {{ ((empty - range) / (empty - full) * 100) | round(1) }}

The issue I have is that when the espHome gets an invalid reading it sends a null value to HA. When the template sensor updates, it reads this as zero and thus outputs a percentage fill of 114.3 %.

I’ve tried various things but how can I either return the previous value or send another null value from the template sensor?

Thanks!

James

1 Like

Hi there, Can you try this template. It should prevent updating your HA sensor when the value is 0.

template:
    - sensor:
        - name: "dehumid_tank_percentage"
          unit_of_measurement: "%"
          filters:
            - lambda:
          state: >
            {% if states('sensor.dehumid_tank_ultrasonic_sensor')| float > 0 %}
            {% set range = states('sensor.dehumid_tank_ultrasonic_sensor') | float %}
            {% set full = 0.05 | float %}
            {% set empty = 0.4 | float %}
            {{ ((empty - range) / (empty - full) * 100) | round(1) }}
            {%else%}
            {{states('sensor.dehumid_tank_percentage')}}
            {% endif %}

If you want you can even specifiy a range for sensor.dehumid_tank_ultrasonic_sensor by making the condition line like below.

{% if states('sensor.dehumid_tank_ultrasonic_sensor')| float > 0 and states('sensor.dehumid_tank_ultrasonic_sensor')| float < 99 %}

You can also change the esphome script and only update the Dehumid Tank Ultrasonic Sensor when the value is above a range.

Awesome thanks for your quick reply. I’ve added it to my config and will see how it settles. Can I just ask what the else line does here. When the sensor sends a null reading, will it return 0 % or the last value for the percentage (ie not update it)?

The last value before the sensor turns to zero.

1 Like

Great example, Wally2k21. just what I was lookin for.

I believe there is also a filter_out: nan option