ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
absolute_humidity.cpp
Go to the documentation of this file.
1#include "esphome/core/log.h"
2#include "absolute_humidity.h"
3
5
6ESPHOME_LOG_TAG(TAG, "absolute_humidity.sensor");
7
10 this->temperature_ = state;
11 this->enable_loop();
12 });
13 ESP_LOGD(TAG, " Added callback for temperature '%s'", LOG_STR_ARG(this->temperature_sensor_->get_log_name()));
14 // Get initial value
15 if (this->temperature_sensor_->has_state()) {
17 }
18
19 this->humidity_sensor_->add_on_state_callback([this](float state) {
20 this->humidity_ = state;
21 this->enable_loop();
22 });
23 ESP_LOGD(TAG, " Added callback for relative humidity '%s'", LOG_STR_ARG(this->humidity_sensor_->get_log_name()));
24 // Get initial value
25 if (this->humidity_sensor_->has_state()) {
26 this->humidity_ = this->humidity_sensor_->get_state();
27 }
28}
29
31 LOG_SENSOR("", "Absolute Humidity", this);
32
33 switch (this->equation_) {
34 case BUCK:
35 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Buck");
36 break;
37 case TETENS:
38 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Tetens");
39 break;
40 case WOBUS:
41 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Wobus");
42 break;
43 default:
44 ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
45 break;
46 }
47
48 ESP_LOGCONFIG(TAG,
49 "Sources\n"
50 " Temperature: '%s'\n"
51 " Relative Humidity: '%s'",
52 LOG_STR_ARG(this->temperature_sensor_->get_log_name()),
53 LOG_STR_ARG(this->humidity_sensor_->get_log_name()));
54}
55
57 // Only run once
58 this->disable_loop();
59
60 // Ensure we have source data
61 const bool no_temperature{std::isnan(this->temperature_)};
62 const bool no_humidity{std::isnan(this->humidity_)};
63 if (no_temperature || no_humidity) {
64 if (no_temperature) {
65 ESP_LOGW(TAG, "No valid state from temperature sensor!");
66 }
67 if (no_humidity) {
68 ESP_LOGW(TAG, "No valid state from humidity sensor!");
69 }
70 this->publish_state(NAN);
71 this->status_set_warning(LOG_STR("Unable to calculate absolute humidity."));
72 return;
73 }
74
75 // Convert to desired units
76 const float temperature_c{this->temperature_};
77 const float temperature_k{temperature_c + 273.15f};
78 const float hr{this->humidity_ / 100.0f};
79
80 // Calculate saturation vapor pressure
81 float es;
82 switch (this->equation_) {
83 case BUCK:
84 es = es_buck(temperature_c);
85 break;
86 case TETENS:
87 es = es_tetens(temperature_c);
88 break;
89 case WOBUS:
90 es = es_wobus(temperature_c);
91 break;
92 default:
93 this->publish_state(NAN);
94 this->status_set_error(LOG_STR("Invalid saturation vapor pressure equation selection!"));
95 return;
96 }
97
98 // Calculate absolute humidity
99 const float absolute_humidity{vapor_density(es, hr, temperature_k)};
100
101 ESP_LOGD(TAG, "Saturation vapor pressure %f kPa, absolute humidity %f g/m³", es, absolute_humidity);
102
103 // Publish absolute humidity
104 this->status_clear_warning();
105 this->publish_state(absolute_humidity);
106}
107
108// Buck equation (https://en.wikipedia.org/wiki/Arden_Buck_equation)
109// More accurate than Tetens in normal meteorologic conditions
110float AbsoluteHumidityComponent::es_buck(float temperature_c) {
111 float a, b, c, d;
112 if (temperature_c >= 0.0f) {
113 a = 0.61121f;
114 b = 18.678f;
115 c = 234.5f;
116 d = 257.14f;
117 } else {
118 a = 0.61115f;
119 b = 18.678f;
120 c = 233.7f;
121 d = 279.82f;
122 }
123 return a * expf((b - (temperature_c / c)) * (temperature_c / (d + temperature_c)));
124}
125
126// Tetens equation (https://en.wikipedia.org/wiki/Tetens_equation)
127float AbsoluteHumidityComponent::es_tetens(float temperature_c) {
128 float a, b;
129 if (temperature_c >= 0.0f) {
130 a = 17.27f;
131 b = 237.3f;
132 } else {
133 a = 21.875f;
134 b = 265.5f;
135 }
136 return 0.61078f * expf((a * temperature_c) / (temperature_c + b));
137}
138
139// Wobus equation
140// https://wahiduddin.net/calc/density_altitude.htm
141// https://wahiduddin.net/calc/density_algorithms.htm
142// Calculate the saturation vapor pressure (kPa)
144 // THIS FUNCTION RETURNS THE SATURATION VAPOR PRESSURE ESW (MILLIBARS)
145 // OVER LIQUID WATER GIVEN THE TEMPERATURE T (CELSIUS). THE POLYNOMIAL
146 // APPROXIMATION BELOW IS DUE TO HERMAN WOBUS, A MATHEMATICIAN WHO
147 // WORKED AT THE NAVY WEATHER RESEARCH FACILITY, NORFOLK, VIRGINIA,
148 // BUT WHO IS NOW RETIRED. THE COEFFICIENTS OF THE POLYNOMIAL WERE
149 // CHOSEN TO FIT THE VALUES IN TABLE 94 ON PP. 351-353 OF THE SMITH-
150 // SONIAN METEOROLOGICAL TABLES BY ROLAND LIST (6TH EDITION). THE
151 // APPROXIMATION IS VALID FOR -50 < T < 100C.
152 //
153 // Baker, Schlatter 17-MAY-1982 Original version.
154
155 constexpr float c0{+0.99999683e+00f};
156 constexpr float c1{-0.90826951e-02f};
157 constexpr float c2{+0.78736169e-04f};
158 constexpr float c3{-0.61117958e-06f};
159 constexpr float c4{+0.43884187e-08f};
160 constexpr float c5{-0.29883885e-10f};
161 constexpr float c6{+0.21874425e-12f};
162 constexpr float c7{-0.17892321e-14f};
163 constexpr float c8{+0.11112018e-16f};
164 constexpr float c9{-0.30994571e-19f};
165 const float p{c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * (c6 + t * (c7 + t * (c8 + t * (c9)))))))))};
166 return 0.61078f / powf(p, 8.0f);
167}
168
169// From https://www.environmentalbiophysics.org/chalk-talk-how-to-calculate-absolute-humidity/
170// H/T to https://esphome.io/cookbook/bme280_environment/
171// H/T to https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
172float AbsoluteHumidityComponent::vapor_density(float es, float hr, float ta) {
173 // es = saturated vapor pressure (kPa)
174 // hr = relative humidity [0-1]
175 // ta = absolute temperature (K)
176
177 const float ea{hr * es * 1000.0f}; // vapor pressure of the air (Pa)
178 const float mw{18.01528f}; // molar mass of water (g⋅mol⁻¹)
179 const float r{8.31446261815324f}; // molar gas constant (J⋅K⁻¹)
180 return (ea * mw) / (r * ta);
181}
182
183} // namespace esphome::absolute_humidity
void enable_loop()
Enable this component's loop.
Definition component.h:248
void disable_loop()
Disable this component's loop.
void status_clear_warning()
Definition component.h:296
const LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
bool has_state() const
static float es_buck(float temperature_c)
Buck equation for saturation vapor pressure in kPa.
static float es_tetens(float temperature_c)
Tetens equation for saturation vapor pressure in kPa.
static float vapor_density(float es, float hr, float ta)
Calculate vapor density (absolute humidity) in g/m³.
static float es_wobus(float temperature_c)
Wobus equation for saturation vapor pressure in kPa.
void add_on_state_callback(F &&callback)
Add a callback that will be called every time a filtered value arrives.
Definition sensor.h:121
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
float get_state() const
Getter-syntax for .state.
Definition sensor.h:98
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:140
ESPHOME_LOG_TAG(TAG, "absolute_humidity.sensor")