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.

286 lines
8.8 KiB

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