Average room temperature

Hello Community,

another questions :slight_smile:
In my rooms I have various devices, and a lot of them measure the temperature.
I would like to combine all of them to a group calculating the average of all it’s elements and would like to present this as Room temperature.

Is this easily possible?

thanks
martin

Will this do it?

2 Likes

looks cool, and also works :slight_smile:
thanks a lot!

or use the min/max integration:

or, if you want to use a group, as stated, use this python_script:

tempEntities = 'group.indoor_temp_sensors'
#tempEntities = ['sensor.first_sensor_temperature','sensor.second_sensor_temperature','etc']
sensorsTotal = 0 #len([tempEntities])
tempsCounted = 0
tempsTotal = 0

# look up each entity_id
#for entity_id in tempEntities:
for entity_id in hass.states.get(tempEntities).attributes['entity_id']:
  # copy it's state
  state = hass.states.get(entity_id)
  sensorsTotal = sensorsTotal + 1
  # If not None, add up and increase counter
  if state.state is not None:
     if state.state is not 'unknown':
       tempsCounted = tempsCounted + 1
       tempsTotal = tempsTotal + int(float(state.state))

# Get average
averageTemp = float("{0:.2f}".format(tempsTotal / tempsCounted))
#averageTemp = tempsTotal / tempsCounted

iconColor = 'purple' if averageTemp < 10 else \
            'black' if averageTemp < 12 else \
            'mediumblue' if averageTemp < 14 else \
            'dodgerblue' if averageTemp < 16 else \
            'lightblue' if averageTemp < 18 else \
            'turquoise' if averageTemp < 20 else \
            'green' if averageTemp < 22 else \
            'darkgreen' if averageTemp < 24 else \
            'orange' if averageTemp < 26 else \
            'crimson' if averageTemp < 28 else \
            'firebrick'

icon = 'mdi:home-thermometer' if averageTemp > 20 else 'mdi:home-thermometer-outline'
hass.states.set('sensor.average_indoor_temp', averageTemp, {
                'unit_of_measurement': '°C',
                'friendly_name': 'Average indoor temp',
                'icon': icon,
                'icon_color': iconColor,
                'temps_counted': tempsCounted,
#                'temps_total': tempsTotal,
                'sensors_total': sensorsTotal
#                'device_class': 'temperature'
               })
2 Likes

This is the template sensor I use for an average household temperature from a group…

average_household_temp:
        value_template: >-
          {% set temp_sum = expand('group.indoor_thermometers')| selectattr('attributes.unit_of_measurement', 'equalto', '°F')| rejectattr('state', 'in', ['unavailable', 'unknown'])| map(attribute='state') | map('float') | sum | round(1) %}
          {% set temp_count = expand('group.indoor_thermometers')|map(attribute='state')|list|length%}
          {{ (temp_sum / temp_count) | round(1)}}
4 Likes

Hi There,

I’m searching for a solution to my temperature averaging issue. I have 4 room sensors which I can get the average temperatures from to control my central heating system to turn on or off. However when one of the sensors either goes offline or errors to a “0” reading, then the average is also affected as the sum total is still divided by the original total number of sensors, rather than the total number of working or plausible values (my sensors can go offline but still displaying a reading of “0” which is still a value albeit false in my case.

I tried to adapt the above code but is still reads a low average rather than what would be the higher value if it was only divided by the 3 plausible readings.

image

image

From above the correct Upstairs average (that I’m looking for) would be the sum ((19+18.7+20.9)/3) = 19.53 rather than the currently displayed 14.65

Anyone have a suggested way to only count sensors that are online and working with plausible values?

Yes - use the actual dedicated component that specifically does averages.
eg:

  - platform: min_max
    entity_ids:
      - sensor.living_room_temperature
      - sensor.hall_temperature
      - sensor.livingroom_temperature_temperature
      - sensor.zigbee_hall_temperature_temperature
      - sensor.livingroom_east_temperature
    type: mean
    name: "average_house_temperature"
    round_digits: 2

Is what I use. It will ignore any sensors that are not outputting a numeric value, and it will include them again once they start working again.

To get around the 0 issue, the easiest solution would be to create a template sensor for any sensor that exhibits this behaviour, and output the value of the source sensor if the value is over 0, otherwise output the existing value.

1 Like

Thanx Andrew,

Very fast reply!

I have been using this code which uses the “Average” platform:

# Temperature Average
  - platform: average
    name: 'Upstairs Avg Temperature'
    entities:
      - sensor.luminance_sensor_3_temperature
      - sensor.luminance_sensor_4_temperature
      - sensor.luminance_sensor_5_temperature
      - sensor.luminance_sensor_6_temperature

But as my erroneous sensor is still outputting a value of “0” it is still a value so counted. Let me change the platform to your suggested “min_max” to see if that can get around the 0 value.

Something like:

template:
  - sensor:
      - name: "My Average"
        unit_of_measurement: "C"
        unique_id: bd87ddae-855f-440a-a0e1-31137858a9d5
        state: >
          {% set src = states('sensor.source_sensor')|float(0) %}
          {{ src if src > 0 else states('sensor.my_average') }}

something like that - output the source temperature sensor if it is over 0, otherwise output the last value of sensor.my_average

1 Like

Thanx Andrew,

I got something working with your example and substituted the room next door to the troublesome sensor so if it goes to “0” then the reading used is close to that bedroom temp and keeps the averages in the ball park.

Only thing that I noticed is the average is not exactly the same if I manually add them up and divide by 4. I manually calculate 19.03 but the sensor average is calculated as 19.23. I’m not sure if this is anything to do with the “float(0)” in the sensor template?

template:
  sensor:
    - name: "Sensor 5 Temperature"
      unit_of_measurement: "C"
      unique_id: Sensor 5 Temperature
      state: >
        {% set src = states('sensor.luminance_sensor_5_temperature')|float(0) %}
        {{ src if src > 0 else states('sensor.luminance_sensor_3_temperature') }}

The template already rejects sensors with states that are “unavailable” and “unknown”. If you know that your sensor’s state is always ‘0.0’ when it is malfunctioning you can just add that to the list in the rejectattr filter. Also, we can now use Jinja’s average filter instead of setting up the math:

template:
  sensor:
    - name: "Upstairs Avg Temperature"
      unit_of_measurement: "C"
      unique_id: upstairs_avg_temperature
      state: >
        {{ expand('sensor.luminance_sensor_3_temperature', 'sensor.luminance_sensor_4_temperature', 'sensor.luminance_sensor_5_temperature', 'sensor.luminance_sensor_6_temperature')
        | rejectattr('state', 'in', ['unavailable', 'unknown', '0.0'])
        | map(attribute='state') | map('float') | average | round(2, 0) }}

If you really want to spoof the data by substituting a malfunctioning sensor_5 with sensor_3 it’s possible, but I wouldn’t bother…

w/ Substitution
template:
  sensor:
    - name: "Upstairs Avg Temperature"
      unit_of_measurement: "C"
      unique_id: upstairs_avg_temperature
      state: >
        {% set x = 'sensor.luminance_sensor_5_temperature' if (states('sensor.luminance_sensor_5_temperature') != '0.0') else 'sensor.luminance_sensor_3_temperature' %}
        {{ expand('sensor.luminance_sensor_3_temperature', 'sensor.luminance_sensor_4_temperature', 
        x, 'sensor.luminance_sensor_6_temperature')
        | rejectattr('state', 'in', ['unavailable', 'unknown'])
        | map(attribute='state') | map('float') | average | round(2, 0) }}
2 Likes

Thanx Andrew and Drew,

I finally got something working that now only averages out the non 0.0 temperatures. Now my heating timer boolean can get switched on when the average house temperatures drop below a set value and this is now not skewed when one sensor goes down.