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.

263 lines
7.6 KiB

  1. // -----------------------------------------------------------------------------
  2. // DHTXX Sensor
  3. // Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. // -----------------------------------------------------------------------------
  5. #if SENSOR_SUPPORT && DHT_SUPPORT
  6. #pragma once
  7. #include "Arduino.h"
  8. #include "BaseSensor.h"
  9. #define DHT_MAX_DATA 5
  10. #define DHT_MAX_ERRORS 5
  11. #define DHT_MIN_INTERVAL 2000
  12. #define DHT_CHIP_DHT11 11
  13. #define DHT_CHIP_DHT12 12
  14. #define DHT_CHIP_DHT22 22
  15. #define DHT_CHIP_DHT21 21
  16. #define DHT_CHIP_AM2301 21
  17. #define DHT_DUMMY_VALUE -255
  18. class DHTSensor : public BaseSensor {
  19. public:
  20. // ---------------------------------------------------------------------
  21. // Public
  22. // ---------------------------------------------------------------------
  23. DHTSensor(): BaseSensor() {
  24. _count = 2;
  25. _sensor_id = SENSOR_DHTXX_ID;
  26. }
  27. ~DHTSensor() {
  28. if (_previous != GPIO_NONE) gpioReleaseLock(_previous);
  29. }
  30. // ---------------------------------------------------------------------
  31. void setGPIO(unsigned char gpio) {
  32. _gpio = gpio;
  33. }
  34. void setType(unsigned char type) {
  35. _type = type;
  36. }
  37. // ---------------------------------------------------------------------
  38. unsigned char getGPIO() {
  39. return _gpio;
  40. }
  41. unsigned char getType() {
  42. return _type;
  43. }
  44. // ---------------------------------------------------------------------
  45. // Sensor API
  46. // ---------------------------------------------------------------------
  47. // Initialization method, must be idempotent
  48. void begin() {
  49. _count = 0;
  50. // Manage GPIO lock
  51. if (_previous != GPIO_NONE) gpioReleaseLock(_previous);
  52. _previous = GPIO_NONE;
  53. if (!gpioGetLock(_gpio)) {
  54. _error = SENSOR_ERROR_GPIO_USED;
  55. return;
  56. }
  57. _previous = _gpio;
  58. // Set now to fail the check in _read at least once
  59. _last_ok = millis();
  60. _count = 2;
  61. _ready = true;
  62. }
  63. // Pre-read hook (usually to populate registers with up-to-date data)
  64. void pre() {
  65. _error = SENSOR_ERROR_OK;
  66. _read();
  67. }
  68. // Descriptive name of the sensor
  69. String description() {
  70. char buffer[20];
  71. snprintf(buffer, sizeof(buffer), "DHT%d @ GPIO%d", _type, _gpio);
  72. return String(buffer);
  73. }
  74. // Descriptive name of the slot # index
  75. String slot(unsigned char index) {
  76. return description();
  77. };
  78. // Address of the sensor (it could be the GPIO or I2C address)
  79. String address(unsigned char index) {
  80. return String(_gpio);
  81. }
  82. // Type for slot # index
  83. unsigned char type(unsigned char index) {
  84. if (index == 0) return MAGNITUDE_TEMPERATURE;
  85. if (index == 1) return MAGNITUDE_HUMIDITY;
  86. return MAGNITUDE_NONE;
  87. }
  88. // Current value for slot # index
  89. double value(unsigned char index) {
  90. if (index == 0) return _temperature;
  91. if (index == 1) return _humidity;
  92. return 0;
  93. }
  94. protected:
  95. // ---------------------------------------------------------------------
  96. // Protected
  97. // ---------------------------------------------------------------------
  98. void _read() {
  99. if ((_last_ok > 0) && (millis() - _last_ok < DHT_MIN_INTERVAL)) {
  100. if ((_temperature == DHT_DUMMY_VALUE) && (_humidity == DHT_DUMMY_VALUE)) {
  101. _error = SENSOR_ERROR_WARM_UP;
  102. } else {
  103. _error = SENSOR_ERROR_OK;
  104. }
  105. return;
  106. }
  107. unsigned long low = 0;
  108. unsigned long high = 0;
  109. unsigned char dhtData[DHT_MAX_DATA] = {0};
  110. unsigned char byteInx = 0;
  111. unsigned char bitInx = 7;
  112. pinMode(_gpio, OUTPUT);
  113. // Send start signal to DHT sensor
  114. if (++_errors > DHT_MAX_ERRORS) {
  115. _errors = 0;
  116. digitalWrite(_gpio, HIGH);
  117. nice_delay(250);
  118. }
  119. noInterrupts();
  120. digitalWrite(_gpio, LOW);
  121. if ((_type == DHT_CHIP_DHT11) || (_type == DHT_CHIP_DHT12)) {
  122. nice_delay(20);
  123. } else {
  124. delayMicroseconds(1100);
  125. }
  126. digitalWrite(_gpio, HIGH);
  127. delayMicroseconds(40);
  128. pinMode(_gpio, INPUT_PULLUP);
  129. delayMicroseconds(10);
  130. // No errors, read the 40 data bits
  131. for( int k = 0; k < 41; k++ ) {
  132. // Starts new data transmission with >50us low signal
  133. low = _signal(100, LOW);
  134. if (low == 0) {
  135. _error = SENSOR_ERROR_TIMEOUT;
  136. return;
  137. }
  138. // Check to see if after >70us rx data is a 0 or a 1
  139. high = _signal(100, HIGH);
  140. if (high == 0) {
  141. _error = SENSOR_ERROR_TIMEOUT;
  142. return;
  143. }
  144. // Skip the first bit
  145. if (k == 0) continue;
  146. // add the current read to the output data
  147. // since all dhtData array where set to 0 at the start,
  148. // only look for "1" (>28us us)
  149. if (high > low) dhtData[byteInx] |= (1 << bitInx);
  150. // index to next byte
  151. if (bitInx == 0) {
  152. bitInx = 7;
  153. ++byteInx;
  154. } else {
  155. --bitInx;
  156. }
  157. }
  158. interrupts();
  159. // Verify checksum
  160. if (dhtData[4] != ((dhtData[0] + dhtData[1] + dhtData[2] + dhtData[3]) & 0xFF)) {
  161. _error = SENSOR_ERROR_CRC;
  162. return;
  163. }
  164. // Get humidity from Data[0] and Data[1]
  165. if (_type == DHT_CHIP_DHT11) {
  166. _humidity = dhtData[0];
  167. } else if (_type == DHT_CHIP_DHT12) {
  168. _humidity = dhtData[0];
  169. _humidity += dhtData[1] * 0.1;
  170. } else {
  171. _humidity = dhtData[0] * 256 + dhtData[1];
  172. _humidity /= 10;
  173. }
  174. // Get temp from Data[2] and Data[3]
  175. if (_type == DHT_CHIP_DHT11) {
  176. _temperature = dhtData[2];
  177. } else if (_type == DHT_CHIP_DHT12) {
  178. _temperature = (dhtData[2] & 0x7F);
  179. _temperature += dhtData[3] * 0.1;
  180. if (dhtData[2] & 0x80) _temperature *= -1;
  181. } else {
  182. _temperature = (dhtData[2] & 0x7F) * 256 + dhtData[3];
  183. _temperature /= 10;
  184. if (dhtData[2] & 0x80) _temperature *= -1;
  185. }
  186. _last_ok = millis();
  187. _errors = 0;
  188. _error = SENSOR_ERROR_OK;
  189. }
  190. unsigned long _signal(unsigned long usTimeOut, bool state) {
  191. unsigned long uSec = 1;
  192. while (digitalRead(_gpio) == state) {
  193. if (++uSec > usTimeOut) return 0;
  194. delayMicroseconds(1);
  195. }
  196. return uSec;
  197. }
  198. unsigned char _gpio = GPIO_NONE;
  199. unsigned char _previous = GPIO_NONE;
  200. unsigned char _type = DHT_CHIP_DHT22;
  201. unsigned long _last_ok = 0;
  202. unsigned char _errors = 0;
  203. double _temperature = DHT_DUMMY_VALUE;
  204. double _humidity = DHT_DUMMY_VALUE;
  205. };
  206. #endif // SENSOR_SUPPORT && DHT_SUPPORT