ESPHome  2024.4.1
dht.cpp
Go to the documentation of this file.
1 #include "dht.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/helpers.h"
4 
5 namespace esphome {
6 namespace dht {
7 
8 static const char *const TAG = "dht";
9 
10 void DHT::setup() {
11  ESP_LOGCONFIG(TAG, "Setting up DHT...");
12  this->pin_->digital_write(true);
13  this->pin_->setup();
14  this->pin_->digital_write(true);
15 }
17  ESP_LOGCONFIG(TAG, "DHT:");
18  LOG_PIN(" Pin: ", this->pin_);
19  if (this->is_auto_detect_) {
20  ESP_LOGCONFIG(TAG, " Auto-detected model: %s", this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22");
21  } else if (this->model_ == DHT_MODEL_DHT11) {
22  ESP_LOGCONFIG(TAG, " Model: DHT11");
23  } else {
24  ESP_LOGCONFIG(TAG, " Model: DHT22 (or equivalent)");
25  }
26 
27  LOG_UPDATE_INTERVAL(this);
28 
29  LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
30  LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
31 }
32 
33 void DHT::update() {
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, "Got 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);
54  this->status_clear_warning();
55  } else {
56  const char *str = "";
57  if (this->is_auto_detect_) {
58  str = " and consider manually specifying the DHT model using the model option";
59  }
60  ESP_LOGW(TAG, "Invalid readings! Please check your wiring (pull-up resistor, pin number)%s.", str);
61  if (this->temperature_sensor_ != nullptr)
63  if (this->humidity_sensor_ != nullptr)
64  this->humidity_sensor_->publish_state(NAN);
65  this->status_set_warning();
66  }
67 }
68 
71  this->model_ = model;
72  this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT;
73 }
74 bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
75  *humidity = NAN;
76  *temperature = NAN;
77 
78  int error_code = 0;
79  int8_t i = 0;
80  uint8_t data[5] = {0, 0, 0, 0, 0};
81 
82  this->pin_->digital_write(false);
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) {
89  delayMicroseconds(500);
90  this->pin_->digital_write(true);
92  } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
93  delayMicroseconds(2000);
94  } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) {
95  delayMicroseconds(1000);
96  } else {
97  delayMicroseconds(800);
98  }
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)
106  delayMicroseconds(70);
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;
119  } else {
120  error_code = 2;
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  if ((end_time = micros()) - start_time > 90) {
134  if (i < 0) {
135  error_code = 3;
136  } else {
137  error_code = 4;
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  if (!report_errors && error_code != 0)
159  return false;
160 
161  switch (error_code) {
162  case 1:
163  ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!");
164  return false;
165  case 2:
166  ESP_LOGW(TAG, "Rising edge for bit %d failed!", i);
167  return false;
168  case 3:
169  ESP_LOGW(TAG, "Requesting data from DHT failed!");
170  return false;
171  case 4:
172  ESP_LOGW(TAG, "Falling edge for bit %d failed!", i);
173  return false;
174  case 0:
175  default:
176  break;
177  }
178 
179  ESP_LOGVV(TAG,
180  "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
181  ", Temp=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN ", Checksum=0b" BYTE_TO_BINARY_PATTERN,
182  BYTE_TO_BINARY(data[0]), BYTE_TO_BINARY(data[1]), BYTE_TO_BINARY(data[2]), BYTE_TO_BINARY(data[3]),
183  BYTE_TO_BINARY(data[4]));
184 
185  uint8_t checksum_a = data[0] + data[1] + data[2] + data[3];
186  // On the DHT11, two algorithms for the checksum seem to be used, either the one from the DHT22,
187  // or just using bytes 0 and 2
188  uint8_t checksum_b = this->model_ == DHT_MODEL_DHT11 ? (data[0] + data[2]) : checksum_a;
189 
190  if (checksum_a != data[4] && checksum_b != data[4]) {
191  if (report_errors) {
192  ESP_LOGW(TAG, "Checksum invalid: %u!=%u", checksum_a, data[4]);
193  }
194  return false;
195  }
196 
197  if (this->model_ == DHT_MODEL_DHT11) {
198  if (checksum_a == data[4]) {
199  // Data format: 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit
200  // check sum - some models always have 0 in the decimal part
201  const uint16_t raw_temperature = uint16_t(data[2]) * 10 + (data[3] & 0x7F);
202  *temperature = raw_temperature / 10.0f;
203  if ((data[3] & 0x80) != 0) {
204  // negative
205  *temperature *= -1;
206  }
207 
208  const uint16_t raw_humidity = uint16_t(data[0]) * 10 + data[1];
209  *humidity = raw_humidity / 10.0f;
210  } else {
211  // For compatibility with DHT11 models which might only use 2 bytes checksums, only use the data from these two
212  // bytes
213  *temperature = data[2];
214  *humidity = data[0];
215  }
216  } else {
217  uint16_t raw_humidity = (uint16_t(data[0] & 0xFF) << 8) | (data[1] & 0xFF);
218  uint16_t raw_temperature = (uint16_t(data[2] & 0xFF) << 8) | (data[3] & 0xFF);
219 
220  if (raw_temperature & 0x8000) {
221  if (!(raw_temperature & 0x4000))
222  raw_temperature = ~(raw_temperature & 0x7FFF);
223  } else if (raw_temperature & 0x800) {
224  raw_temperature |= 0xf000;
225  }
226 
227  if (raw_temperature == 1 && raw_humidity == 10) {
228  if (report_errors) {
229  ESP_LOGW(TAG, "Invalid temperature+humidity! Sensor reported 1°C and 1%% Hum");
230  }
231  return false;
232  }
233 
234  *humidity = raw_humidity * 0.1f;
235  if (*humidity > 100)
236  *humidity = NAN;
237  *temperature = int16_t(raw_temperature) * 0.1f;
238  }
239 
240  if (*temperature == 0.0f && (*humidity == 1.0f || *humidity == 2.0f)) {
241  if (report_errors) {
242  ESP_LOGW(TAG, "DHT reports invalid data. Is the update interval too high or the sensor damaged?");
243  }
244  return false;
245  }
246 
247  return true;
248 }
249 
250 } // namespace dht
251 } // namespace esphome
virtual void digital_write(bool value)=0
sensor::Sensor * temperature_sensor_
Definition: dht.h:60
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
DHTModel model_
Definition: dht.h:58
void set_dht_model(DHTModel model)
Manually select the DHT model.
Definition: dht.cpp:70
InternalGPIOPin * pin_
Definition: dht.h:57
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
bool is_auto_detect_
Definition: dht.h:59
sensor::Sensor * humidity_sensor_
Definition: dht.h:61
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
uint32_t IRAM_ATTR HOT micros()
Definition: core.cpp:27
float get_setup_priority() const override
HARDWARE_LATE setup priority.
Definition: dht.cpp:69
void dump_config() override
Definition: dht.cpp:16
void status_clear_warning()
Definition: component.cpp:166
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
DHTModel
Definition: dht.h:10
uint16_t temperature
Definition: sun_gtil2.cpp:26
bool read_sensor_(float *temperature, float *humidity, bool report_errors)
Definition: dht.cpp:74
virtual bool digital_read()=0
void setup() override
Set up the pins and check connection.
Definition: dht.cpp:10
void update() override
Update sensor values and push them to the frontend.
Definition: dht.cpp:33
Helper class to disable interrupts.
Definition: helpers.h:587
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition: core.cpp:28