DHT22/DHT11 humidity/temperature sensor usermod (#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 <dev.aircoookie@gmail.com>
This commit is contained in:
b3nj1 2021-02-12 16:21:13 -08:00 committed by GitHub
parent d56ab6c971
commit aa242d897d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 287 additions and 1 deletions

View File

@ -0,0 +1,22 @@
; Options
; -------
; USERMOD_DHT - define this to have this user mod included wled00\usermods_list.cpp
; USERMOD_DHT_DHTTYPE - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
; USERMOD_DHT_PIN - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
; USERMOD_DHT_CELSIUS - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
; USERMOD_DHT_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
; USERMOD_DHT_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
; USERMOD_DHT_STATS - For debug, report delay stats
[env:d1_mini_usermod_dht_C]
extends = env:d1_mini
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS
lib_deps = ${env.lib_deps}
https://github.com/alwynallan/DHT_nonblocking
[env:custom32_LEDPIN_16_usermod_dht_C]
extends = env:custom32_LEDPIN_16
build_flags = ${env:custom32_LEDPIN_16.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
lib_deps = ${env.lib_deps}
https://github.com/alwynallan/DHT_nonblocking

41
usermods/DHT/readme.md Normal file
View File

@ -0,0 +1,41 @@
# DHT Temperature/Humidity sensor usermod
This usermod will read from an attached DHT22 or DHT11 humidity and temperature sensor.
The sensor readings are displayed in the Info section of the web UI.
If sensor is not detected after a while (10 update intervals), this usermod will be disabled.
## Installation
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
### Define Your Options
* `USERMOD_DHT` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_DHT_DHTTYPE` - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
* `USERMOD_DHT_PIN` - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
* `USERMOD_DHT_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
* `USERMOD_DHT_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
* `USERMOD_DHT_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
* `USERMOD_DHT_STATS` - For debug, report delay stats
## Project link
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
### PlatformIO requirements
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.
## Change Log
2020-02-04
* Change default QuinLed pin to Q2
* 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
* Add some more (optional) stats
2020-02-03
* Due to poor readouts on ESP32 with previous DHT library, rewrote to use https://github.com/alwynallan/DHT_nonblocking
* The new library serializes/delays up to 5ms for the sensor readout
2020-02-02
* Created

216
usermods/DHT/usermod_dht.h Normal file
View File

@ -0,0 +1,216 @@
#pragma once
#include "wled.h"
#include <dht_nonblocking.h>
// USERMOD_DHT_DHTTYPE:
// 11 // DHT 11
// 21 // DHT 21
// 22 // DHT 22 (AM2302), AM2321 *** default
#ifndef USERMOD_DHT_DHTTYPE
#define USERMOD_DHT_DHTTYPE 22
#endif
#if USERMOD_DHT_DHTTYPE == 11
#define DHTTYPE DHT_TYPE_11
#elif USERMOD_DHT_DHTTYPE == 21
#define DHTTYPE DHT_TYPE_21
#elif USERMOD_DHT_DHTTYPE == 22
#define DHTTYPE DHT_TYPE_22
#endif
// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// NOTE: Pin defaults below are for QuinLed Dig-Uno's Q2 on the board
// Connect pin 4 (on the right) of the sensor to GROUND
// NOTE: If using a bare sensor (AM*), Connect a 10K resistor from pin 2
// (data) to pin 1 (power) of the sensor. DHT* boards have the pullup already
#ifdef USERMOD_DHT_PIN
#define DHTPIN USERMOD_DHT_PIN
#else
#ifdef ARDUINO_ARCH_ESP32
#define DHTPIN 21
#else //ESP8266 boards
#define DHTPIN 4
#endif
#endif
// the frequency to check sensor, 1 minute
#ifndef USERMOD_DHT_MEASUREMENT_INTERVAL
#define USERMOD_DHT_MEASUREMENT_INTERVAL 60000
#endif
// how many seconds after boot to take first measurement, 90 seconds
// 90 gives enough time to OTA update firmware if this crashses
#ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT
#define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000
#endif
// from COOLDOWN_TIME in dht_nonblocking.cpp
#define DHT_TIMEOUT_TIME 10000
DHT_nonblocking dht_sensor(DHTPIN, DHTTYPE);
class UsermodDHT : public Usermod {
private:
unsigned long nextReadTime = 0;
unsigned long lastReadTime = 0;
float humidity, temperature = 0;
bool initializing = true;
bool disabled = false;
#ifdef USERMOD_DHT_STATS
unsigned long nextResetStatsTime = 0;
uint16_t updates = 0;
uint16_t clean_updates = 0;
uint16_t errors = 0;
unsigned long maxDelay = 0;
unsigned long currentIteration = 0;
unsigned long maxIteration = 0;
#endif
public:
void setup() {
nextReadTime = millis() + USERMOD_DHT_FIRST_MEASUREMENT_AT;
lastReadTime = millis();
#ifdef USERMOD_DHT_STATS
nextResetStatsTime = millis() + 60*60*1000;
#endif
}
void loop() {
if (disabled) {
return;
}
if (millis() < nextReadTime) {
return;
}
#ifdef USERMOD_DHT_STATS
if (millis() >= nextResetStatsTime) {
nextResetStatsTime += 60*60*1000;
errors = 0;
updates = 0;
clean_updates = 0;
}
unsigned long dcalc = millis();
if (currentIteration == 0) {
currentIteration = millis();
}
#endif
float tempC;
if (dht_sensor.measure(&tempC, &humidity)) {
#ifdef USERMOD_DHT_CELSIUS
temperature = tempC;
#else
temperature = tempC * 9 / 5 + 32;
#endif
nextReadTime = millis() + USERMOD_DHT_MEASUREMENT_INTERVAL;
lastReadTime = millis();
initializing = false;
#ifdef USERMOD_DHT_STATS
unsigned long icalc = millis() - currentIteration;
if (icalc > maxIteration) {
maxIteration = icalc;
}
if (icalc > DHT_TIMEOUT_TIME) {
errors += icalc/DHT_TIMEOUT_TIME;
} else {
clean_updates += 1;
}
updates += 1;
currentIteration = 0;
#endif
}
#ifdef USERMOD_DHT_STATS
dcalc = millis() - dcalc;
if (dcalc > maxDelay) {
maxDelay = dcalc;
}
#endif
if (((millis() - lastReadTime) > 10*USERMOD_DHT_MEASUREMENT_INTERVAL)) {
disabled = true;
}
}
void addToJsonInfo(JsonObject& root) {
if (disabled) {
return;
}
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray temp = user.createNestedArray("Temperature");
JsonArray hum = user.createNestedArray("Humidity");
#ifdef USERMOD_DHT_STATS
JsonArray next = user.createNestedArray("next");
if (nextReadTime >= millis()) {
next.add((nextReadTime - millis()) / 1000);
next.add(" sec until read");
} else {
next.add((millis() - nextReadTime) / 1000);
next.add(" sec active reading");
}
JsonArray last = user.createNestedArray("last");
last.add((millis() - lastReadTime) / 60000);
last.add(" min since read");
JsonArray err = user.createNestedArray("errors");
err.add(errors);
err.add(" Errors");
JsonArray upd = user.createNestedArray("updates");
upd.add(updates);
upd.add(" Updates");
JsonArray cupd = user.createNestedArray("cleanUpdates");
cupd.add(clean_updates);
cupd.add(" Updates");
JsonArray iter = user.createNestedArray("maxIter");
iter.add(maxIteration);
iter.add(" ms");
JsonArray delay = user.createNestedArray("maxDelay");
delay.add(maxDelay);
delay.add(" ms");
#endif
if (initializing) {
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
temp.add((nextReadTime - millis()) / 1000);
temp.add(" sec until read");
hum.add((nextReadTime - millis()) / 1000);
hum.add(" sec until read");
return;
}
hum.add(humidity);
hum.add("%");
temp.add(temperature);
#ifdef USERMOD_DHT_CELSIUS
temp.add("°C");
#else
temp.add("°F");
#endif
}
uint16_t getId()
{
return USERMOD_ID_DHT;
}
};

View File

@ -24,6 +24,7 @@
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -31,6 +31,10 @@
#include "../usermods/usermod_v2_auto_save/usermod_v2_auto_save.h"
#endif
#ifdef USERMOD_DHT
#include "../usermods/DHT/usermod_dht.h"
#endif
void registerUsermods()
{
/*
@ -49,7 +53,6 @@ void registerUsermods()
#ifdef USERMOD_SENSORSTOMQTT
usermods.add(new UserMod_SensorsToMQTT());
#endif
#ifdef USERMOD_FOUR_LINE_DISLAY
usermods.add(new FourLineDisplayUsermod());
#endif
@ -59,4 +62,7 @@ void registerUsermods()
#ifdef USERMOD_AUTO_SAVE
usermods.add(new AutoSaveUsermod());
#endif
#ifdef USERMOD_DHT
usermods.add(new UsermodDHT());
#endif
}