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.5 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. /*
  2. DHT MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if DHT_SUPPORT
  6. double _dhtTemperature = 0;
  7. unsigned int _dhtHumidity = 0;
  8. bool _dhtIsConnected = false;
  9. // -----------------------------------------------------------------------------
  10. // HAL
  11. // https://github.com/gosouth/DHT22/blob/master/main/DHT22.c
  12. // -----------------------------------------------------------------------------
  13. #define DHT_MAX_DATA 5
  14. #define DHT_MAX_ERRORS 5
  15. #define DHT_MIN_INTERVAL 2000
  16. #define DHT_OK 0
  17. #define DHT_CHECKSUM_ERROR -1
  18. #define DHT_TIMEOUT_ERROR -2
  19. #define DHT11 11
  20. #define DHT22 22
  21. #define DHT21 21
  22. #define AM2301 21
  23. unsigned long _getSignalLevel(unsigned char gpio, int usTimeOut, bool state) {
  24. unsigned long uSec = 1;
  25. while (digitalRead(gpio) == state) {
  26. if (++uSec > usTimeOut) return 0;
  27. delayMicroseconds(1);
  28. }
  29. return uSec;
  30. }
  31. int readDHT(unsigned char gpio, unsigned char type) {
  32. static unsigned long last_ok = 0;
  33. if ((last_ok > 0) && (millis() - last_ok < DHT_MIN_INTERVAL)) return DHT_OK;
  34. unsigned long low = 0;
  35. unsigned long high = 0;
  36. static unsigned char errors = 0;
  37. uint8_t dhtData[DHT_MAX_DATA] = {0};
  38. uint8_t byteInx = 0;
  39. uint8_t bitInx = 7;
  40. // Send start signal to DHT sensor
  41. if (++errors > DHT_MAX_ERRORS) {
  42. errors = 0;
  43. digitalWrite(gpio, HIGH);
  44. delay(250);
  45. }
  46. pinMode(gpio, OUTPUT);
  47. noInterrupts();
  48. digitalWrite(gpio, LOW);
  49. delayMicroseconds(500);
  50. digitalWrite(gpio, HIGH);
  51. delayMicroseconds(40);
  52. pinMode(gpio, INPUT_PULLUP);
  53. // No errors, read the 40 data bits
  54. for( int k = 0; k < 41; k++ ) {
  55. // Starts new data transmission with >50us low signal
  56. low = _getSignalLevel(gpio, 56, LOW);
  57. if (low==0) return DHT_TIMEOUT_ERROR;
  58. // Check to see if after >70us rx data is a 0 or a 1
  59. high = _getSignalLevel(gpio, 75, HIGH);
  60. if (high==0) return DHT_TIMEOUT_ERROR;
  61. // Skip the first bit
  62. if (k==0) continue;
  63. // add the current read to the output data
  64. // since all dhtData array where set to 0 at the start,
  65. // only look for "1" (>28us us)
  66. if (high > low) dhtData[byteInx] |= (1 << bitInx);
  67. // index to next byte
  68. if (bitInx == 0) {
  69. bitInx = 7;
  70. ++byteInx;
  71. } else {
  72. --bitInx;
  73. }
  74. }
  75. interrupts();
  76. // Verify checksum
  77. if (dhtData[4] != ((dhtData[0] + dhtData[1] + dhtData[2] + dhtData[3]) & 0xFF)) {
  78. return DHT_CHECKSUM_ERROR;
  79. }
  80. // Get humidity from Data[0] and Data[1]
  81. if (type == DHT11) {
  82. _dhtHumidity = dhtData[0];
  83. } else {
  84. _dhtHumidity = dhtData[0] * 256 + dhtData[1];
  85. _dhtHumidity /= 10;
  86. }
  87. // Get temp from Data[2] and Data[3]
  88. if (type == DHT11) {
  89. _dhtTemperature = dhtData[2];
  90. } else {
  91. _dhtTemperature = (dhtData[2] & 0x7F) * 256 + dhtData[3];
  92. _dhtTemperature /= 10;
  93. if (dhtData[2] & 0x80) _dhtTemperature *= -1;
  94. }
  95. last_ok = millis();
  96. errors = 0;
  97. return DHT_OK;
  98. }
  99. int readDHT() {
  100. return readDHT(DHT_PIN, DHT_TYPE);
  101. }
  102. // -----------------------------------------------------------------------------
  103. // Private
  104. // -----------------------------------------------------------------------------
  105. void _dhtWebSocketOnSend(JsonObject& root) {
  106. root["dhtVisible"] = 1;
  107. root["dhtConnected"] = getDHTIsConnected();
  108. if (getDHTIsConnected()) {
  109. root["dhtTmp"] = getDHTTemperature();
  110. root["dhtHum"] = getDHTHumidity();
  111. }
  112. root["tmpUnits"] = getSetting("tmpUnits", TMP_UNITS).toInt();
  113. }
  114. // -----------------------------------------------------------------------------
  115. // Values
  116. // -----------------------------------------------------------------------------
  117. bool getDHTIsConnected() {
  118. return _dhtIsConnected;
  119. }
  120. double getDHTTemperature(bool celsius) {
  121. double value = celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32;
  122. double correction = getSetting("tmpCorrection", TEMPERATURE_CORRECTION).toFloat();
  123. return roundTo(value + correction, TEMPERATURE_DECIMALS);
  124. }
  125. double getDHTTemperature() {
  126. bool celsius = getSetting("tmpUnits", TMP_UNITS).toInt() == TMP_CELSIUS;
  127. return getDHTTemperature(celsius);
  128. }
  129. unsigned int getDHTHumidity() {
  130. return _dhtHumidity;
  131. }
  132. void dhtSetup() {
  133. #if DHT_PULLUP
  134. pinMode(DHT_PIN, INPUT_PULLUP);
  135. #endif
  136. #if WEB_SUPPORT
  137. // Websockets
  138. wsOnSendRegister(_dhtWebSocketOnSend);
  139. apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) {
  140. dtostrf(getDHTTemperature(), 1-len, 1, buffer);
  141. });
  142. apiRegister(DHT_HUMIDITY_TOPIC, DHT_HUMIDITY_TOPIC, [](char * buffer, size_t len) {
  143. snprintf_P(buffer, len, PSTR("%d"), getDHTHumidity());
  144. });
  145. #endif
  146. }
  147. void dhtLoop() {
  148. static unsigned long last_update = 0;
  149. static double last_temperature = 0.0;
  150. static unsigned int last_humidity = 0;
  151. // Check if we should read new data
  152. if ((millis() - last_update > DHT_UPDATE_INTERVAL) || (last_update == 0)) {
  153. last_update = millis();
  154. // Read sensor data
  155. int response = readDHT(DHT_PIN, DHT_TYPE);
  156. if (response != DHT_OK) {
  157. DEBUG_MSG_P(PSTR("[DHT] Error: %d\n"), response);
  158. return;
  159. }
  160. _dhtIsConnected = true;
  161. // Get values
  162. bool celsius = getSetting("tmpUnits", TMP_UNITS).toInt() == TMP_CELSIUS;
  163. double t = getDHTTemperature(celsius);
  164. unsigned int h = getDHTHumidity();
  165. // Build strings
  166. char temperature[6];
  167. char humidity[6];
  168. dtostrf(t, 1-sizeof(temperature), 1, temperature);
  169. itoa((unsigned int) h, humidity, 10);
  170. // Debug
  171. DEBUG_MSG_P(PSTR("[DHT] Temperature: %s%s\n"), temperature, celsius ? "ºC" : "ºF");
  172. DEBUG_MSG_P(PSTR("[DHT] Humidity: %s\n"), humidity);
  173. // If the new temperature & humidity are different from the last
  174. if ((fabs(t - last_temperature) >= TEMPERATURE_MIN_CHANGE)
  175. || (abs(h - last_humidity) >= HUMIDITY_MIN_CHANGE)) {
  176. last_temperature = t;
  177. last_humidity = h;
  178. // Send MQTT messages
  179. #if MQTT_SUPPORT
  180. mqttSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
  181. mqttSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
  182. #endif
  183. // Send to Domoticz
  184. #if DOMOTICZ_SUPPORT
  185. {
  186. domoticzSend("dczTmpIdx", 0, temperature);
  187. int status;
  188. if (h > 70) {
  189. status = HUMIDITY_WET;
  190. } else if (h > 45) {
  191. status = HUMIDITY_COMFORTABLE;
  192. } else if (h > 30) {
  193. status = HUMIDITY_NORMAL;
  194. } else {
  195. status = HUMIDITY_DRY;
  196. }
  197. char buffer[2];
  198. snprintf_P(buffer, sizeof(buffer), PSTR("%d"), status);
  199. domoticzSend("dczHumIdx", humidity, buffer);
  200. }
  201. #endif
  202. #if INFLUXDB_SUPPORT
  203. idbSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
  204. idbSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
  205. #endif
  206. }
  207. // Update websocket clients
  208. #if WEB_SUPPORT
  209. wsSend(_dhtWebSocketOnSend);
  210. #endif
  211. }
  212. }
  213. #endif