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