|
|
- /*
-
- 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
|