Skip to content

Commit aa242d8

Browse files
b3nj1Aircoookie
andauthored
DHT22/DHT11 humidity/temperature sensor usermod (wled#1719)
* DHT22/DHT11 humidity/temperature sensor usermod * cleanup - don't report when usermod is auto-disabled since report isn't persistent * track error count; retry once after error occurs * for esp32, use esp32DHT library * fix unreliable ESP32 readings by switching DHT library to https://github.com/alwynallan/DHT_nonblocking * change default pin to Q2; don't burst readings if error occurs Co-authored-by: Aircoookie <[email protected]>
1 parent d56ab6c commit aa242d8

File tree

5 files changed

+287
-1
lines changed

5 files changed

+287
-1
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; Options
2+
; -------
3+
; USERMOD_DHT - define this to have this user mod included wled00\usermods_list.cpp
4+
; USERMOD_DHT_DHTTYPE - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
5+
; USERMOD_DHT_PIN - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
6+
; USERMOD_DHT_CELSIUS - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
7+
; USERMOD_DHT_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
8+
; USERMOD_DHT_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
9+
; USERMOD_DHT_STATS - For debug, report delay stats
10+
11+
[env:d1_mini_usermod_dht_C]
12+
extends = env:d1_mini
13+
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS
14+
lib_deps = ${env.lib_deps}
15+
https://github.com/alwynallan/DHT_nonblocking
16+
17+
[env:custom32_LEDPIN_16_usermod_dht_C]
18+
extends = env:custom32_LEDPIN_16
19+
build_flags = ${env:custom32_LEDPIN_16.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
20+
lib_deps = ${env.lib_deps}
21+
https://github.com/alwynallan/DHT_nonblocking
22+

usermods/DHT/readme.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# DHT Temperature/Humidity sensor usermod
2+
3+
This usermod will read from an attached DHT22 or DHT11 humidity and temperature sensor.
4+
The sensor readings are displayed in the Info section of the web UI.
5+
6+
If sensor is not detected after a while (10 update intervals), this usermod will be disabled.
7+
8+
## Installation
9+
10+
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
11+
12+
### Define Your Options
13+
14+
* `USERMOD_DHT` - define this to have this user mod included wled00\usermods_list.cpp
15+
* `USERMOD_DHT_DHTTYPE` - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
16+
* `USERMOD_DHT_PIN` - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
17+
* `USERMOD_DHT_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
18+
* `USERMOD_DHT_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
19+
* `USERMOD_DHT_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
20+
* `USERMOD_DHT_STATS` - For debug, report delay stats
21+
22+
## Project link
23+
24+
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
25+
26+
### PlatformIO requirements
27+
28+
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dht_C`. If not, you can add the libraries and dependencies into `platformio.ini` as you see fit.
29+
30+
31+
## Change Log
32+
33+
2020-02-04
34+
* Change default QuinLed pin to Q2
35+
* Instead of trying to keep updates at constant cadence, space readings out by measurement interval; hope this helps to avoid occasional bursts of readings with errors
36+
* Add some more (optional) stats
37+
2020-02-03
38+
* Due to poor readouts on ESP32 with previous DHT library, rewrote to use https://github.com/alwynallan/DHT_nonblocking
39+
* The new library serializes/delays up to 5ms for the sensor readout
40+
2020-02-02
41+
* Created

usermods/DHT/usermod_dht.h

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#pragma once
2+
3+
#include "wled.h"
4+
5+
#include <dht_nonblocking.h>
6+
7+
// USERMOD_DHT_DHTTYPE:
8+
// 11 // DHT 11
9+
// 21 // DHT 21
10+
// 22 // DHT 22 (AM2302), AM2321 *** default
11+
#ifndef USERMOD_DHT_DHTTYPE
12+
#define USERMOD_DHT_DHTTYPE 22
13+
#endif
14+
15+
#if USERMOD_DHT_DHTTYPE == 11
16+
#define DHTTYPE DHT_TYPE_11
17+
#elif USERMOD_DHT_DHTTYPE == 21
18+
#define DHTTYPE DHT_TYPE_21
19+
#elif USERMOD_DHT_DHTTYPE == 22
20+
#define DHTTYPE DHT_TYPE_22
21+
#endif
22+
23+
// Connect pin 1 (on the left) of the sensor to +5V
24+
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
25+
// to 3.3V instead of 5V!
26+
// Connect pin 2 of the sensor to whatever your DHTPIN is
27+
// NOTE: Pin defaults below are for QuinLed Dig-Uno's Q2 on the board
28+
// Connect pin 4 (on the right) of the sensor to GROUND
29+
// NOTE: If using a bare sensor (AM*), Connect a 10K resistor from pin 2
30+
// (data) to pin 1 (power) of the sensor. DHT* boards have the pullup already
31+
32+
#ifdef USERMOD_DHT_PIN
33+
#define DHTPIN USERMOD_DHT_PIN
34+
#else
35+
#ifdef ARDUINO_ARCH_ESP32
36+
#define DHTPIN 21
37+
#else //ESP8266 boards
38+
#define DHTPIN 4
39+
#endif
40+
#endif
41+
42+
// the frequency to check sensor, 1 minute
43+
#ifndef USERMOD_DHT_MEASUREMENT_INTERVAL
44+
#define USERMOD_DHT_MEASUREMENT_INTERVAL 60000
45+
#endif
46+
47+
// how many seconds after boot to take first measurement, 90 seconds
48+
// 90 gives enough time to OTA update firmware if this crashses
49+
#ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT
50+
#define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000
51+
#endif
52+
53+
// from COOLDOWN_TIME in dht_nonblocking.cpp
54+
#define DHT_TIMEOUT_TIME 10000
55+
56+
DHT_nonblocking dht_sensor(DHTPIN, DHTTYPE);
57+
58+
class UsermodDHT : public Usermod {
59+
private:
60+
unsigned long nextReadTime = 0;
61+
unsigned long lastReadTime = 0;
62+
float humidity, temperature = 0;
63+
bool initializing = true;
64+
bool disabled = false;
65+
#ifdef USERMOD_DHT_STATS
66+
unsigned long nextResetStatsTime = 0;
67+
uint16_t updates = 0;
68+
uint16_t clean_updates = 0;
69+
uint16_t errors = 0;
70+
unsigned long maxDelay = 0;
71+
unsigned long currentIteration = 0;
72+
unsigned long maxIteration = 0;
73+
#endif
74+
75+
public:
76+
void setup() {
77+
nextReadTime = millis() + USERMOD_DHT_FIRST_MEASUREMENT_AT;
78+
lastReadTime = millis();
79+
#ifdef USERMOD_DHT_STATS
80+
nextResetStatsTime = millis() + 60*60*1000;
81+
#endif
82+
}
83+
84+
void loop() {
85+
if (disabled) {
86+
return;
87+
}
88+
if (millis() < nextReadTime) {
89+
return;
90+
}
91+
92+
#ifdef USERMOD_DHT_STATS
93+
if (millis() >= nextResetStatsTime) {
94+
nextResetStatsTime += 60*60*1000;
95+
errors = 0;
96+
updates = 0;
97+
clean_updates = 0;
98+
}
99+
unsigned long dcalc = millis();
100+
if (currentIteration == 0) {
101+
currentIteration = millis();
102+
}
103+
#endif
104+
105+
float tempC;
106+
if (dht_sensor.measure(&tempC, &humidity)) {
107+
#ifdef USERMOD_DHT_CELSIUS
108+
temperature = tempC;
109+
#else
110+
temperature = tempC * 9 / 5 + 32;
111+
#endif
112+
113+
nextReadTime = millis() + USERMOD_DHT_MEASUREMENT_INTERVAL;
114+
lastReadTime = millis();
115+
initializing = false;
116+
117+
#ifdef USERMOD_DHT_STATS
118+
unsigned long icalc = millis() - currentIteration;
119+
if (icalc > maxIteration) {
120+
maxIteration = icalc;
121+
}
122+
if (icalc > DHT_TIMEOUT_TIME) {
123+
errors += icalc/DHT_TIMEOUT_TIME;
124+
} else {
125+
clean_updates += 1;
126+
}
127+
updates += 1;
128+
currentIteration = 0;
129+
130+
#endif
131+
}
132+
133+
#ifdef USERMOD_DHT_STATS
134+
dcalc = millis() - dcalc;
135+
if (dcalc > maxDelay) {
136+
maxDelay = dcalc;
137+
}
138+
#endif
139+
140+
if (((millis() - lastReadTime) > 10*USERMOD_DHT_MEASUREMENT_INTERVAL)) {
141+
disabled = true;
142+
}
143+
}
144+
145+
void addToJsonInfo(JsonObject& root) {
146+
if (disabled) {
147+
return;
148+
}
149+
JsonObject user = root["u"];
150+
if (user.isNull()) user = root.createNestedObject("u");
151+
152+
JsonArray temp = user.createNestedArray("Temperature");
153+
JsonArray hum = user.createNestedArray("Humidity");
154+
155+
#ifdef USERMOD_DHT_STATS
156+
JsonArray next = user.createNestedArray("next");
157+
if (nextReadTime >= millis()) {
158+
next.add((nextReadTime - millis()) / 1000);
159+
next.add(" sec until read");
160+
} else {
161+
next.add((millis() - nextReadTime) / 1000);
162+
next.add(" sec active reading");
163+
}
164+
165+
JsonArray last = user.createNestedArray("last");
166+
last.add((millis() - lastReadTime) / 60000);
167+
last.add(" min since read");
168+
169+
JsonArray err = user.createNestedArray("errors");
170+
err.add(errors);
171+
err.add(" Errors");
172+
173+
JsonArray upd = user.createNestedArray("updates");
174+
upd.add(updates);
175+
upd.add(" Updates");
176+
177+
JsonArray cupd = user.createNestedArray("cleanUpdates");
178+
cupd.add(clean_updates);
179+
cupd.add(" Updates");
180+
181+
JsonArray iter = user.createNestedArray("maxIter");
182+
iter.add(maxIteration);
183+
iter.add(" ms");
184+
185+
JsonArray delay = user.createNestedArray("maxDelay");
186+
delay.add(maxDelay);
187+
delay.add(" ms");
188+
#endif
189+
190+
if (initializing) {
191+
// if we haven't read the sensor yet, let the user know
192+
// that we are still waiting for the first measurement
193+
temp.add((nextReadTime - millis()) / 1000);
194+
temp.add(" sec until read");
195+
hum.add((nextReadTime - millis()) / 1000);
196+
hum.add(" sec until read");
197+
return;
198+
}
199+
200+
hum.add(humidity);
201+
hum.add("%");
202+
203+
temp.add(temperature);
204+
#ifdef USERMOD_DHT_CELSIUS
205+
temp.add("°C");
206+
#else
207+
temp.add("°F");
208+
#endif
209+
}
210+
211+
uint16_t getId()
212+
{
213+
return USERMOD_ID_DHT;
214+
}
215+
216+
};

wled00/const.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
2525
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
2626
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
27+
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
2728

2829
//Access point behavior
2930
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

wled00/usermods_list.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#include "../usermods/usermod_v2_auto_save/usermod_v2_auto_save.h"
3232
#endif
3333

34+
#ifdef USERMOD_DHT
35+
#include "../usermods/DHT/usermod_dht.h"
36+
#endif
37+
3438
void registerUsermods()
3539
{
3640
/*
@@ -49,7 +53,6 @@ void registerUsermods()
4953
#ifdef USERMOD_SENSORSTOMQTT
5054
usermods.add(new UserMod_SensorsToMQTT());
5155
#endif
52-
5356
#ifdef USERMOD_FOUR_LINE_DISLAY
5457
usermods.add(new FourLineDisplayUsermod());
5558
#endif
@@ -59,4 +62,7 @@ void registerUsermods()
5962
#ifdef USERMOD_AUTO_SAVE
6063
usermods.add(new AutoSaveUsermod());
6164
#endif
65+
#ifdef USERMOD_DHT
66+
usermods.add(new UsermodDHT());
67+
#endif
6268
}

0 commit comments

Comments
 (0)