diff --git a/usermods/DHT/platformio_override.ini b/usermods/DHT/platformio_override.ini new file mode 100644 index 00000000..1771fd17 --- /dev/null +++ b/usermods/DHT/platformio_override.ini @@ -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 + diff --git a/usermods/DHT/readme.md b/usermods/DHT/readme.md new file mode 100644 index 00000000..5a123d4b --- /dev/null +++ b/usermods/DHT/readme.md @@ -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 diff --git a/usermods/DHT/usermod_dht.h b/usermods/DHT/usermod_dht.h new file mode 100644 index 00000000..9f46734f --- /dev/null +++ b/usermods/DHT/usermod_dht.h @@ -0,0 +1,216 @@ +#pragma once + +#include "wled.h" + +#include + +// 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; + } + +}; diff --git a/wled00/const.h b/wled00/const.h index d2cf05a3..409a4ce3 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -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 diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index bfff2d77..cdd6fdfa 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -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 } \ No newline at end of file