feat: added support DHT11/DHT22 sensors (#223)

* feat: Added support DHT11/DHT22 sensors

* chore: formatting

* fix: typo

* fix: `HaHelper::publishDynamicSensor()` for DHT sensors fixed

* refactor: optimization of wired sensors
This commit is contained in:
Yurii
2026-02-16 10:17:38 +03:00
committed by GitHub
parent 11747dd8bd
commit 3fdb48e016
14 changed files with 174 additions and 19 deletions

View File

@@ -1,6 +1,7 @@
#include <unordered_map>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <esp32DHT.h>
#if USE_BLE
#include <NimBLEDevice.h>
@@ -50,19 +51,23 @@ protected:
class SensorsTask : public LeanTask {
public:
SensorsTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {
this->gpioLastPollingTime.reserve(2);
// OneWire
this->owInstances.reserve(2);
this->dallasInstances.reserve(2);
this->dallasSearchTime.reserve(2);
this->dallasPolling.reserve(2);
this->dallasLastPollingTime.reserve(2);
}
~SensorsTask() {
this->gpioLastPollingTime.clear();
// OneWire
this->dallasInstances.clear();
this->owInstances.clear();
this->dallasSearchTime.clear();
this->dallasPolling.clear();
this->dallasLastPollingTime.clear();
}
protected:
@@ -70,17 +75,26 @@ protected:
const unsigned int wirelessDisconnectTimeout = 600000u;
const unsigned short dallasSearchInterval = 60000;
const unsigned short dallasPollingInterval = 10000;
const unsigned short dhtPollingInterval = 15000;
const unsigned short globalPollingInterval = 15000;
#if USE_BLE
const unsigned int bleSetDtInterval = 7200000;
#endif
std::unordered_map<uint8_t, unsigned long> gpioLastPollingTime;
// OneWire
std::unordered_map<uint8_t, OneWire> owInstances;
std::unordered_map<uint8_t, DallasTemperature> dallasInstances;
std::unordered_map<uint8_t, unsigned long> dallasSearchTime;
std::unordered_map<uint8_t, bool> dallasPolling;
std::unordered_map<uint8_t, unsigned long> dallasLastPollingTime;
// DHT
DHT dhtInstance;
bool dhtIsPolling = false;
#if USE_BLE
// Bluetooth
std::unordered_map<uint8_t, NimBLEClient*> bleClients;
std::unordered_map<uint8_t, bool> bleSubscribed;
std::unordered_map<uint8_t, unsigned long> bleLastSetDtTime;
@@ -116,6 +130,9 @@ protected:
this->yield();
}
pollingDhtSensors();
this->yield();
if (millis() - this->globalLastPollingTime > this->globalPollingInterval) {
cleanDallasInstances();
makeDallasInstances();
@@ -173,7 +190,7 @@ protected:
this->dallasSearchTime[sSensor.gpio] = 0;
this->dallasPolling[sSensor.gpio] = false;
this->dallasLastPollingTime[sSensor.gpio] = 0;
this->gpioLastPollingTime[sSensor.gpio] = 0;
auto& instance = this->dallasInstances[sSensor.gpio];
instance.setOneWire(&owInstance);
@@ -208,7 +225,7 @@ protected:
this->owInstances.erase(gpio);
this->dallasSearchTime.erase(gpio);
this->dallasPolling.erase(gpio);
this->dallasLastPollingTime.erase(gpio);
this->gpioLastPollingTime.erase(gpio);
Log.sinfoln(FPSTR(L_SENSORS_DALLAS), F("Stopped on GPIO %hhu"), gpio);
continue;
@@ -329,7 +346,7 @@ protected:
if (this->dallasPolling[gpio]) {
unsigned long minPollingTime = instance.millisToWaitForConversion(12) * 2;
unsigned long estimatePollingTime = ts - this->dallasLastPollingTime[gpio];
unsigned long estimatePollingTime = ts - this->gpioLastPollingTime[gpio];
// check conversion time
// isConversionComplete does not work with chinese clones!
@@ -381,7 +398,7 @@ protected:
this->dallasPolling[gpio] = false;
} else if (newPolling) {
auto estimateLastPollingTime = ts - this->dallasLastPollingTime[gpio];
auto estimateLastPollingTime = ts - this->gpioLastPollingTime[gpio];
// check last polling time
if (estimateLastPollingTime < this->dallasPollingInterval) {
@@ -392,13 +409,102 @@ protected:
instance.setResolution(12);
instance.requestTemperatures();
this->dallasPolling[gpio] = true;
this->dallasLastPollingTime[gpio] = ts;
this->gpioLastPollingTime[gpio] = ts;
Log.straceln(FPSTR(L_SENSORS_DALLAS), F("GPIO %hhu, polling..."), gpio);
}
}
}
void pollingDhtSensors() {
if (this->dhtIsPolling) {
// busy
return;
}
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
auto& sSensor = Sensors::settings[sensorId];
if (!sSensor.enabled || sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
continue;
}
if (sSensor.type != Sensors::Type::DHT11 && sSensor.type != Sensors::Type::DHT22) {
continue;
}
if (this->gpioLastPollingTime.count(sSensor.gpio) && millis() - this->gpioLastPollingTime[sSensor.gpio] < this->dhtPollingInterval) {
continue;
}
const auto sensorGpio = static_cast<gpio_num_t>(sSensor.gpio);
if (this->dhtInstance.getGpio() != sensorGpio) {
this->dhtInstance.reset();
this->dhtInstance.onData([this, sensorId](float humidity, float temperature) {
auto& sSensor = Sensors::settings[sensorId];
Log.straceln(
FPSTR(L_SENSORS_DHT), F("GPIO %hhu, sensor #%hhu '%s', temp: %.2f, humidity: %.2f%%"),
sSensor.gpio, sensorId, sSensor.name, temperature, humidity
);
// set temperature
Sensors::setValueById(sensorId, temperature, Sensors::ValueType::TEMPERATURE, true, true);
// set humidity
Sensors::setValueById(sensorId, humidity, Sensors::ValueType::HUMIDITY, true, true);
auto& rSensor = Sensors::results[sensorId];
if (rSensor.signalQuality < 100) {
rSensor.signalQuality++;
}
this->gpioLastPollingTime[sSensor.gpio] = millis();
this->dhtIsPolling = false;
});
this->dhtInstance.onError([this, sensorId](DHT::Status status) {
auto& sSensor = Sensors::settings[sensorId];
Log.swarningln(
FPSTR(L_SENSORS_DHT), F("GPIO %hhu, sensor #%hhu '%s': failed receiving data (err: %s)"),
sSensor.gpio, sensorId, sSensor.name, DHT::statusToString(this->dhtInstance.getStatus())
);
auto& rSensor = Sensors::results[sensorId];
if (rSensor.signalQuality > 0) {
rSensor.signalQuality--;
}
this->gpioLastPollingTime[sSensor.gpio] = millis();
this->dhtIsPolling = false;
});
DHT::Type sType = DHT::Type::DHT22;
if (sSensor.type == Sensors::Type::DHT11) {
sType = DHT::Type::DHT11;
} else if (sSensor.type == Sensors::Type::DHT22) {
sType = DHT::Type::DHT22;
}
if (this->dhtInstance.setup(sensorGpio, sType)) {
Log.sinfoln(FPSTR(L_SENSORS_DHT), F("Started on GPIO %hhu"), sSensor.gpio);
} else {
Log.swarningln(
FPSTR(L_SENSORS_DHT), F("Failed to start on GPIO %hhu (err: %s)"),
sSensor.gpio, DHT::statusToString(this->dhtInstance.getStatus())
);
}
}
this->dhtIsPolling = this->dhtInstance.poll();
break;
}
}
void pollingNtcSensors() {
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
auto& sSensor = Sensors::settings[sensorId];