monotux.tech

Dealing with unreliable temperature sensors

Home Assistant

As I’m getting closer to 40 I’m getting more and more obsessed with the weather, especially with the outdoor temperature1. This is my latest attempt at estimating the current outdoor temperature based on a bunch of unreliable temperature sensors.

I use RTLSDR to listen in on a few 433 MHz temperature sensors, which can be pretty unreliable. I also use a few fake DS18B202 sensors around the house, which are much more reliable but can intermittently disconnect.

I’ve tried putting reliable sensors into a group and removed unreliable sensors when needed, but this is repetitive and error prone. I also want to have as many data points as possible for this calculation (due to reasons), so how do we solve this? A rolling median, of course!

The algorithm is very simple:

  1. List a bunch of sensors in Home Assistant
  2. Loop over them and collect sensors that has reported any data the last N minutes
  3. Calculate a median for said sensors, or the last reported value from any sensor

Below is the Home Assistant templating code necessary to achieve this:

{% set sensors = expand('sensor.temperature_1',
                        'sensor.temperature_2',
                        'sensor.temperature_3',
                        'sensor.temperature_4',
                        'sensor.temperature_5',
                        'sensor.temperature_6',
                        'sensor.temperature_7') %}

{% set cur = now() %}
{% set data = namespace(active_sensors=[]) %}

{% for sensor in sensors %}
  {% set diff = cur - sensor.last_reported %}
  {# Change the time period to your liking here #}
  {% if diff <= timedelta(minutes=5) %}
    {% set data.active_sensors = data.active_sensors + [sensor] %}
  {% endif %}
{% endfor %}

{# Extract values and convert to float #}
{% set values = data.active_sensors | map(attribute="state") | map("float", 0.0) | list %}

{# If no values at all in the time window, take the last one reported #}
{% set last = (sensors | sort(attribute="last_reported", reverse=true) | first).state | round(1) %}

{# Finally, calculate the median for the values seen #}
{{ median(values, last) }}

This will work as long as one sensor reports a value over a 5 minute period, otherwise the median will fallback to reporting 0.0. This should also filter the worst outliers, get us fairly close to the current outdoor temperature, and stop us from getting stuck on old, irrelevant data.


  1. I suspect I will get into humidity and atomspheric pressure once I gather the courage to buy a proper weather station. ↩︎

  2. Apparently most DS18B20 are counterfeit unless you bought the expensive ones from a legit supplier (aliexpress is not one of those) ↩︎