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