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.

261 lines
8.2 KiB

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