ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
dht.cpp
Go to the documentation of this file.
1#include "dht.h"
3#include "esphome/core/log.h"
4
5namespace esphome::dht {
6
7static const char *const TAG = "dht";
8
9void DHT::setup() {
10 this->t_pin_->digital_write(true);
11 this->t_pin_->setup();
12#ifdef USE_ESP32
14#endif
15 this->t_pin_->digital_write(true);
16}
17
19 ESP_LOGCONFIG(TAG,
20 "DHT:\n"
21 " %sModel: %s\n"
22 " Internal pull-up: %s",
23 this->is_auto_detect_ ? "Auto-detected " : "",
24 this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22 or equivalent",
25 ONOFF(this->t_pin_->get_flags() & gpio::FLAG_PULLUP));
26 LOG_PIN(" Pin: ", this->t_pin_);
27 LOG_UPDATE_INTERVAL(this);
28 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
29 LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
30}
31
33 float temperature, humidity;
34 bool success;
35 if (this->model_ == DHT_MODEL_AUTO_DETECT) {
36 this->model_ = DHT_MODEL_DHT22;
37 success = this->read_sensor_(&temperature, &humidity, false);
38 if (!success) {
39 this->model_ = DHT_MODEL_DHT11;
40 return;
41 }
42 } else {
43 success = this->read_sensor_(&temperature, &humidity, true);
44 }
45
46 if (success) {
47 if (this->temperature_sensor_ != nullptr)
48 this->temperature_sensor_->publish_state(temperature);
49 if (this->humidity_sensor_ != nullptr)
50 this->humidity_sensor_->publish_state(humidity);
52 } else {
53 ESP_LOGW(TAG, "Invalid readings");
54 if (this->temperature_sensor_ != nullptr)
56 if (this->humidity_sensor_ != nullptr)
58 this->status_set_warning();
59 }
60}
61
63 this->model_ = model;
65}
66
67bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
68 *humidity = NAN;
69 *temperature = NAN;
70
71 int error_code = 0;
72 uint8_t data[5] = {};
73
74#ifndef USE_ESP32
76#endif
77 this->pin_.digital_write(false);
78
79 if (this->model_ == DHT_MODEL_DHT11) {
80 delayMicroseconds(18000);
81 } else if (this->model_ == DHT_MODEL_SI7021) {
83 } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
85 } else {
87 }
88
89#ifdef USE_ESP32
90 this->pin_.digital_write(true);
91#else
92 this->pin_.pin_mode(this->t_pin_->get_flags());
93#endif
94
95 {
96 InterruptLock lock;
97 // Host pull up 20-40us then DHT response 80us
98 // Start waiting for initial rising edge at the center when we
99 // expect the DHT response (30us+40us)
101
102 uint8_t bit = 7;
103 uint8_t byte = 0;
104
105 // On 32-bit Xtensa/RISC-V cores, int8_t would require masking/sign-extension for comparisons
106 // vs. native int. Using int i is native word size — small win in the timing-critical section.
107 for (int i = -1; i < 40; i++) {
108 uint32_t start_time = micros();
109
110 // Wait for rising edge
111 while (!this->pin_.digital_read()) {
112 if (micros() - start_time > 90) {
113 if (i < 0) {
114 error_code = 1; // line didn't clear
115 } else {
116 error_code = 2; // rising edge for bit i timeout
117 }
118 break;
119 }
120 }
121 if (error_code != 0)
122 break;
123
124 start_time = micros();
125 uint32_t end_time = start_time;
126
127 // Wait for falling edge
128 while (this->pin_.digital_read()) {
129 end_time = micros();
130 if (end_time - start_time > 90) {
131 if (i < 0) {
132 error_code = 3; // requesting data failed
133 } else {
134 error_code = 4; // falling edge for bit i timeout
135 }
136 break;
137 }
138 }
139 if (error_code != 0)
140 break;
141
142 if (i < 0)
143 continue;
144
145 if (end_time - start_time >= 40) {
146 data[byte] |= 1 << bit;
147 }
148 if (bit == 0) {
149 bit = 7;
150 byte++;
151 } else {
152 bit--;
153 }
154 }
155 }
156 if (error_code != 0) {
157 if (report_errors)
158 ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
159 return false;
160 }
161
162 ESP_LOGVV(TAG,
163 "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
164 ", Temp=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN ", Checksum=0b" BYTE_TO_BINARY_PATTERN,
165 BYTE_TO_BINARY(data[0]), BYTE_TO_BINARY(data[1]), BYTE_TO_BINARY(data[2]), BYTE_TO_BINARY(data[3]),
166 BYTE_TO_BINARY(data[4]));
167
168 uint8_t checksum_a = data[0] + data[1] + data[2] + data[3];
169 // On the DHT11, two algorithms for the checksum seem to be used, either the one from the DHT22,
170 // or just using bytes 0 and 2
171 uint8_t checksum_b = this->model_ == DHT_MODEL_DHT11 ? (data[0] + data[2]) : checksum_a;
172
173 if (checksum_a != data[4] && checksum_b != data[4]) {
174 if (report_errors) {
175 ESP_LOGW(TAG, "Invalid checksum");
176 }
177 return false;
178 }
179
180 if (this->model_ == DHT_MODEL_DHT11) {
181 if (checksum_a == data[4]) {
182 // Data format: 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit
183 // check sum - some models always have 0 in the decimal part
184 const uint16_t raw_temperature = static_cast<uint16_t>(data[2]) * 10 + (data[3] & 0x7F);
185 *temperature = static_cast<float>(raw_temperature) / 10.0f;
186 if ((data[3] & 0x80) != 0) {
187 // negative
188 *temperature *= -1;
189 }
190
191 const uint16_t raw_humidity = static_cast<uint16_t>(data[0]) * 10 + data[1];
192 *humidity = static_cast<float>(raw_humidity) / 10.0f;
193 } else {
194 // For compatibility with DHT11 models which might only use 2 bytes checksums, only use the data from these two
195 // bytes
196 *temperature = data[2];
197 *humidity = data[0];
198 }
199 } else {
200 uint16_t raw_humidity = encode_uint16(data[0], data[1]);
201 uint16_t raw_temperature = encode_uint16(data[2], data[3]);
202
203 if (raw_temperature & 0x8000) {
204 if (!(raw_temperature & 0x4000))
205 raw_temperature = ~(raw_temperature & 0x7FFF);
206 } else if (raw_temperature & 0x800) {
207 raw_temperature |= 0xf000;
208 }
209
210 if (raw_temperature == 1 && raw_humidity == 10) {
211 if (report_errors) {
212 ESP_LOGW(TAG, "Invalid data");
213 }
214 return false;
215 }
216
217 *humidity = static_cast<float>(raw_humidity) * 0.1f;
218 if (*humidity > 100.0f)
219 *humidity = NAN;
220 *temperature = static_cast<int16_t>(raw_temperature) * 0.1f;
221 }
222
223 if (*temperature == 0.0f && (*humidity == 1.0f || *humidity == 2.0f)) {
224 if (report_errors) {
225 ESP_LOGW(TAG, "Invalid data");
226 }
227 return false;
228 }
229 return true;
230}
231
232} // namespace esphome::dht
void status_clear_warning()
Definition component.h:306
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.
void digital_write(bool value)
Definition gpio.cpp:148
void pin_mode(gpio::Flags flags)
Definition gpio.cpp:157
Helper class to disable interrupts.
Definition helpers.h:2104
bool is_auto_detect_
Definition dht.h:61
void update() override
Update sensor values and push them to the frontend.
Definition dht.cpp:32
void dump_config() override
Definition dht.cpp:18
sensor::Sensor * temperature_sensor_
Definition dht.h:56
sensor::Sensor * humidity_sensor_
Definition dht.h:57
InternalGPIOPin * t_pin_
Definition dht.h:58
DHTModel model_
Definition dht.h:60
void setup() override
Set up the pins and check connection.
Definition dht.cpp:9
bool read_sensor_(float *temperature, float *humidity, bool report_errors)
Definition dht.cpp:67
ISRInternalGPIOPin pin_
Definition dht.h:59
void set_dht_model(DHTModel model)
Manually select the DHT model.
Definition dht.cpp:62
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
@ DHT_MODEL_AUTO_DETECT
Definition dht.h:10
@ DHT_MODEL_DHT22
Definition dht.h:12
@ DHT_MODEL_SI7021
Definition dht.h:16
@ DHT_MODEL_DHT22_TYPE2
Definition dht.h:17
@ DHT_MODEL_DHT11
Definition dht.h:11
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_OPEN_DRAIN
Definition gpio.h:29
@ FLAG_PULLUP
Definition gpio.h:30
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
uint32_t IRAM_ATTR HOT micros()
Definition core.cpp:29
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:881
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12