Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

272 lines
7.6 KiB

/*
DHT MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if DHT_SUPPORT
double _dhtTemperature = 0;
unsigned int _dhtHumidity = 0;
bool _dhtIsConnected = false;
// -----------------------------------------------------------------------------
// HAL
// https://github.com/gosouth/DHT22/blob/master/main/DHT22.c
// -----------------------------------------------------------------------------
#define DHT_MAX_DATA 5
#define DHT_MAX_ERRORS 5
#define DHT_MIN_INTERVAL 2000
#define DHT_OK 0
#define DHT_CHECKSUM_ERROR -1
#define DHT_TIMEOUT_ERROR -2
#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21
unsigned long _getSignalLevel(unsigned char gpio, int usTimeOut, bool state) {
unsigned long uSec = 1;
while (digitalRead(gpio) == state) {
if (++uSec > usTimeOut) return 0;
delayMicroseconds(1);
}
return uSec;
}
int readDHT(unsigned char gpio, unsigned char type) {
static unsigned long last_ok = 0;
if ((last_ok > 0) && (millis() - last_ok < DHT_MIN_INTERVAL)) return DHT_OK;
unsigned long low = 0;
unsigned long high = 0;
static unsigned char errors = 0;
uint8_t dhtData[DHT_MAX_DATA] = {0};
uint8_t byteInx = 0;
uint8_t bitInx = 7;
// Send start signal to DHT sensor
if (++errors > DHT_MAX_ERRORS) {
errors = 0;
digitalWrite(gpio, HIGH);
delay(250);
}
pinMode(gpio, OUTPUT);
noInterrupts();
digitalWrite(gpio, LOW);
delayMicroseconds(500);
digitalWrite(gpio, HIGH);
delayMicroseconds(40);
pinMode(gpio, INPUT_PULLUP);
// No errors, read the 40 data bits
for( int k = 0; k < 41; k++ ) {
// Starts new data transmission with >50us low signal
low = _getSignalLevel(gpio, 56, LOW);
if (low==0) return DHT_TIMEOUT_ERROR;
// Check to see if after >70us rx data is a 0 or a 1
high = _getSignalLevel(gpio, 75, HIGH);
if (high==0) return DHT_TIMEOUT_ERROR;
// Skip the first bit
if (k==0) continue;
// add the current read to the output data
// since all dhtData array where set to 0 at the start,
// only look for "1" (>28us us)
if (high > low) dhtData[byteInx] |= (1 << bitInx);
// index to next byte
if (bitInx == 0) {
bitInx = 7;
++byteInx;
} else {
--bitInx;
}
}
interrupts();
// Verify checksum
if (dhtData[4] != ((dhtData[0] + dhtData[1] + dhtData[2] + dhtData[3]) & 0xFF)) {
return DHT_CHECKSUM_ERROR;
}
// Get humidity from Data[0] and Data[1]
if (type == DHT11) {
_dhtHumidity = dhtData[0];
} else {
_dhtHumidity = dhtData[0] * 256 + dhtData[1];
_dhtHumidity /= 10;
}
// Get temp from Data[2] and Data[3]
if (type == DHT11) {
_dhtTemperature = dhtData[2];
} else {
_dhtTemperature = (dhtData[2] & 0x7F) * 256 + dhtData[3];
_dhtTemperature /= 10;
if (dhtData[2] & 0x80) _dhtTemperature *= -1;
}
last_ok = millis();
errors = 0;
return DHT_OK;
}
int readDHT() {
return readDHT(DHT_PIN, DHT_TYPE);
}
// -----------------------------------------------------------------------------
// Private
// -----------------------------------------------------------------------------
void _dhtWebSocketOnSend(JsonObject& root) {
root["dhtVisible"] = 1;
root["dhtConnected"] = getDHTIsConnected();
if (getDHTIsConnected()) {
root["dhtTmp"] = getDHTTemperature();
root["dhtHum"] = getDHTHumidity();
}
root["tmpUnits"] = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt();
}
// -----------------------------------------------------------------------------
// Values
// -----------------------------------------------------------------------------
bool getDHTIsConnected() {
return _dhtIsConnected;
}
double getDHTTemperature(bool celsius) {
double value = celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32;
double correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat();
return roundTo(value + correction, TEMPERATURE_DECIMALS);
}
double getDHTTemperature() {
bool celsius = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt() == TMP_CELSIUS;
return getDHTTemperature(celsius);
}
unsigned int getDHTHumidity() {
return _dhtHumidity;
}
void dhtSetup() {
#if DHT_PULLUP
pinMode(DHT_PIN, INPUT_PULLUP);
#endif
#if WEB_SUPPORT
// Websockets
wsOnSendRegister(_dhtWebSocketOnSend);
apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) {
dtostrf(getDHTTemperature(), 1-len, 1, buffer);
});
apiRegister(DHT_HUMIDITY_TOPIC, DHT_HUMIDITY_TOPIC, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), getDHTHumidity());
});
#endif
}
void dhtLoop() {
static unsigned long last_update = 0;
static double last_temperature = 0.0;
static unsigned int last_humidity = 0;
// Check if we should read new data
if ((millis() - last_update > DHT_UPDATE_INTERVAL) || (last_update == 0)) {
last_update = millis();
// Read sensor data
int response = readDHT(DHT_PIN, DHT_TYPE);
if (response != DHT_OK) {
DEBUG_MSG_P(PSTR("[DHT] Error: %d\n"), response);
return;
}
_dhtIsConnected = true;
// Get values
bool celsius = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt() == TMP_CELSIUS;
double t = getDHTTemperature(celsius);
unsigned int h = getDHTHumidity();
// Build strings
char temperature[6];
char humidity[6];
dtostrf(t, 1-sizeof(temperature), 1, temperature);
itoa((unsigned int) h, humidity, 10);
// Debug
DEBUG_MSG_P(PSTR("[DHT] Temperature: %s%s\n"), temperature, celsius ? "ºC" : "ºF");
DEBUG_MSG_P(PSTR("[DHT] Humidity: %s\n"), humidity);
// If the new temperature & humidity are different from the last
if ((fabs(t - last_temperature) >= TEMPERATURE_MIN_CHANGE)
|| (abs(h - last_humidity) >= HUMIDITY_MIN_CHANGE)) {
last_temperature = t;
last_humidity = h;
// Send MQTT messages
#if MQTT_SUPPORT
mqttSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
mqttSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
#endif
// Send to Domoticz
#if DOMOTICZ_SUPPORT
{
domoticzSend("dczTmpIdx", 0, temperature);
int status;
if (h > 70) {
status = HUMIDITY_WET;
} else if (h > 45) {
status = HUMIDITY_COMFORTABLE;
} else if (h > 30) {
status = HUMIDITY_NORMAL;
} else {
status = HUMIDITY_DRY;
}
char buffer[2];
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), status);
domoticzSend("dczHumIdx", humidity, buffer);
}
#endif
#if INFLUXDB_SUPPORT
idbSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
idbSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
#endif
}
// Update websocket clients
#if WEB_SUPPORT
wsSend(_dhtWebSocketOnSend);
#endif
}
}
#endif