Dew point calculator not working; Custom Enthalpy Calculator?

First off: ultimately, I’m looking for a way to calculate specific humidity (i.e., mass of water per mass of air – not absolute humidity, which is mass-per-volume), and moist air enthalpy from dry bulb temperature, relative humidity, and pressure.

I searched and searched, but did not find an existing component or other straightforward way to do this. Also, I’m not familiar enough with Home Assistant yet to write such a component…but I’d like to be.

The good news is, I found a custom component that’s very close to what I want to do. This one: GitHub - miguelangel-nubla/home-assistant-dewpoint: Home Assistant custom component to calculate dew point using temperature and humidity sensors. – it uses psychrolib to calculate dewpoint, which can also perform the calculations I want. I’m hoping I can create a version of this that does what I want. However, it’s kind of moot if I can’t get the original component to work.

I installed it to config/custom_components and initially got error messages, as it was missing the Version tag. I fixed the Version tag in the manifest (the same way most of the forks on github have fixed it), but I am still unable to get it to work. The component now loads without error (now that the the Version thing is fixed), but adding this code to sensor.yaml first causes Developer Tools > Check Configuration to hang, and doesn’t create the sensor on a restart anyway:

- platform: dewpoint
  sensors:
    dewpoint_outside:
      temperature: sensor.outdoor_air_bme280_temperature
      rel_hum: sensor.outdoor_air_bme280_relative_humidity

(There are other functional things in my sensor.yaml file, so I know it’s being looked at; the two input sensors are otherwise valid)

There’s nothing helpful in the logs, just a warning about this custom integration not being tested by Home Assistant.

Any idea what I could be doing wrong? Any thoughts on how to fix it?

I assume you’ve checked out the Thermal Comfort integration? It only calculates specific humidity, but it does calculate moist air enthalpy.

Out of curiosity, what are you trying to do with these values?

Ah, that’s good to know; I’ll check it out.

I’m trying to do two things:

  1. To be able to show when it is possible to economize with outside air (i.e., in the summer, outdoor air enthalpy < indoor air enthalpy, among other things)

  2. To understand how to get Home Assistant to run my own (procedural) code, in a language I am familiar with (C, C++, Java, Python). I generally learn best from examples and by modifying existing code.

I had a suspicion this might be what you were trying to do. I actually setup some template sensors and an automation to do exactly this. Here’s one of my template sensors for calculating total enthalpy:

      - name: "Home Enthalpy"
        unique_id: home_enthalpy
        icon: mdi:gauge
        state_class: "measurement"
        unit_of_measurement: "BTU/lb"
        state: >
          {% set DB = states('sensor.upstairs_average_temperature')|float %}
          {% set RH = states('sensor.upstairs_average_humidity')|float %}
          {{ (0.24*DB+(0.6219)*(0.01*(0.000000007401234*DB**4 - 0.000000493526794*DB**3 + 0.000071281097208*DB**2 - 0.000489806163078*DB + 0.039762055806989)*RH)/(14.7-(0.01*(0.000000007401234*DB**4 - 0.000000493526794*DB**3 + 0.000071281097208*DB**2 - 0.000489806163078*DB + 0.039762055806989)*RH))*(1061.2+0.444*DB))|round(2) }}

Obviously you normally can’t derive enthalpy directly like this, however I found this equation online that someone derived by curve fitting data in excel. It’s not perfect, but it’s more than close enough for my needs. I then made the following template sensor to throw on my dashboard (I have window sensors, so I have it change based on how many windows with screens are currently open):

      - name: "Economizer"
        unique_id: economizer
        state: >
          {% set Open_Windows_Count = (states | selectattr('entity_id','in',state_attr('binary_sensor.screen_windows','entity_id')) | selectattr('state','eq','on') | list | count | int) %}
          {% if is_state('climate.home', 'heat') %}
            Heating Mode
          {% elif is_state('input_boolean.economizer', 'on') and (Open_Windows_Count > 2) %}
            Windows Open; {{ (states.sensor.home_enthalpy.state | float - states.sensor.outside_enthalpy.state | float) |round(1) }} BTU/lb Benefit
          {% elif is_state('input_boolean.economizer', 'off') and (Open_Windows_Count <= 2) %}
            Windows Closed; {{ -(states.sensor.home_enthalpy.state | float - states.sensor.outside_enthalpy.state | float) |round(1) }} BTU/lb Penalty Avoided
          {% elif is_state('input_boolean.economizer', 'on') %}
            Open the Windows; {{ (states.sensor.home_enthalpy.state | float - states.sensor.outside_enthalpy.state | float) |round(1) }} BTU/lb Potential Benefit
          {% else %}
            Close the Windows; {{ -(states.sensor.home_enthalpy.state | float - states.sensor.outside_enthalpy.state | float) |round(1) }} BTU/lb Penalty
          {% endif %}
        icon: >
          {% if is_state('input_boolean.economizer', 'on') %}
            mdi:window-open
          {% else %}
            mdi:window-closed
          {% endif %}

Hopefully this might be helpful for you?

Mostly writing this as a follow-up for others interested in this problem.

I didn’t want to try to copy the entirety of the calculations from psychrolib into my own code; part of the point of libraries is that they are tested, and might be difficult to duplicate.

That said, I ended up figuring it out – I looked at the Thermal Comfort module and was able to add specific humidity (or “humidity ratio”), and even Wet Bulb temperature. I’m sure HA will try to wipe out my changes in the next update, but I’ll back it up and cross that bridge later. For now, I just edited the version that was installed in config/custom_components/thermal_comfort

This commit was the most helpful in that process:

It shows that there are 3 major locations within the code that need to be modified to add another output to the module:

  • name of the sensor and its key (related) - line 83
  • attributes (device class, display precision, units of measurement, icon) - lines 142-148
  • calculation of the sensor value (from only the inputs) - lines 712-763

Following their naming scheme, I coded my own addition. I also needed to add psychrolib to the manifest.

I also determined that it is necessary to restart Home Assistant (via Developer Tools > YAML > RESTART or Settings > System > (power icon)) to get it to recognize a change in the code.

I’m still not entirely sure why the other module didn’t work, but I figure I’ll discover the reason eventually. My next task is to modify Thermal Comfort to make use of the pressure sensor in the BME280, since many psychrometric calculations take pressure as an input. Right now, Thermal Comfort just has hardcoded atmospheric pressures in several places.

In general, Thermal Comfort appears to be a good template for general “numeric converter modules” of sorts – it doesn’t require you to write yaml just to use it (configuration can be done through the GUI), it has multilingual support, there are a dozen examples of varied output types/units, etc…

Interesting. Are you planning to submit a PR to thermal Comfort to add these entities? It’d be nice to pull in Enthalpy natively.

Does your use-case have you comparing air volumes at meaningfully different pressures? I admittedly have not compared psych charts for varying pressures, but I can’t imagine it really making a difference unless the pressures are significantly different or you’re at elevation (and even then, my gut says the comparative calculations wouldn’t have significant differences).

Thermal Comfort already calculates Moist Air Enthalpy, so no need for that. I’m considering submitting a PR for wet bulb and/or specific humidity, but I probably need to write tests, update documentation, etc…

Regarding pressure, no, my use case doesn’t have meaningfully different pressures, and I can’t imagine it would be common. Considering this is Home Assistant and Thermal Comfort, I can’t see anyone taking one of these devices on a plane, nor sticking one in the inlet manifold of a car. This change certainly wouldn’t warrant a pull request. That said, it’s for the same reason I wanted to go through the process of learning to modify a component myself – it gives me an idea of how to write/modify software that connects to HA.

It might be practical to have a configuration field for altitude or, more specifically, “atmospheric pressure where the sensor is”. That way, if you happen to live at a higher altitude, your values might be comparable to those at sea level. I’ll have to look up a few things and see if that even makes sense.

Interesting, I was aware of this entity but I assumed it was just the enthalpy of the water vapor in the air (and explicitly excluding the dry air component) . Google seems to confirm you are correct; maybe it’s a regional thing? I’m a mechanical engineer in the US and never heard of that term despite taking numerous thermodynamics courses: we always just called it total enthalpy. Thanks for enlightening me! I’ll have to update my automations and get rid of the template sensors I made for this value.

Totally makes sense.

That would actually be really handy I think, specifically for folks at elevation. But at the same time, probably wouldn’t significantly change most of the values. :slight_smile:

Well, to satisfy my own curiosity I checked the ‘Moist Air Enthalpy’ number reported by Thermal Comfort to both my own Total Enthalpy calculation (from the excel curve fit) as well as pulling out a psych chart and plotting the values manually. Something is very off…

I used my current outside conditions of 80.4F & 88% RH which yields a total enthalpy of ~41 BTU/lb (both my excel curve fit calculation and paper psych chart essentially match). But the Thermal Comfort ‘Moist Air Enthalpy’ value is wildly different with ~33 BTU/lb (77.36 kJ/kg is what it actually reports). Interestingly, while triple checking my work I came across one website that happens to exactly match the Thermal Comfort value:
https://drajmarsh.bitbucket.io/psychro-chart2d.html

To confirm that I’m not crazy (at least in regards to this), I asked a friend of mine who is also an engineer to calculate things and his numbers match mine. Without digging further, I have a sneaking suspicion that they both use the same library to calculate Enthalpy and that it’s just plain wrong. So much for being able to get rid of a couple more template sensors… :slight_smile:

Edit 1: To further try and satisfy my curiosity, I wondered if maybe the lower enthalpy value was actually just the latent enthalpy from the moisture in the air, but that also doesn’t match. For my stated outside conditions I came up with a Total Enthalpy of 41, Sensible (Dry Air) Enthalpy of 19 and Latent Enthalpy of 22 (BTU/lb). Obviously, none of those matches to the 33 reported by Thermal Comfort…

Yikes. I guess my next task should be to see if psychrolib generates correct values, or if it is also wrong.

Edit: just pulled up psychrolib in interactive and got these results:

>>> import psychrolib
>>> psychrolib.SetUnitSystem(psychrolib.IP)
>>> drybulb = 80.4
>>> rh = 0.88
>>> patm = 14.7
>>> humRatio = psychrolib.GetHumRatioFromRelHum(drybulb, rh, patm)
>>> humRatio
0.019745976629191458
>>> moistAirEnthalpy = psychrolib.GetMoistAirEnthalpy(drybulb, humRatio)
>>> moistAirEnthalpy
40.951365178890356
>>> psychrolib.SetUnitSystem(psychrolib.SI)
>>> drybulbSI = 26.9
>>> patmSI = 101325
>>> humRatioSI = psychrolib.GetHumRatioFromRelHum(drybulbSI, rh, patmSI)
>>> humRatioSI
0.01976491205310456
>>> moistAirEnthalpySI = psychrolib.GetMoistAirEnthalpy(drybulbSI, humRatioSI)
>>> moistAirEnthalpySI
77482.36265447954
>>>

So, for psychrolib in IP mode, it seems to work correctly, but for SI mode, it doesn’t. I’ve been using psychrolib in SI mode because the rest of the inputs in Thermal Comfort are in SI units.

Interestingly, if you look at the tests:

For GetMoistAirEnthalpy(drybulb, humratio)

The SI test is (30, 0.02) → 81316
The IP test is (86, 0.02) → 42.6168

I hand-checked the BTU/lb ↔ kJ/kg calculations, and mine agreed with yours and with Google’s converter.

Then, I found this psychrometric chart: http://www.uigi.com/UIGI_SI.PDF

and this one: https://tranecds.custhelp.com/ci/fattach/get/308147/0/filename/SI+Psychrometric+Chart.pdf

Both match Thermal Comfort and SI-psychrolib. Additionally, the enthalpy is referred to as “dry air” in both charts.

I also found this chart: https://hvacrassets.net/content/121/handouts/0000Psych11x17US_SI_logos.pdf
Which seems to match what happens when you convert, but is not a useful dual-units chart.

And finally, I found this page on Engineering Toolbox, which explained the whole thing: Moist Air - Enthalpy

Note! - the “reference” points for the metric and imperial enthalpies are different.

  • for eq. (5) metric units - the “reference” point for enthalpy h = 0 (kJ/kg) is t = 0 oC (32oF) and x = 0 kg/kg
  • for eq. (6) imperial units - the “reference” point for enthalpy h = 0 (Btu/lb) is t = 0 oF (-17.8oC) and x = 0 lb/lb. The evaporation heat for water at 0 oF is 1061 Btu/lb as used in eq. (6).

You can not convert from metric to imperial enthalpy or vice versa directly.

…so it appears that, like everything else related to psychrometry, it’s dirty. Nice of them to make it look like the units work like standard units… I’m going to try to borrow the proper ASHRAE book this week and confirm.

Edit: Also this: Enthalpy conversion btu/lb to kj/kg

I was wondering if this was it, my memory was that it’s a subjective value. That makes perfect sense.

What ASHRAE book are you after? I’ve got all the standard ones.

I ended up just asking the friend with the books and he confirmed that it’s a hack – if you start messing around with relative temperature scales, you have to treat the results as deltas only, or manually add the offset when converting.

The problem is, the unit labels (BTU/lb, kJ/kg) are missing any indication that they are offset from absolute zero. Not a problem if you happen know the secret, but a terrible communication tool.

Admittedly, it’s normally rare that one would be switching unit systems and deltas are normally what one uses those types of values for anyway. All of that material was purpose-made for HVAC design, not abstract scientific curiosity. As soon as you use a temperature scale other than Kelvin you’ve pretty much entered the world of relative values already. :slight_smile:

Does it seem like there’s anything stopping Thermal Comfort from using Imperial units for Enthalpy and Absolute Humidity? While it doesn’t REALLY matter, it’d be nice to have it use the user’s selected unit system.

Internally, Thermal Comfort uses celsius. I don’t think the Thermal Comfort module is actually aware of the user’s selected output units; it appears HA is what converts outputs marked as temperature to the user’s units. I don’t know how to hook into that part of the system yet.

psychrolib can be configured for SI or IP units, so if you wanted to calculate those fields in in imperial, you could just configure it for IP and convert the input values.

Have you considered reporting an issue to Issues · dolezsa/thermal_comfort · GitHub? If you’re able to create a pull request, I’m sure that would be welcomed.

I’m also working on a custom component to let me know if the windows should be open or closed. The reason it’s a custom component instead of a simple sensor is that it links to an hourly weather forecast and calculates future open or close times (for open windows at night).