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.

237 lines
7.3 KiB

  1. // -----------------------------------------------------------------------------
  2. // DHT Sensor
  3. // -----------------------------------------------------------------------------
  4. #pragma once
  5. #include "Arduino.h"
  6. #include "BaseSensor.h"
  7. #include <vector>
  8. #include <OneWire.h>
  9. #define DS_CHIP_DS18S20 0x10
  10. #define DS_CHIP_DS1822 0x22
  11. #define DS_CHIP_DS18B20 0x28
  12. #define DS_CHIP_DS1825 0x3B
  13. #define DS_PARASITE 1
  14. #define DS_DISCONNECTED -127
  15. #define DS_CMD_START_CONVERSION 0x44
  16. #define DS_CMD_READ_SCRATCHPAD 0xBE
  17. #define DS_ERROR_FAILED_RESET -2
  18. #define DS_ERROR_FAILED_READ -3
  19. class DallasSensor : public BaseSensor {
  20. public:
  21. DallasSensor(unsigned char gpio, unsigned long interval, bool pull_up = false): BaseSensor() {
  22. // Cache params
  23. _gpio = gpio;
  24. _interval = interval / 2;
  25. // OneWire
  26. _wire = new OneWire(_gpio);
  27. // Must be done after the OneWire initialization
  28. if (pull_up) pinMode(_gpio, INPUT_PULLUP);
  29. // Search devices
  30. loadDevices();
  31. }
  32. // Loop-like method, call it in your main loop
  33. void tick() {
  34. static unsigned long last = 0;
  35. if (millis() - last < _interval) return;
  36. last = millis();
  37. // Every second we either start a conversion or read the scratchpad
  38. static bool conversion = true;
  39. if (conversion) {
  40. // Start conversion
  41. _wire->reset();
  42. _wire->skip();
  43. _wire->write(DS_CMD_START_CONVERSION, DS_PARASITE);
  44. } else {
  45. // Read scratchpads
  46. for (unsigned char index=0; index<_devices.size(); index++) {
  47. // Read scratchpad
  48. if (_wire->reset() == 0) {
  49. _error = DS_ERROR_FAILED_RESET;
  50. return;
  51. }
  52. _wire->select(_devices[index].address);
  53. _wire->write(DS_CMD_READ_SCRATCHPAD);
  54. uint8_t data[9];
  55. for (unsigned char i = 0; i < 9; i++) {
  56. data[i] = _wire->read();
  57. }
  58. #if false
  59. Serial.printf("[DS18B20] Data = ");
  60. for (unsigned char i = 0; i < 9; i++) {
  61. Serial.printf("%02X ", data[i]);
  62. }
  63. Serial.printf(" CRC = %02X\n", OneWire::crc8(data, 8));
  64. #endif
  65. if (_wire->reset() != 1) {
  66. _error = DS_ERROR_FAILED_READ;
  67. return;
  68. }
  69. if (OneWire::crc8(data, 8) != data[8]) {
  70. _error = SENSOR_ERROR_CRC;
  71. return;
  72. }
  73. memcpy(_devices[index].data, data, 9);
  74. }
  75. }
  76. conversion = !conversion;
  77. }
  78. // Descriptive name of the sensor
  79. String name() {
  80. char buffer[20];
  81. snprintf(buffer, sizeof(buffer), "Dallas @ GPIO%d", _gpio);
  82. return String(buffer);
  83. }
  84. // Descriptive name of the slot # index
  85. String slot(unsigned char index) {
  86. _error = SENSOR_ERROR_OK;
  87. if (index < _count) {
  88. char buffer[40];
  89. uint8_t * address = _devices[index].address;
  90. snprintf(buffer, sizeof(buffer), "%s (%02X%02X%02X%02X%02X%02X%02X%02X) @ GPIO%d",
  91. chipAsString(index).c_str(),
  92. address[0], address[1], address[2], address[3],
  93. address[4], address[5], address[6], address[7],
  94. _gpio
  95. );
  96. return String(buffer);
  97. }
  98. _error = SENSOR_ERROR_OUT_OF_RANGE;
  99. return String();
  100. }
  101. // Type for slot # index
  102. magnitude_t type(unsigned char index) {
  103. _error = SENSOR_ERROR_OK;
  104. if (index < _count) return MAGNITUDE_TEMPERATURE;
  105. _error = SENSOR_ERROR_OUT_OF_RANGE;
  106. return MAGNITUDE_NONE;
  107. }
  108. // Current value for slot # index
  109. double value(unsigned char index) {
  110. if (index >= _count) {
  111. _error = SENSOR_ERROR_OUT_OF_RANGE;
  112. return 0;
  113. }
  114. uint8_t * data = _devices[index].data;
  115. // Registers
  116. // byte 0: temperature LSB
  117. // byte 1: temperature MSB
  118. // byte 2: high alarm temp
  119. // byte 3: low alarm temp
  120. // byte 4: DS18S20: store for crc
  121. // DS18B20 & DS1822: configuration register
  122. // byte 5: internal use & crc
  123. // byte 6: DS18S20: COUNT_REMAIN
  124. // DS18B20 & DS1822: store for crc
  125. // byte 7: DS18S20: COUNT_PER_C
  126. // DS18B20 & DS1822: store for crc
  127. // byte 8: SCRATCHPAD_CRC
  128. int16_t raw = (data[1] << 8) | data[0];
  129. if (chip(index) == DS_CHIP_DS18S20) {
  130. raw = raw << 3; // 9 bit resolution default
  131. if (data[7] == 0x10) {
  132. raw = (raw & 0xFFF0) + 12 - data[6]; // "count remain" gives full 12 bit resolution
  133. }
  134. } else {
  135. byte cfg = (data[4] & 0x60);
  136. if (cfg == 0x00) raw = raw & ~7; // 9 bit res, 93.75 ms
  137. else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
  138. else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  139. // 12 bit res, 750 ms
  140. }
  141. double value = (float) raw / 16.0;
  142. if (value == DS_DISCONNECTED) {
  143. _error = SENSOR_ERROR_CRC;
  144. return 0;
  145. }
  146. _error = SENSOR_ERROR_OK;
  147. return value;
  148. }
  149. protected:
  150. unsigned char chip(unsigned char index) {
  151. if (index < _count) return _devices[index].address[0];
  152. return 0;
  153. }
  154. String chipAsString(unsigned char index) {
  155. unsigned char chip_id = chip(index);
  156. if (chip_id == DS_CHIP_DS18S20) return String("DS18S20");
  157. if (chip_id == DS_CHIP_DS18B20) return String("DS18B20");
  158. if (chip_id == DS_CHIP_DS1822) return String("DS1822");
  159. if (chip_id == DS_CHIP_DS1825) return String("DS1825");
  160. return String("Unknown");
  161. }
  162. void loadDevices() {
  163. uint8_t address[8];
  164. _wire->reset_search();
  165. while (_wire->search(address)) {
  166. // Check CRC
  167. if (_wire->crc8(address, 7) == address[7]) {
  168. ds_device_t device;
  169. memcpy(device.address, address, 8);
  170. _devices.push_back(device);
  171. }
  172. }
  173. _count = _devices.size();
  174. }
  175. typedef struct {
  176. uint8_t address[8];
  177. uint8_t data[9];
  178. } ds_device_t;
  179. std::vector<ds_device_t> _devices;
  180. unsigned char _gpio;
  181. unsigned long _interval;
  182. OneWire * _wire;
  183. };