OUTLIER filter does not filter

Hello.
i am reading the values from a temperature sensor. Sometimes the sensor sends very high values. (e.g. 6000 C°). This mess up my history graph card. So i implemented a filter sensor but it seems this does not filter correctly my data. I want to filter all values over 60 C°. This is my filter:

- platform: filter
  unique_id: "heizung_aussentemperatur_gefiltert" 
  name: "Außentemperatur (C°)"
  entity_id: sensor.heizung_aussentemperatur
  filters:
      - filter: outlier
        window_size: 4
        radius: 60.0
      - filter: lowpass
        time_constant: 5
        precision: 2

Can somebody tell me why my filter does not filter correctly?

That will allow any value from the 4 sample average of your sensor’s current state +/- 60.

So if your sensor reads 1000, 1000, 1000, 1000 then the next allowable value could be 940 to 1060.

Oh, ok. I think this could be the solution. I will give it a try. :slight_smile: Thank you very much!
One additional question: If i set the window_size to 40 for e.g, and it has read 40 samples, then it will drop the first sample of the 40 and adds the new sample at the end, right?

[0] = 600, [1] = 650, [1] = 850,… [40] = 345
now a new high value is added and the new range looks like this, right?
[0] = 650, [1] = 850, …[40] = 2000

Or would it be better not to use the window_size property?

hmmmm… i have read your answer now twice. So if set a radius value of 60 and a window_size of 1 and the sensor reads the value 6000, then 5940 is allowed?
But how can i set a maximum and a minimum? How can i set a filter which ignores all values over 60 °C and below -60 °C?

Seems the range filter is the better choice for this task.

But it is not he best solution, because it replaces the outbound values with the upper/lower bound value, what will cause strange spikes in a diagram. A “ignore” values filter would be the best but there is no such filter.

I have not got the outlier filter to work correctly yet either.

This is my filtered sensor:

- platform: filter
  name: "All appliances energy"
  entity_id: sensor.appliances_plus_computer_energy
  unique_id: sensor.filtered_appliances_plus_computer_energy
  filters:
    - filter: outlier
      window_size: 20
      radius: 1.0

The source sensor is a whole load of energy sensors (Shelly devices and Aqara outlets):

- sensor:
  - name: "All appliances energy"
    unique_id: sensor.appliances_plus_computer_energy
    state: >
      {% set energy = states('sensor.shelly_2pm_plus_kitchen_switch_1_energy') | float(0)
      + states('sensor.shelly_2pm_plus_kitchen_switch_0_energy') | float(0)
      + states('sensor.shelly_1pm_plus_dishwasher_switch_0_energy') | float(0)
      + states('sensor.shelly_1pm_plus_fridges_switch_0_energy') | float(0)
      + states('sensor.shelly_2pm_plus_laundry_switch_0_energy') | float(0)
      + states('sensor.shelly_2pm_plus_laundry_switch_1_energy') | float(0)
      + states('sensor.freezer_outlet_energy') | float(0)
      + states('sensor.electrical_cabinet_outlet_energy') | float(0)
      + states('sensor.internet_outlet_energy') | float(0)
      + states('sensor.tv_outlet_energy') | float(0)
      + states('sensor.office_outlet_energy') | float(0) %}
      {{ energy }}
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

But I still occasionally get sensor total values creeping into the statistics which seem to be from restarts of HA. I’ve had multiple erroneous values today from morning and evening restarts.

Normal values are expected in the range of 0.01 - 0.1 kWh:

However, the abnormal values are in the 100 - 1000 kWh range. From the explanation that @tom_l gave, I would expect this outlier filter to eliminate those values…

Add an availability template to that instead of trying to filter it.

Yeah that is definitely a step in the right direction. Now my sensors seem to have less garbage values and I think I finally understand availability templates.

However with the following availability template, the sensor is still quite brittle because I’ve noticed that if a device upgrades (particularly the Shellys) then it’s data will typically be reset, meaning my availability template will return false until I go back to edit the sensor to correct for the new value. :frowning:

Is there a better way to handle that situation than what I am doing below?

- sensor:
    - name: "All appliances energy"
      unique_id: sensor.appliances_plus_computer_energy
      state: >
        {% set energy = states('sensor.shelly_2pm_plus_kitchen_switch_1_energy') | float(0)
        + states('sensor.shelly_2pm_plus_kitchen_switch_0_energy') | float(0)
        + states('sensor.shelly_1pm_plus_dishwasher_switch_0_energy') | float(0)
        + states('sensor.shelly_1pm_plus_fridges_switch_0_energy') | float(0)
        + states('sensor.shelly_2pm_plus_laundry_switch_0_energy') | float(0)
        + states('sensor.shelly_2pm_plus_laundry_switch_1_energy') | float(0)
        + states('sensor.freezer_outlet_energy') | float(0)
        + states('sensor.electrical_cabinet_outlet_energy') | float(0)
        + states('sensor.internet_outlet_energy') | float(0)
        + states('sensor.tv_outlet_energy') | float(0)
        + states('sensor.office_outlet_energy') | float(0) %}
        {{ energy }}
      availability: >
        {{ states('sensor.shelly_2pm_plus_kitchen_switch_1_energy') | float(0) > 3.0
        and states('sensor.shelly_2pm_plus_kitchen_switch_0_energy') | float(0) > 2.5
        and states('sensor.shelly_1pm_plus_dishwasher_switch_0_energy') | float(0) > 1.2
        and states('sensor.shelly_1pm_plus_fridges_switch_0_energy') | float(0) > 3.5
        and states('sensor.shelly_2pm_plus_laundry_switch_0_energy') | float(0) > 10.4
        and states('sensor.shelly_2pm_plus_laundry_switch_1_energy') | float(0) > 9.3
        and states('sensor.freezer_outlet_energy') | float(0) > 135.0 
        and states('sensor.electrical_cabinet_outlet_energy') | float(0) > 187.0
        and states('sensor.internet_outlet_energy') | float(0) > 448.0
        and states('sensor.tv_outlet_energy') | float(0) > 328.0
        and states('sensor.office_outlet_energy') | float(0) > 53.0 }}
      unit_of_measurement: kWh
      state_class: total_increasing
      device_class: energy

Try this:

      availability: >
        {{ has_value('sensor.shelly_2pm_plus_kitchen_switch_1_energy')
        and has_value('sensor.shelly_2pm_plus_kitchen_switch_0_energy')
        and has_value('sensor.shelly_1pm_plus_dishwasher_switch_0_energy')
        and has_value('sensor.shelly_1pm_plus_fridges_switch_0_energy')
        and has_value('sensor.shelly_2pm_plus_laundry_switch_0_energy')
        and has_value('sensor.shelly_2pm_plus_laundry_switch_1_energy')
        and has_value('sensor.freezer_outlet_energy')
        and has_value('sensor.electrical_cabinet_outlet_energy')
        and has_value('sensor.internet_outlet_energy')
        and has_value('sensor.tv_outlet_energy')
        and has_value('sensor.office_outlet_energy') }}

As for the values resetting after a firmware update, one way around that would be to use a whole lot of utility meters fed by your energy sensors.

1 Like

Is the outlier filter just not working as expected? I’m seeing multiple posts where it’s indicated not to be functional, even though the yaml looks ok.

Three examples are as follows:

In my own case I have a filter setup on a sensor because it generates a randomly high temperature reading from time to time. It’s always a single incorrect value and tends to be between 1000 to 10,000 where the nominal range of the temperature sensor is between 20 and 50C. In this case you would think that an outlier filter would catch these excessive values on the basis that the median value will remain low and the next value will be well outside that range?

Here’s my sensor outlier showing the one incorrect value:

And here’s the filter for it from sensor.yaml:

# Filters for the hot-tank sensors which are showing some noise from time-to-time
  - platform: filter
    name: "hot_tank_air_temperature_5-filtered"
    entity_id: sensor.hot_tank_air_temperature_5
    filters:
      - filter: outlier
        window_size: 2
        radius: 4.0

Any clues what might be going on here?

The outlier filter seems to indeed work as designed but not as expected.

I’m using it to filter glitches from my heatpump MQTT interface which glitches a bit if the device is disconnected from the network. It the nsends a single wrong value that is several million times greater than the old one which especially screws up any utility meter that e.g. tracks energy consumption throughout the year.

I created a simple test for the outlier filter with an input number and the following outlier config

- platform: filter
  name: "outlier_test"
  entity_id: input_number.outlier_test_raw
  filters:
    - filter: outlier
      precision: 1
      window_size: 1
      radius: 10

From the docs I would have expected that if the input_number changes ±10 in a single step, the value is accepted and if it is more than that it uses the median of the previous window, hence the last value in case window_size is 1.
Setting it from 1 to 9 works as expected.

Setting the input number from 9 to 100 the resulting value is 9 .
The debug log notes that an outlier is detected

2024-04-26 07:20:12.779 DEBUG (MainThread) [homeassistant.components.filter.sensor] Update filter on event: <Event state_changed[L]: entity_id=input_number.outlier_test_raw, old_state=<state input_number.outlier_test_raw=9.0; initial=None, editable=True, min=0.0, max=1e+17, step=1.0, mode=box, friendly_name=outlier_test_raw @ 2024-04-26T07:19:57.840015+02:00>, new_state=<state input_number.outlier_test_raw=100.0; initial=None, editable=True, min=0.0, max=1e+17, step=1.0, mode=box, friendly_name=outlier_test_raw @ 2024-04-26T07:20:12.777708+02:00>>
2024-04-26 07:20:12.780 DEBUG (MainThread) [homeassistant.components.filter.sensor] Outlier nr. 1 in input_number.outlier_test_raw: 100.0
2024-04-26 07:20:12.780 DEBUG (MainThread) [homeassistant.components.filter.sensor] outlier(input_number.outlier_test_raw=100.0) -> 9.0

It goes wrong if now a normal value is set again. E.g. setting the input number from 100 (the glitch value) to e.g. 10
The resulting value is not 9 as one would expect, but 100, the previously filtered value as that of course is now part of the window_size.

2024-04-26 07:29:48.964 DEBUG (MainThread) [homeassistant.components.filter.sensor] Outlier nr. 2 in input_number.outlier_test_raw: 10.0
2024-04-26 07:29:48.964 DEBUG (MainThread) [homeassistant.components.filter.sensor] outlier(input_number.outlier_test_raw=10.0) -> 100.0``` 

Using a larger window_size does not change this problem, it would just decrase the overall value which might not be enough depending on how different the outlier is.

It would help if the median was calculated based on the outlier filter result and not the input entity as that would exclude any previously ignored values.

Update: I’ve raised this as issue Outlier filter not dropping filtered value · Issue #116226 · home-assistant/core · GitHub. The filter code has an explicit flag to include the raw input value in the previous states. Changing this or making it configurable would make the filter work as expected.

4 Likes

I am having the same issues I have a energy sensor that keeps spiking by 20 billion kWh. I cleaned up all the old wrong readings and put a filter in front of it

  - platform: filter
    unique_id: 'e4daece9-1269-43a0-8186-82b6fb8cc3a7'
    name: "Patio Lanterns - Energy (Filtered)"
    entity_id: sensor.patio_lanterns_energy
    filters:
      - filter: outlier
        window_size: 4
        radius: 4.0

From what I understand, this filter will take the last 4 valid reading for the device and average them out and the new reading cannot be more than +/-4 from the average…

If this is so then how did my reading spike by 300 million… how does the filter not filter out this bad reading? It’s way higher than +/-4 Am I just understanding the filter wrong or is it a bug…

And this has nothing to do with the availability of my sensors issue that has been discussed so many times IE sensor going from 18 (current reading for last 5 days) to unavailable which is 0 then back to 18kWh again and it counts as energy used… because if that was so it would have had to have done this 16 million times to get the 300 million value. so its not the typical availability issue it jumped by 300 million in ONE read

Okay it has finally happened again and I wanted to document it so someone can tell me what I am doing wrong or that there is a bug somewhere the filter settings.

I have a Z-Wave plug for my washing machine it is a NAS-WR01Z by Inteset. The device reported a spike in energy reading for some reason:

This is from the Washing Machine device history:

This is the history for the filter that I setup for the washing machine:

You can see that both are showing the spike in energy consumption

Here are the settings for the Outlier filter:

What I am expecting if the filter to receive the new reading and compare it to the last 1 reading to see if the delta between them is +/- 0.5 If so, it shoudl “filter” this reading by replacing it with the last reading, if not, accept this value as a good reading.

Yes I know the Outlier filters normally is used to smooth out abnormalities by using averages of the last x reading and replacing bad reading with the average, but in that case there is a possibility that the replaced reading will be lower than the last reading and Consumption value should never be below its last reading because it’s consumption. So if I only take 1 reading it will average that by the nubmer of readings which is 1 and you will get the last value. simple way to make sure the value is only incrementing below a set value. this should remove any spike or dips by more than 0.5

The last reading before this bad one was 5.87 then the next reading was 8.35. A delta of 2.48 which is out of bounds of the +/- 0.5 that the filter is set for. So how did the filter miss this? Am I using or understanding this filter wrong? Is there any kind of logging that I can turn on that tells me exactly what the filter is doing each time so that I can see that it sees this value and says it’s okay or not okay?

I have no touched the reading so if you guys if you need any information I have not corrected the bad reading.

Filter operation issues aside…

That has everything to do with availability.

Your sensor should not go to 0 when unavailable. Fix this and your problem goes away. You won’t need a filter.

The energy will be counted when going from 0 to 18.

It will not be counted when going unavailable to 18.

Sorry I moved my issue to my own thread

If you fix your sensor availability you won’t need a filter.

Sorry I’m not following. How does a sensor going from 5.87 to 8.35 have to do with an availability reading? This is a Total kWh reading form the device. You can see my reading from the sensor above nothing went to 0 in the above example so I am confused. I am very much aware of the unavailable issue as we have discussed it before and I could see in my sensor reading that it went to 0 then back up. How do i put an availability on a sensor that is a real device… this is not a calculated sensor value I am producing this is a value read from the device?

Who said anything about going from 5.87 to 8.35?

The problem is your sensor goes to 0 when unavailable instead of going to unavailable.

You said it yourself.

(emphasis mine).

By creating a template sensor to use instead.

In my post above I did! I show the sensor going from 5.87 to 8.53 and then back again. you are looking at an older post to the one I just posted above.

I know you believe this is an unavailability reading but I don’t believe it is… this is the SQL table for this sensor

8883342	NULL	5.87	NULL	NULL	NULL	NULL	1743383900.4882674	NULL	1743383900.4882674	8882488	157769	NULL	NULL	NULL	0	AZXpxzFI6R0uS56B01cXBQ==	NULL	NULL	1660
8884247	NULL	5.87	NULL	NULL	NULL	NULL	1743384202.4672308	NULL	1743384202.4672308	8883342	157769	NULL	NULL	NULL	0	AZXpy8zjRurCqgzKS6wN7g==	NULL	NULL	1660
8885126	NULL	5.87	NULL	NULL	NULL	NULL	1743384503.4370558	NULL	1743384503.4370558	8884247	157769	NULL	NULL	NULL	0	AZXp0GSN3nXR/RYOJPYEFw==	NULL	NULL	1660
8885691	NULL	5.87	NULL	NULL	NULL	NULL	1743384804.408207	NULL	1743384804.408207	8885126	157769	NULL	NULL	NULL	0	AZXp1Pw4gbkoRbJXMc0Yhw==	NULL	NULL	1660
8886514	NULL	5.87	NULL	NULL	NULL	NULL	1743385105.3717282	NULL	1743385105.3717282	8885691	157769	NULL	NULL	NULL	0	AZXp2ZPbM4epBCsRnw71RQ==	NULL	NULL	1660
8887221	NULL	5.87	NULL	NULL	NULL	NULL	1743385407.3466272	NULL	1743385407.3466272	8886514	157769	NULL	NULL	NULL	0	AZXp3i9yVZXHVbACZwXnCg==	NULL	NULL	1660
8887708	NULL	5.87	NULL	NULL	NULL	NULL	1743385707.303694	NULL	1743385707.303694	8887221	157769	NULL	NULL	NULL	0	AZXp4sMncbzyLzMOZGvNyw==	NULL	NULL	1660
8887717	NULL	5.87	NULL	NULL	NULL	NULL	1743385707.365355	NULL	1743385707.365355	8887708	157769	NULL	NULL	NULL	0	AZXp4sNlNLosJFQiFvsuyw==	NULL	NULL	1660
8888138	NULL	5.87	NULL	NULL	NULL	NULL	1743386009.28175	NULL	1743386009.28175	8887717	157769	NULL	NULL	NULL	0	AZXp517BOIW2hQzbQkURlA==	NULL	NULL	1660
8888621	NULL	5.87	NULL	NULL	NULL	NULL	1743386310.2532086	NULL	1743386310.2532086	8888138	157769	NULL	NULL	NULL	0	AZXp6/ZtF2V09ZwoA1fGcw==	NULL	NULL	1660
8889057	NULL	5.87	NULL	NULL	NULL	NULL	1743386612.2229328	NULL	1743386612.2229328	8888621	157769	NULL	NULL	NULL	0	AZXp8JH+V8n7Ay25qazTKA==	NULL	NULL	1660
8889301	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.1857965	NULL	1743386773.1857965	8889057	157769	NULL	NULL	NULL	0	AZXp8wbBHb9yIV95NA+vrA==	NULL	NULL	1660
8889307	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.6431708	NULL	1743386773.6431708	8889301	157769	NULL	NULL	NULL	0	AZXp8wiL4q+QsKvnXmjc6A==	NULL	NULL	1660
8889310	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.655856	NULL	1743386773.655856	8889307	157769	NULL	NULL	NULL	0	AZXp8wiXDyRl6yjW4A0V1A==	NULL	NULL	1660
8889313	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.6715593	NULL	1743386773.6715593	8889310	157769	NULL	NULL	NULL	0	AZXp8winHcFDgqsz2RwI6w==	NULL	NULL	1660
8889316	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.7132907	NULL	1743386773.7132907	8889313	157769	NULL	NULL	NULL	0	AZXp8wjRQoyhYwp3Aut9Zw==	NULL	NULL	1660
8889318	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.8909774	NULL	1743386773.8909774	8889316	157769	NULL	NULL	NULL	0	AZXp8wmCxMdjbwyTtT8bPg==	NULL	NULL	1660
8889349	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.9278378	NULL	1743386773.9278378	8889318	157769	NULL	NULL	NULL	0	AZXp8wmnx5jekHwByl6f+g==	NULL	NULL	1660
8889356	NULL	8.35	NULL	NULL	NULL	NULL	1743386773.9837818	NULL	1743386773.9837818	8889349	157769	NULL	NULL	NULL	0	AZXp8wnffqhKsa3sspjN7Q==	NULL	NULL	1660
8889360	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.1777656	NULL	1743386774.1777656	8889356	157769	NULL	NULL	NULL	0	AZXp8wqhGcrS6A8MRY5Z+g==	NULL	NULL	1660
8889361	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.3254342	NULL	1743386774.3254342	8889360	157769	NULL	NULL	NULL	0	AZXp8ws1XhiS1gJFaZzjvQ==	NULL	NULL	1660
8889363	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.5090609	NULL	1743386774.5090609	8889361	157769	NULL	NULL	NULL	0	AZXp8wvtG1E5GVMPHgXMlA==	NULL	NULL	1660
8889365	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.724806	NULL	1743386774.724806	8889363	157769	NULL	NULL	NULL	0	AZXp8wzEzIwf8GSn6+1aLg==	NULL	NULL	1660
8889367	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.7464106	NULL	1743386774.7464106	8889365	157769	NULL	NULL	NULL	0	AZXp8wzaEeh05PtouDqwEw==	NULL	NULL	1660
8889370	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.8251703	NULL	1743386774.8251703	8889367	157769	NULL	NULL	NULL	0	AZXp8w0pnujXZEFYG3z05w==	NULL	NULL	1660
8889371	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.877427	NULL	1743386774.877427	8889370	157769	NULL	NULL	NULL	0	AZXp8w1d0W9j73NK4oJTeQ==	NULL	NULL	1660
8889372	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.9337897	NULL	1743386774.9337897	8889371	157769	NULL	NULL	NULL	0	AZXp8w2VOAKxXC3c9Di6xg==	NULL	NULL	1660
8889373	NULL	8.35	NULL	NULL	NULL	NULL	1743386774.9455671	NULL	1743386774.9455671	8889372	157769	NULL	NULL	NULL	0	AZXp8w2hLjPVL/ahgK4FDQ==	NULL	NULL	1660
8889374	NULL	8.35	NULL	NULL	NULL	NULL	1743386775.0955539	NULL	1743386775.0955539	8889373	157769	NULL	NULL	NULL	0	AZXp8w43MaXt1wDhNz83FQ==	NULL	NULL	1660
8889553	NULL	5.87	NULL	NULL	NULL	NULL	1743386914.186983	NULL	1743386914.186983	8889374	157769	NULL	NULL	NULL	0	AZXp9S2K3LP0JQnsRKznmA==	NULL	NULL	1660
8889986	NULL	5.87	NULL	NULL	NULL	NULL	1743387214.1531038	NULL	1743387214.1531038	8889553	157769	NULL	NULL	NULL	0	AZXp+cFJR2rmD5GWV4npwg==	NULL	NULL	1660

As you can see there is no unavailable records for this device that cause this to spike… and if there was it would jump by at minimum the value the device used to be at before going to (unavailable/0) then back again. For example if my sensor was at 5.87 then went unavailable then back again it would double the reading at minimum and this is only jumping by 2.48 kWh so that tells me not an availability issue.

Then good luck.

Well I explained why also… if you want to ignore the data that shows there are no unavailable records for this device then I guess you won’t be much help anyways…

Any one else want to look at the real issue here that the filters are not working