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