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