ESPHome 2025.5.0
Loading...
Searching...
No Matches
dht.cpp
Go to the documentation of this file.
1#include "dht.h"
2#include "esphome/core/log.h"
4
5namespace esphome {
6namespace dht {
7
8static const char *const TAG = "dht";
9
10void DHT::setup() {
11 ESP_LOGCONFIG(TAG, "Setting up DHT...");
12 this->pin_->digital_write(true);
13 this->pin_->setup();
14 this->pin_->digital_write(true);
15}
17 ESP_LOGCONFIG(TAG, "DHT:");
18 LOG_PIN(" Pin: ", this->pin_);
19 if (this->is_auto_detect_) {
20 ESP_LOGCONFIG(TAG, " Auto-detected model: %s", this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22");
21 } else if (this->model_ == DHT_MODEL_DHT11) {
22 ESP_LOGCONFIG(TAG, " Model: DHT11");
23 } else {
24 ESP_LOGCONFIG(TAG, " Model: DHT22 (or equivalent)");
25 }
26 ESP_LOGCONFIG(TAG, " Internal Pull-up: %s", ONOFF(this->pin_->get_flags() & gpio::FLAG_PULLUP));
27
28 LOG_UPDATE_INTERVAL(this);
29
30 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
31 LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
32}
33
35 float temperature, humidity;
36 bool success;
37 if (this->model_ == DHT_MODEL_AUTO_DETECT) {
38 this->model_ = DHT_MODEL_DHT22;
39 success = this->read_sensor_(&temperature, &humidity, false);
40 if (!success) {
41 this->model_ = DHT_MODEL_DHT11;
42 return;
43 }
44 } else {
45 success = this->read_sensor_(&temperature, &humidity, true);
46 }
47
48 if (success) {
49 ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity);
50
51 if (this->temperature_sensor_ != nullptr)
52 this->temperature_sensor_->publish_state(temperature);
53 if (this->humidity_sensor_ != nullptr)
54 this->humidity_sensor_->publish_state(humidity);
56 } else {
57 const char *str = "";
58 if (this->is_auto_detect_) {
59 str = " and consider manually specifying the DHT model using the model option";
60 }
61 ESP_LOGW(TAG, "Invalid readings! Please check your wiring (pull-up resistor, pin number)%s.", str);
62 if (this->temperature_sensor_ != nullptr)
64 if (this->humidity_sensor_ != nullptr)
66 this->status_set_warning();
67 }
68}
69
72 this->model_ = model;
74}
75bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
76 *humidity = NAN;
77 *temperature = NAN;
78
79 int error_code = 0;
80 int8_t i = 0;
81 uint8_t data[5] = {0, 0, 0, 0, 0};
82
83 this->pin_->digital_write(false);
85 this->pin_->digital_write(false);
86
87 if (this->model_ == DHT_MODEL_DHT11) {
88 delayMicroseconds(18000);
89 } else if (this->model_ == DHT_MODEL_SI7021) {
90#ifdef USE_ESP8266
92 this->pin_->digital_write(true);
94#else
96 this->pin_->digital_write(true);
97#endif
98 } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
100 } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) {
101 delayMicroseconds(1000);
102 } else {
104 }
105 this->pin_->pin_mode(this->pin_->get_flags());
106
107 {
108 InterruptLock lock;
109 // Host pull up 20-40us then DHT response 80us
110 // Start waiting for initial rising edge at the center when we
111 // expect the DHT response (30us+40us)
113
114 uint8_t bit = 7;
115 uint8_t byte = 0;
116
117 for (i = -1; i < 40; i++) {
118 uint32_t start_time = micros();
119
120 // Wait for rising edge
121 while (!this->pin_->digital_read()) {
122 if (micros() - start_time > 90) {
123 if (i < 0) {
124 error_code = 1;
125 } else {
126 error_code = 2;
127 }
128 break;
129 }
130 }
131 if (error_code != 0)
132 break;
133
134 start_time = micros();
135 uint32_t end_time = start_time;
136
137 // Wait for falling edge
138 while (this->pin_->digital_read()) {
139 end_time = micros();
140 if (end_time - start_time > 90) {
141 if (i < 0) {
142 error_code = 3;
143 } else {
144 error_code = 4;
145 }
146 break;
147 }
148 }
149 if (error_code != 0)
150 break;
151
152 if (i < 0)
153 continue;
154
155 if (end_time - start_time >= 40) {
156 data[byte] |= 1 << bit;
157 }
158 if (bit == 0) {
159 bit = 7;
160 byte++;
161 } else {
162 bit--;
163 }
164 }
165 }
166 if (!report_errors && error_code != 0)
167 return false;
168
169 switch (error_code) {
170 case 1:
171 ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!");
172 return false;
173 case 2:
174 ESP_LOGW(TAG, "Rising edge for bit %d failed!", i);
175 return false;
176 case 3:
177 ESP_LOGW(TAG, "Requesting data from DHT failed!");
178 return false;
179 case 4:
180 ESP_LOGW(TAG, "Falling edge for bit %d failed!", i);
181 return false;
182 case 0:
183 default:
184 break;
185 }
186
187 ESP_LOGVV(TAG,
188 "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
189 ", Temp=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN ", Checksum=0b" BYTE_TO_BINARY_PATTERN,
190 BYTE_TO_BINARY(data[0]), BYTE_TO_BINARY(data[1]), BYTE_TO_BINARY(data[2]), BYTE_TO_BINARY(data[3]),
191 BYTE_TO_BINARY(data[4]));
192
193 uint8_t checksum_a = data[0] + data[1] + data[2] + data[3];
194 // On the DHT11, two algorithms for the checksum seem to be used, either the one from the DHT22,
195 // or just using bytes 0 and 2
196 uint8_t checksum_b = this->model_ == DHT_MODEL_DHT11 ? (data[0] + data[2]) : checksum_a;
197
198 if (checksum_a != data[4] && checksum_b != data[4]) {
199 if (report_errors) {
200 ESP_LOGW(TAG, "Checksum invalid: %u!=%u", checksum_a, data[4]);
201 }
202 return false;
203 }
204
205 if (this->model_ == DHT_MODEL_DHT11) {
206 if (checksum_a == data[4]) {
207 // Data format: 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit
208 // check sum - some models always have 0 in the decimal part
209 const uint16_t raw_temperature = uint16_t(data[2]) * 10 + (data[3] & 0x7F);
210 *temperature = raw_temperature / 10.0f;
211 if ((data[3] & 0x80) != 0) {
212 // negative
213 *temperature *= -1;
214 }
215
216 const uint16_t raw_humidity = uint16_t(data[0]) * 10 + data[1];
217 *humidity = raw_humidity / 10.0f;
218 } else {
219 // For compatibility with DHT11 models which might only use 2 bytes checksums, only use the data from these two
220 // bytes
221 *temperature = data[2];
222 *humidity = data[0];
223 }
224 } else {
225 uint16_t raw_humidity = (uint16_t(data[0] & 0xFF) << 8) | (data[1] & 0xFF);
226 uint16_t raw_temperature = (uint16_t(data[2] & 0xFF) << 8) | (data[3] & 0xFF);
227
228 if (raw_temperature & 0x8000) {
229 if (!(raw_temperature & 0x4000))
230 raw_temperature = ~(raw_temperature & 0x7FFF);
231 } else if (raw_temperature & 0x800) {
232 raw_temperature |= 0xf000;
233 }
234
235 if (raw_temperature == 1 && raw_humidity == 10) {
236 if (report_errors) {
237 ESP_LOGW(TAG, "Invalid temperature+humidity! Sensor reported 1°C and 1%% Hum");
238 }
239 return false;
240 }
241
242 *humidity = raw_humidity * 0.1f;
243 if (*humidity > 100)
244 *humidity = NAN;
245 *temperature = int16_t(raw_temperature) * 0.1f;
246 }
247
248 if (*temperature == 0.0f && (*humidity == 1.0f || *humidity == 2.0f)) {
249 if (report_errors) {
250 ESP_LOGW(TAG, "DHT reports invalid data. Is the update interval too high or the sensor damaged?");
251 }
252 return false;
253 }
254
255 return true;
256}
257
258} // namespace dht
259} // namespace esphome
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual gpio::Flags get_flags() const =0
Retrieve GPIO pin flags.
virtual bool digital_read()=0
Helper class to disable interrupts.
Definition helpers.h:614
bool is_auto_detect_
Definition dht.h:59
float get_setup_priority() const override
HARDWARE_LATE setup priority.
Definition dht.cpp:70
void update() override
Update sensor values and push them to the frontend.
Definition dht.cpp:34
void dump_config() override
Definition dht.cpp:16
sensor::Sensor * temperature_sensor_
Definition dht.h:60
sensor::Sensor * humidity_sensor_
Definition dht.h:61
InternalGPIOPin * pin_
Definition dht.h:57
DHTModel model_
Definition dht.h:58
void setup() override
Set up the pins and check connection.
Definition dht.cpp:10
bool read_sensor_(float *temperature, float *humidity, bool report_errors)
Definition dht.cpp:75
void set_dht_model(DHTModel model)
Manually select the DHT model.
Definition dht.cpp:71
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
@ DHT_MODEL_AUTO_DETECT
Definition dht.h:11
@ DHT_MODEL_DHT22
Definition dht.h:13
@ DHT_MODEL_AM2302
Definition dht.h:15
@ DHT_MODEL_SI7021
Definition dht.h:17
@ DHT_MODEL_DHT22_TYPE2
Definition dht.h:18
@ DHT_MODEL_AM2120
Definition dht.h:14
@ DHT_MODEL_DHT11
Definition dht.h:12
@ FLAG_OUTPUT
Definition gpio.h:19
@ FLAG_PULLUP
Definition gpio.h:21
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:19
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
uint32_t IRAM_ATTR HOT micros()
Definition core.cpp:29
uint16_t temperature
Definition sun_gtil2.cpp:12