Calculating the Relative Humidity (not as simple as it sounds)

I want to calculate the relative humidity of the air entering my house through an Air Exchanger (if you don’t know how these work, they take the air from outside, and mix it with the air inside the house through a plastic core, mine has heat recovery, so it mixes warm air with the cold air from outside).

I have a formula:
100*(EXP((17.625TD)/(243.04+TD))/EXP((17.625T)/(243.04+T)))

TD is the dewpoint in degrees c
T is the temperature in degrees c
EXP is the exponent to raise Euler’s constant to

The result is the Relative Humidity of the air once it’s in the house. The same air outside will have a different relative humidity to the same air inside. For example today it’s -10 outside and the dewpoint is -12. That gives a relative humidity in the house @ 20 degrees of around 18%. The relative humidity outside is 85%.

Here’s my question. How can I calculate these values in HA on the fly. I want HA to do the math and return the relative humidity of the air if it enters my house. I in turn want to then use this value to see if the humidity inside the house, exceeds the humidity outside the house, and then turn on the air exchanger (no point in adding more humidity in).

This is beyond my knowledge (I’m good with the math, I just don’t know how to implement this). I’m hoping someone out there is smart enough to tell me how to do this!

1 Like

You can do Math in templates if you go to the Templates tab you can test it out

For example {{100*(50/100)}} will out put 50.0

Then in your automation

-id: 0000
  alias: exchanger  Start
  trigger:
  - at: '10:30:00'
    platform: time
  condition:
  - condition: template
    value_template: '{{ (10+8) < (80+5) }}'
  action:
    service: exchanger.start

where (10+8) represents you inside humidity and (80+5) represents your outside humidity

Hello!

Have you tried the Node-Red add-on? You can use a simple function that reads your variables upon change or at a certain time and based on that you can opt to trigger a humidifier on/off.

I personally am using Aquara environment monitors that return temperature and humidity inside my kids’ room and based on the value decide to turn on/off their humidifier. You can easily tweak this flow to suit your needs if you’re up to it. Let me know and I’m happy to post it and connect with you to help.

Cheers,

W.

Node Red was really unreliable for me. I might revisit it.

I’m going to check out templates, is there a limit to the functions that I can use in there?

Create a template sensor.

value_template: "{{ 100*(e**((17.625 *TD)/(243.04+TD))/e**((17.625* T)/(243.04+T))) }}"

Replace TD and T with your sensors.

e.g. for TD, it could be something like this states('sensor.outside_dew_pt') | float

That’s amazing, thank you so much for taking the time to do that for me!

So I’m getting an error, but I don’t really understand what the issue is:

[homeassistant.components.sensor.template] Template sensor humidity_true_inside has no entity ids configured to track nor were we able to extract the entities to track from the value template(s). This entity will only be able to be updated manually.

The sensor values are:

sensor.bedroom_temperature
20.0
unit_of_measurement: °C friendly_name: Bedroom Temperature

And:

Sensor.pws_dewpoint_c
-4
attribution: Data provided by the WUnderground weather service date: Last Updated on February 7, 7:40 PM EST unit_of_measurement: °C friendly_name: Dewpoint icon: mdi:water

You need to explicitly tell the sensor template which entities to monitor.

Post the code you have for the template sensor and I’ll be able to help.

"{{ 100*(e**((17.625 *('sensor.pws_dewpoint_c')|float)/(243.04+('sensor.pws_dewpoint_c')|float))/e**((17.625*('sensor.bedroom_temperature')|float)/(243.04+('sensor.bedroom_temperature')|float))) }}"

  • platform: template
    sensors:
    humidity_true_inside:
    value_template: “{{ 100*(e**((17.625 (‘sensor.pws_dewpoint_c’)|float)/(243.04+(‘sensor.pws_dewpoint_c’)|float))/e*((17.625*(‘sensor.bedroom_temperature’)|float)/(243.04+(‘sensor.bedroom_temperature’)|float))) }}”

Thank you!

1 Like

Try this:

- platform: template
  sensors:
    humidity_true_inside:
    friendly_name: True Inside Humidity
    entity_id:
      - sensor.pws_dewpoint_c
      - sensor.bedroom_temperature
    value_template: "{{ 100 * (e**((17.625 * states('sensor.pws_dewpoint_c')|float)/(243.04 + states(‘sensor.pws_dewpoint_c’)|float))/e**((17.625 * states('sensor.bedroom_temperature')|float)/(243.04+ states('sensor.bedroom_temperature')|float))) }}"

The defined entity ids tell HA what to monitor to update the template.
You also missed the “states” part of states(‘sensor.pws_dewpoint_c’) in your template. Same for the bedroom temp sensor (fixed above).

So this is now giving a value, but it is constantly 100.

I need to check our the math

I once started doing this for absolute humidity by using the python_script component. Even though you may have your answer, an alternative approach might be interesting for comparison.

Here’s the script (it’s just logging everything):

# Compute the absolute humidity in g/m³
# Param rh - relative humidity in %
# Param t - temperature in °C
def ah(rh, t):
    mw = 18.016 # kg/kmol (Molecularweight of vapor)
    rs = 8314.3 # J/(kmol*K) (Universal Gasconstant)
    svp = 6.112 * math.exp((17.67*t)/(243.5+t)) # Compute saturated water vapor pressure in hPa
    vp = rh/100. * svp # Compute actual water vapor pressure in hPa
    return 10**5 * mw/rs * vp/(t + 273.15)

humidity_entity = data.get('humidity_entity')
humidity_attribute = data.get('humidity_attribute')
temperature_entity = data.get('temperature_entity')
temperature_attribute = data.get('temperature_attribute')

if humidity_entity is not None and temperature_entity is not None:
    if humidity_attribute is not None:
        logger.warning("Humidity attr: {}".format(humidity_attribute))
        humidity = float(hass.states.get(humidity_entity).attributes[humidity_attribute])
    else:
        humidity = float(hass.states.get(humidity_entity).state)
    if temperature_attribute is not None:
        logger.warning("Temperature attr: {}".format(temperature_attribute))
        temperature = float(hass.states.get(temperature_entity).attributes[temperature_attribute])
    else:
        temperature = float(hass.states.get(temperature_entity).state)
    
    logger.warning("Humidity: {}".format(humidity))
    logger.warning("Temperature: {}".format(temperature))
    
    absolute_humidity = ah(humidity, temperature)
    logger.warning("Absolute Humidity: {}".format(absolute_humidity))
    #hass.bus.fire(name, { "wow": "from a Python script!" })
else:
    logger.error("Missing entities in service data.")

To use this you would you would call the service with data like this:

{
    "humidity_entity":"sensor.myhumiditysensor",
    "temperature_entity":"climate.mythermostat",
    "temperature_attribute":"current_temperature"
}

So it’s using existing entities, just like the template approach. In my example I used a climate entity for the temperature where the current temperature is exposed via an attribute. But it could also be a sensor like I do it for the humidity.

3 Likes

That’s an interesting approach. Did this actually work? I’m just getting a value of 100, which when I do the math means that there are no values for either sensor, but this doesn’t make a whole load of sense as the sensors actually have values.

Where do you put the Python script? And where do you call the service? In HA?

Use the developer tools template editor to play with your equation.

What was your source of the equation?

If you can post that I can check the formula for order of operations problems.

Tom, I put the calculation in a spreadsheet and it returns the correct values! Therefore I think there is an issue with my sensor values…

Excel and HA may have a different order of operations.

What happens when you put your sensors in the template editor?

I’m still getting 100. I’ll post more tomorrow

It does generate a value. I am however not too involved in that topic to judge if the result makes any sense. It’s what I implemented based on my Google research.

Follow the python_script instructions. Once you have placed the script at the correct location etc., you shoul see the script as a service in the service overview panel of HA. There you can feed it with JSON just like I have posted above. The result will be logged. Just below the line that does the final log there’s a commented out line I took from a template that would generate an event. But you probably could also modify an entity. I don’t know about that. So that’s the part you have to figure out, as it depends on you how you want this to work.

I tried to prettify the Jinja2 code + using even more accurate constants.
(huge thanks for @danielperna84, for rhTdFromWetBulb.pdf and for this book)

Here is my solution:


- platform: template
  sensors:
    o1balcony_ah:
      friendly_name: 'Outside: Abs. humidity'
      entity_id:
        - sensor.o1balcony_xiamul_t
        - sensor.o1balcony_xiamul_h
      device_class: humidity
      unit_of_measurement: 'g/m³'
      availability_template: >
        {{ not is_state('sensor.o1balcony_xiamul_t', 'unavailable') and not is_state('sensor.o1balcony_xiamul_h', 'unavailable') }}
      value_template: >
        {%- set t = states('sensor.o1balcony_xiamul_t') | float %}
        {%- set rh = states('sensor.o1balcony_xiamul_h') | float %}
        {%- set mw = 18.016 %}                                       {#- kg/kmol (Molecularweight of vapor) #}
        {%- set rs = 8314.3 %}                                       {#- J/(kmol*K) (Universal Gasconstant) #}
        {%- set svp = 6.112 * (e ** ((17.67 * t) / (243.5 + t))) %}  {#- Compute saturated water vapor pressure in hPa #}
        {%- set vp = rh / 100.0 * svp %}                             {#- Compute actual water vapor pressure in hPa #}
        {{ (10 ** 5 * mw / rs * vp / (t + 273.15)) | round(1) }}
2 Likes

And a follow-up in the new template form:

- sensor:                                                                                                               
    - name: o1balcony_ah                                                                                                   
      unique_id: d698a9fe-6c31-4351-a821-704ba488cddb                                                                   
      device_class: humidity                                                                                            
      icon: 'mdi:water'                                                                                                 
      unit_of_measurement: 'g/m³'                                                                                       
      availability: >                                                                                                   
        {{ not is_state('sensor.o1balcony_xiamul_t', 'unavailable') and not is_state('sensor.o1balcony_xiamul_h', 'unavailable') }}                 
      state: >                                                                                                          
        {%- set t = states('sensor.o1balcony_xiamul_t') | float %}                                                                    
        {%- set rh = states('sensor.o1balcony_xiamul_h') | float %}                                                                   
        {%- set mw = 18.016 %}                                       {#- kg/kmol (Molecularweight of vapor) #}          
        {%- set rs = 8314.3 %}                                       {#- J/(kmol*K) (Universal Gasconstant) #}          
        {%- set svp = 6.112 * (e ** ((17.67 * t) / (243.5 + t))) %}  {#- Compute saturated water vapor pressure in hPa #}
        {%- set vp = rh / 100.0 * svp %}                             {#- Compute actual water vapor pressure in hPa #}  
        {{ (10 ** 5 * mw / rs * vp / (t + 273.15)) | round(1) }}
3 Likes