A comfort reading
Relative humidity is a percentage of a limit that moves with temperature, so 60 % means something different in every room. The dew point does not, and it takes four lines of arithmetic on the two numbers the DHT22 already gives you. At 24 °C and 60 %, its ±2 % humidity puts the dew point within about ±0.5 °C; a DHT11's ±5 % makes that ±1.3 °C.
A number that means the same everywhere
Move both sliders, then switch the sensor.
The dew point is the temperature the air would have to cool to before water came out of it. It is measured against nothing that moves, so a 12 °C dew point is the same amount of water in a cellar and in a greenhouse, and two rooms at different temperatures compare directly.
It is also what predicts the things people ask a humidity sensor about: condensation on a cold window, damp in a corner, a night that is hard to sleep through.
The arithmetic
Four lines, from the two numbers the sensor already gave you:
float dewPoint(float tC, float rh) {
float g = log(rh / 100.0) + (17.62 * tC) / (243.12 + tC);
return (243.12 * g) / (17.62 - g);
}That is the Magnus–Tetens approximation with Sonntag's 1990 coefficients, good to about 0.35 °C from −45 to 60 °C. It is not where the error comes from.
Where the error comes from
From the humidity reading, passed through that formula. Run the arithmetic at both ends of a sensor's humidity tolerance and the dew point comes out as a band.
At 24 °C and 60 %, the DHT22's ±2 % gives a dew point within about ±0.5 °C. The DHT11's ±5 % gives about ±1.3 °C, a band two and a half times as wide, which can straddle two of the bands below where the DHT22's sits in one. That is the concrete version of DHT11 or DHT22: the precision matters when something acts on the number.
The ±2 % is the DHT22's typical figure; its datasheet gives ±5 % as the maximum. So the band is a fair guide to how steady the reading is, and a generous one for how right it is.
Bands worth using
A scale commonly used in US weather forecasting, converted from Fahrenheit and rounded:
| Dew point | It feels |
|---|---|
| under 10 °C | dry |
| 10 to 16 °C | comfortable |
| 16 to 18 °C | sticky |
| 18 to 21 °C | humid |
| over 21 °C | oppressive |
For a home the trend matters more than the band. A dew point that climbs every evening and does not come back down is a ventilation problem, and it shows in the log before it shows on a wall.
The code
Reads the DHT22 every ten seconds and prints temperature, humidity, the dew point computed from both, and a one-word verdict from the dew point bands in the table below.
/*
DHT22 - a comfort reading TK39 / /p/tk39
Wiring. Count from the square pad on the TinkerBlock board, sensor
side up, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
NC -> nothing (unconnected on the board)
DATA -> D2 on an Uno, GPIO 18 on an ESP32,
GPIO 4 on an ESP32-S3, GP2 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. ESP32S3 Dev Module
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
Tools > Manage Libraries DHT sensor library, by Adafruit.
Say yes to Adafruit Unified Sensor.
Mount the sensor in free air, off the board: a warm sensor reads
dry, and the dew point inherits the error.
*/
#include <DHT.h>
#include <math.h>
// Uno: 2. ESP32: 18. ESP32-S3: 4. Pico: 2.
#define DHT_PIN 4
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
// Magnus-Tetens, Sonntag 1990 coefficients: about 0.35 C
// between -45 and 60 C.
const float MAGNUS_A = 17.62;
const float MAGNUS_B = 243.12;
float dewPoint(float tC, float rh) {
if (rh < 1) rh = 1; // log(0) is not a temperature
float g = log(rh / 100.0) + (MAGNUS_A * tC) / (MAGNUS_B + tC);
return (MAGNUS_B * g) / (MAGNUS_A - g);
}
const char *howItFeels(float dp) {
if (dp < 10) return "dry";
if (dp < 16) return "comfortable";
if (dp < 18) return "sticky";
if (dp < 21) return "humid";
return "oppressive";
}
const unsigned long EVERY_MS = 10000;
unsigned long last = 0;
void setup() {
Serial.begin(115200);
dht.begin();
last = millis();
}
void loop() {
if (millis() - last < EVERY_MS) return;
last += EVERY_MS;
float rh = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(rh) || isnan(t)) {
Serial.println("read failed");
return;
}
float dp = dewPoint(t, rh);
Serial.print(t, 1); Serial.print(" C ");
Serial.print(rh, 1); Serial.print(" % dew point ");
Serial.print(dp, 1); Serial.print(" C ");
Serial.println(howItFeels(dp));
}The dew point is at or below the air temperature, and the two meet at 100 %. A dew point above the temperature means the humidity reading is wrong, not the arithmetic. The sketch compiles for an Uno and an ESP32-S3.
View on GitHub · blocks/tk39-dht22/arduino/dht22_comfort/dht22_comfort.ino @ v1.13When it does not work
That cannot happen in air, so the humidity reading is at fault. A sensor that has just been breathed on, or has come in from the cold and has water on it, can read at or near 100 % for a while. Give it time in ordinary air; the datasheet warns against using it where dew forms on it.
Because it does not compare between rooms. 60 % in a 30 °C conservatory is about three times as much water as 60 % in a 12 °C garage, and only one of them feels sticky. The dew point is a temperature, so the same number means the same air everywhere.
Add #include <math.h> at the top, as the sketch does. The ESP32 cores usually pull it in through another header, which is why it is easy to leave out and then find missing on an Uno.
The dew point is sitting on a boundary. Change the word only when the dew point has crossed a boundary by half a degree, which is about the DHT22's own uncertainty here. A DHT11 will do it more, because it moves in whole steps.
A sketch that says DHT11 on a DHT22, and the other way round: one prints a steady wrong number, the other prints nan.
The wrong type →Edit this page — content/books/dht22/a-comfort-reading.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.