ESPHome 2025.6.3
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
4namespace esphome {
5namespace absolute_humidity {
6
7static const char *const TAG = "absolute_humidity.sensor";
8
10 ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
11
12 ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
13 this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
14 if (this->temperature_sensor_->has_state()) {
16 }
17
18 ESP_LOGD(TAG, " Added callback for relative humidity '%s'", this->humidity_sensor_->get_name().c_str());
19 this->humidity_sensor_->add_on_state_callback([this](float state) { this->humidity_callback_(state); });
20 if (this->humidity_sensor_->has_state()) {
22 }
23}
24
26 LOG_SENSOR("", "Absolute Humidity", this);
27
28 switch (this->equation_) {
29 case BUCK:
30 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Buck");
31 break;
32 case TETENS:
33 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Tetens");
34 break;
35 case WOBUS:
36 ESP_LOGCONFIG(TAG, "Saturation Vapor Pressure Equation: Wobus");
37 break;
38 default:
39 ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
40 break;
41 }
42
43 ESP_LOGCONFIG(TAG,
44 "Sources\n"
45 " Temperature: '%s'\n"
46 " Relative Humidity: '%s'",
47 this->temperature_sensor_->get_name().c_str(), this->humidity_sensor_->get_name().c_str());
48}
49
51
53 if (!this->next_update_) {
54 return;
55 }
56 this->next_update_ = false;
57
58 // Ensure we have source data
59 const bool no_temperature = std::isnan(this->temperature_);
60 const bool no_humidity = std::isnan(this->humidity_);
61 if (no_temperature || no_humidity) {
62 if (no_temperature) {
63 ESP_LOGW(TAG, "No valid state from temperature sensor!");
64 }
65 if (no_humidity) {
66 ESP_LOGW(TAG, "No valid state from temperature sensor!");
67 }
68 ESP_LOGW(TAG, "Unable to calculate absolute humidity.");
69 this->publish_state(NAN);
70 this->status_set_warning();
71 return;
72 }
73
74 // Convert to desired units
75 const float temperature_c = this->temperature_;
76 const float temperature_k = temperature_c + 273.15;
77 const float hr = this->humidity_ / 100;
78
79 // Calculate saturation vapor pressure
80 float es;
81 switch (this->equation_) {
82 case BUCK:
83 es = es_buck(temperature_c);
84 break;
85 case TETENS:
86 es = es_tetens(temperature_c);
87 break;
88 case WOBUS:
89 es = es_wobus(temperature_c);
90 break;
91 default:
92 ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
93 this->publish_state(NAN);
94 this->status_set_error();
95 return;
96 }
97 ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
98
99 // Calculate absolute humidity
100 const float absolute_humidity = vapor_density(es, hr, temperature_k);
101
102 // Publish absolute humidity
103 ESP_LOGD(TAG, "Publishing absolute humidity %f g/m³", 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) {
113 a = 0.61121;
114 b = 18.678;
115 c = 234.5;
116 d = 257.14;
117 } else {
118 a = 0.61115;
119 b = 18.678;
120 c = 233.7;
121 d = 279.82;
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) {
130 a = 17.27;
131 b = 237.3;
132 } else {
133 a = 21.875;
134 b = 265.5;
135 }
136 return 0.61078 * 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 const float c0 = +0.99999683e00;
156 const float c1 = -0.90826951e-02;
157 const float c2 = +0.78736169e-04;
158 const float c3 = -0.61117958e-06;
159 const float c4 = +0.43884187e-08;
160 const float c5 = -0.29883885e-10;
161 const float c6 = +0.21874425e-12;
162 const float c7 = -0.17892321e-14;
163 const float c8 = +0.11112018e-16;
164 const float c9 = -0.30994571e-19;
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.61078 / pow(p, 8);
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.html
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; // vapor pressure of the air (Pa)
178 const float mw = 18.01528; // molar mass of water (g⋅mol⁻¹)
179 const float r = 8.31446261815324; // molar gas constant (J⋅K⁻¹)
180 return (ea * mw) / (r * ta);
181}
182
183} // namespace absolute_humidity
184} // namespace esphome
void status_set_warning(const char *message="unspecified")
void status_set_error(const char *message="unspecified")
void status_clear_warning()
const StringRef & get_name() const
bool has_state() const
Definition entity_base.h:53
constexpr const char * c_str() const
Definition string_ref.h:69
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 publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
float get_state() const
Getter-syntax for .state.
Definition sensor.cpp:91
void add_on_state_callback(std::function< void(float)> &&callback)
Add a callback that will be called every time a filtered value arrives.
Definition sensor.cpp:54
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:136
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:20
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7