9#if defined(__ESP32__) || defined(__ESP__)
10#define G_INT_ATTR IRAM_ATTR
15#define USTD_DHT_MAX_PIRQS (10)
24 DATA_ACQUISITION_INTRO_START,
25 DATA_ACQUISITION_INTRO_END,
34 BAD_START_PULSE_LEVEL = 1,
35 BAD_REPLY_PULSE_LENGTH = 2,
36 BAD_START_PULSE_END_LEVEL = 3,
37 BAD_REPLY_PULSE_LENGTH2 = 4,
38 BAD_START_PULSE_END_LEVEL2 = 5,
39 BAD_DATA_INTRO_PULSE_LENGTH = 6,
40 BAD_DATA_BIT_LENGTH = 7
43volatile DhtProtState pDhtState[USTD_DHT_MAX_PIRQS] = {DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE,
44 DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE, DhtProtState::NONE};
45volatile unsigned long pDhtBeginIrqTimer[USTD_DHT_MAX_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
46volatile uint8_t pDhtPortIrq[USTD_DHT_MAX_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
47volatile uint8_t pDhtBitCounter[USTD_DHT_MAX_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
48volatile DhtFailureCode pDhtFailureCode[USTD_DHT_MAX_PIRQS] = {DhtFailureCode::OK, DhtFailureCode::OK, DhtFailureCode::OK,
49 DhtFailureCode::OK, DhtFailureCode::OK, DhtFailureCode::OK, DhtFailureCode::OK, DhtFailureCode::OK, DhtFailureCode::OK,
51volatile int pDhtFailureData[USTD_DHT_MAX_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
52volatile uint8_t sensorDataBytes[USTD_DHT_MAX_PIRQS * 5];
54unsigned long dhtWakeUpPulse = 22000;
55int dhtInitialDelay = 20;
56int dhtSignalInitDelta = 25;
57int dhtSignalIntroDelta = 25;
58int dhtSignalDelta = 15;
60void G_INT_ATTR ustd_dht_pirq_master(uint8_t irqno) {
62 switch (pDhtState[irqno]) {
63 case DhtProtState::NONE:
65 case DhtProtState::START_PULSE_START:
67 case DhtProtState::START_PULSE_END:
68 if (digitalRead(pDhtPortIrq[irqno]) == LOW) {
69 pDhtBeginIrqTimer[irqno] = micros();
70 pDhtState[irqno] = DhtProtState::REPL_PULSE_START;
71 pDhtBitCounter[irqno] = 0;
72 for (
int i = 0; i < 5; i++)
73 sensorDataBytes[irqno * 5 + i] = 0;
76 pDhtFailureCode[irqno] = DhtFailureCode::BAD_START_PULSE_LEVEL;
77 pDhtState[irqno] = DhtProtState::DATA_ABORT;
80 case DhtProtState::REPL_PULSE_START:
81 if (digitalRead(pDhtPortIrq[irqno]) == HIGH) {
82 dt = timeDiff(pDhtBeginIrqTimer[irqno], micros());
83 if (dt > 80 - dhtInitialDelay - dhtSignalInitDelta && dt < 80 + dhtSignalInitDelta) {
84 pDhtBeginIrqTimer[irqno] = micros();
85 pDhtState[irqno] = DhtProtState::REPL_PULSE_START_H;
88 pDhtFailureCode[irqno] = DhtFailureCode::BAD_REPLY_PULSE_LENGTH;
89 pDhtFailureData[irqno] = dt;
90 pDhtState[irqno] = DhtProtState::DATA_ABORT;
93 pDhtFailureCode[irqno] = DhtFailureCode::BAD_START_PULSE_END_LEVEL;
94 pDhtState[irqno] = DhtProtState::DATA_ABORT;
97 case DhtProtState::REPL_PULSE_START_H:
98 if (digitalRead(pDhtPortIrq[irqno]) == LOW) {
99 dt = timeDiff(pDhtBeginIrqTimer[irqno], micros());
100 if (dt > 80 - dhtSignalInitDelta && dt < 80 + dhtSignalInitDelta) {
101 pDhtBeginIrqTimer[irqno] = micros();
102 pDhtState[irqno] = DhtProtState::DATA_ACQUISITION_INTRO_END;
105 pDhtFailureCode[irqno] = DhtFailureCode::BAD_REPLY_PULSE_LENGTH2;
106 pDhtFailureData[irqno] = dt;
107 pDhtState[irqno] = DhtProtState::DATA_ABORT;
110 pDhtFailureCode[irqno] = DhtFailureCode::BAD_START_PULSE_END_LEVEL2;
111 pDhtState[irqno] = DhtProtState::DATA_ABORT;
115 case DhtProtState::DATA_ACQUISITION_INTRO_START:
116 if (digitalRead(pDhtPortIrq[irqno]) == LOW) {
117 pDhtBeginIrqTimer[irqno] = micros();
118 pDhtState[irqno] = DhtProtState::DATA_ACQUISITION_INTRO_END;
120 case DhtProtState::DATA_ACQUISITION_INTRO_END:
121 if (digitalRead(pDhtPortIrq[irqno]) == HIGH) {
122 dt = timeDiff(pDhtBeginIrqTimer[irqno], micros());
123 if (dt > 50 - dhtSignalIntroDelta && dt < 50 + dhtSignalIntroDelta) {
124 pDhtBeginIrqTimer[irqno] = micros();
125 pDhtState[irqno] = DhtProtState::DATA_ACQUISITION;
128 pDhtFailureCode[irqno] = DhtFailureCode::BAD_DATA_INTRO_PULSE_LENGTH;
129 pDhtFailureData[irqno] = dt;
130 pDhtState[irqno] = DhtProtState::DATA_ABORT;
134 case DhtProtState::DATA_ACQUISITION:
135 if (digitalRead(pDhtPortIrq[irqno]) == LOW) {
136 dt = timeDiff(pDhtBeginIrqTimer[irqno], micros());
137 if (dt > 27 - dhtSignalDelta && dt < 27 + dhtSignalDelta) {
140 if (dt > 70 - dhtSignalDelta && dt < 70 + dhtSignalDelta) {
141 uint8_t
byte = pDhtBitCounter[irqno] / 8;
142 uint8_t bit = pDhtBitCounter[irqno] % 8;
143 sensorDataBytes[irqno * 5 + byte] |= 1 << (7 - bit);
145 pDhtFailureCode[irqno] = DhtFailureCode::BAD_DATA_BIT_LENGTH;
146 pDhtFailureData[irqno] = dt;
147 pDhtState[irqno] = DhtProtState::DATA_ABORT;
151 ++pDhtBitCounter[irqno];
152 if (pDhtBitCounter[irqno] == 40) {
153 pDhtState[irqno] = DhtProtState::DATA_OK;
155 pDhtBeginIrqTimer[irqno] = micros();
156 pDhtState[irqno] = DhtProtState::DATA_ACQUISITION_INTRO_END;
165void G_INT_ATTR ustd_dht_pirq0() {
166 ustd_dht_pirq_master(0);
168void G_INT_ATTR ustd_dht_pirq1() {
169 ustd_dht_pirq_master(1);
171void G_INT_ATTR ustd_dht_pirq2() {
172 ustd_dht_pirq_master(2);
174void G_INT_ATTR ustd_dht_pirq3() {
175 ustd_dht_pirq_master(3);
177void G_INT_ATTR ustd_dht_pirq4() {
178 ustd_dht_pirq_master(4);
180void G_INT_ATTR ustd_dht_pirq5() {
181 ustd_dht_pirq_master(5);
183void G_INT_ATTR ustd_dht_pirq6() {
184 ustd_dht_pirq_master(6);
186void G_INT_ATTR ustd_dht_pirq7() {
187 ustd_dht_pirq_master(7);
189void G_INT_ATTR ustd_dht_pirq8() {
190 ustd_dht_pirq_master(8);
192void G_INT_ATTR ustd_dht_pirq9() {
193 ustd_dht_pirq_master(9);
196void (*ustd_dht_irq_table[USTD_DHT_MAX_PIRQS])() = {ustd_dht_pirq0, ustd_dht_pirq1, ustd_dht_pirq2, ustd_dht_pirq3,
197 ustd_dht_pirq4, ustd_dht_pirq5, ustd_dht_pirq6, ustd_dht_pirq7,
198 ustd_dht_pirq8, ustd_dht_pirq9};
271 String DHT_VERSION =
"0.1.0";
276 uint8_t interruptIndex;
277 double temperatureValue, humidityValue;
278 bool bActive =
false;
279 unsigned long stateMachineTimeout = 0;
280 unsigned long lastPoll = 0;
281 unsigned long startPulseStartUs = 0;
282 unsigned long errs = 0;
283 unsigned long oks = 0;
284 unsigned long sensorPollRate = 3;
288 enum DHTType { DHT11,
291 enum FilterMode { FAST,
294 FilterMode filterMode;
295 ustd::sensorprocessor temperatureSensor = ustd::sensorprocessor(4, 600, 0.005);
296 ustd::sensorprocessor humiditySensor = ustd::sensorprocessor(4, 600, 0.005);
298 TempHumDHT(String name, uint8_t port, uint8_t interruptIndex, DHTType dhtType = DHTType::DHT22, FilterMode filterMode = FilterMode::MEDIUM)
299 : name(name), port(port), interruptIndex(interruptIndex), dhtType(dhtType), filterMode(filterMode) {
308 if (interruptIndex >= 0 && interruptIndex < USTD_DHT_MAX_PIRQS) {
309 iPin = digitalPinToInterrupt(port);
310 attachInterrupt(iPin, ustd_dht_irq_table[interruptIndex], CHANGE);
311 pDhtPortIrq[interruptIndex] = port;
312 pDhtState[interruptIndex] = DhtProtState::NONE;
313 setFilterMode(filterMode,
true);
319 detachInterrupt(iPin);
326 return temperatureValue;
333 return humidityValue;
336 void begin(Scheduler *_pSched) {
340 auto ft = [=]() { this->loop(); };
341 tID = pSched->add(ft, name, 500);
343 auto fnall = [=](String topic, String msg, String originator) {
344 this->subsMsg(topic, msg, originator);
346 pSched->subscribe(tID, name +
"/sensor/#", fnall);
348 pDhtState[interruptIndex] = DhtProtState::NONE;
353 void setFilterMode(FilterMode mode,
bool silent =
false) {
357 temperatureSensor.update(1, 2, 0.05);
358 humiditySensor.update(1, 2, 0.1);
362 temperatureSensor.update(4, 30, 0.1);
363 humiditySensor.update(4, 30, 0.5);
367 filterMode = LONGTERM;
368 temperatureSensor.update(10, 600, 0.1);
369 humiditySensor.update(50, 600, 0.5);
377 void publishTemperature() {
379 sprintf(buf,
"%6.2f", temperatureValue);
380 pSched->publish(name +
"/sensor/temperature", buf);
383 void publishHumidity() {
385 sprintf(buf,
"%6.2f", humidityValue);
386 pSched->publish(name +
"/sensor/humidity", buf);
389 void publishError(String errMsg) {
390 pSched->publish(name +
"/sensor/error", errMsg);
393 void publishFilterMode() {
394 switch (filterMode) {
395 case FilterMode::FAST:
396 pSched->publish(name +
"/sensor/mode",
"FAST");
398 case FilterMode::MEDIUM:
399 pSched->publish(name +
"/sensor/mode",
"MEDIUM");
401 case FilterMode::LONGTERM:
402 pSched->publish(name +
"/sensor/mode",
"LONGTERM");
407 void generateStartMeasurementPulse() {
410 switch (pDhtState[interruptIndex]) {
411 case DhtProtState::NONE:
412 pinMode(port, OUTPUT);
413 digitalWrite(port, LOW);
414 startPulseStartUs = micros();
415 pDhtState[interruptIndex] = DhtProtState::START_PULSE_START;
416 pDhtFailureCode[interruptIndex] = DhtFailureCode::OK;
417 pDhtFailureData[interruptIndex] = 0;
419 case DhtProtState::START_PULSE_START:
420 if (timeDiff(startPulseStartUs, micros()) > dhtWakeUpPulse) {
421 digitalWrite(port, HIGH);
422 delayMicroseconds(dhtInitialDelay);
423 startPulseStartUs = 0;
424 pDhtState[interruptIndex] = DhtProtState::START_PULSE_END;
425 lastPoll = time(
nullptr);
426 pinMode(port, INPUT_PULLUP);
435 bool measurementChanged(
double *tempVal,
double *humiVal) {
438 for (
unsigned int i = 0; i < 4; i++)
439 crc += sensorDataBytes[interruptIndex * 5 + i];
440 if (crc % 256 != sensorDataBytes[interruptIndex * 5 + 4]) {
442 sprintf(msg,
"CRC_ERROR! (%d) Errs: %ld, Code: %d, ErrData %d, bytes:[%d,%d,%d,%d,%d]", (crc % 256), errs,
int(pDhtFailureCode[interruptIndex]), pDhtFailureData[interruptIndex],
443 sensorDataBytes[interruptIndex * 5 + 0], sensorDataBytes[interruptIndex * 5 + 1], sensorDataBytes[interruptIndex * 5 + 2], sensorDataBytes[interruptIndex * 5 + 3], sensorDataBytes[interruptIndex * 5 + 4]);
446 pDhtState[interruptIndex] = DhtProtState::NONE;
452 sprintf(msg,
"OK! Oks: %ld Errs: %ld, Code: %d, ErrData %d, bytes:[%d,%d,%d,%d,%d]", oks, errs,
int(pDhtFailureCode[interruptIndex]), pDhtFailureData[interruptIndex],
453 sensorDataBytes[interruptIndex * 5 + 0], sensorDataBytes[interruptIndex * 5 + 1], sensorDataBytes[interruptIndex * 5 + 2], sensorDataBytes[interruptIndex * 5 + 3], sensorDataBytes[interruptIndex * 5 + 4]);
455 int t = ((sensorDataBytes[interruptIndex * 5 + 2] & 0x7f) << 8) | sensorDataBytes[interruptIndex * 5 + 3];
456 if (sensorDataBytes[interruptIndex * 5 + 2] & 0x80) t = t * (-1);
457 *tempVal = (double)t / 10.0;
458 int h = ((sensorDataBytes[interruptIndex * 5 + 0]) << 8) | sensorDataBytes[interruptIndex * 5 + 1];
459 *humiVal = (double)h / 10.0;
465 double tempVal, humiVal;
467 DhtProtState curState;
470 curState = pDhtState[interruptIndex];
473 case DhtProtState::NONE:
474 if (time(
nullptr) - lastPoll > sensorPollRate) {
475 generateStartMeasurementPulse();
476 lastPoll = time(
nullptr);
479 case DhtProtState::START_PULSE_START:
480 generateStartMeasurementPulse();
482 case DhtProtState::DATA_OK:
483 if (measurementChanged(&tempVal, &humiVal)) {
484 if (temperatureSensor.filter(&tempVal)) {
485 temperatureValue = tempVal;
486 publishTemperature();
488 if (humiditySensor.filter(&humiVal)) {
489 humidityValue = humiVal;
495 pDhtState[interruptIndex] = DhtProtState::NONE;
498 case DhtProtState::DATA_ABORT:
501 errratio = (double)errs / (errs + oks) * 100.0;
503 sprintf(msg,
"Errs: %ld, err-rate: %6.2f Code: %d, Data %d", errs, errratio, pDhtFailureCode[interruptIndex], pDhtFailureData[interruptIndex]);
506 pDhtState[interruptIndex] = DhtProtState::NONE;
515 void subsMsg(String topic, String msg, String originator) {
516 if (topic == name +
"/sensor/temperature/get") {
517 publishTemperature();
518 }
else if (topic == name +
"/sensor/humidity/get") {
520 }
else if (topic == name +
"/sensor/mode/get") {
522 }
else if (topic == name +
"/sensor/mode/set") {
523 if (msg ==
"fast" || msg ==
"FAST") {
524 setFilterMode(FilterMode::FAST);
526 if (msg ==
"medium" || msg ==
"MEDIUM") {
527 setFilterMode(FilterMode::MEDIUM);
529 setFilterMode(FilterMode::LONGTERM);
mupplet-sensor temperature and humidity with DHT11/22
Definition: mup_temphum_dht.h:269
TempHumDHT(String name, uint8_t port, uint8_t interruptIndex, DHTType dhtType=DHTType::DHT22, FilterMode filterMode=FilterMode::MEDIUM)
Definition: mup_temphum_dht.h:298
double getTemperature()
Definition: mup_temphum_dht.h:322
double getHumidity()
Definition: mup_temphum_dht.h:329