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.

212 lines
5.5 KiB

  1. // -----------------------------------------------------------------------------
  2. // EZO™ pH Circuit from Atlas Scientific
  3. //
  4. // Uses SoftwareSerial library
  5. // Copyright (C) 2018 by Rui Marinho <ruipmarinho at gmail dot com>
  6. // -----------------------------------------------------------------------------
  7. #if SENSOR_SUPPORT && EZOPH_SUPPORT
  8. #pragma once
  9. #include <SoftwareSerial.h>
  10. #include "BaseSensor.h"
  11. class EZOPHSensor : public BaseSensor {
  12. public:
  13. // ---------------------------------------------------------------------
  14. // Public
  15. // ---------------------------------------------------------------------
  16. EZOPHSensor() {
  17. _count = 1;
  18. _sensor_id = SENSOR_EZOPH_ID;
  19. }
  20. ~EZOPHSensor() {
  21. if (_serial) delete _serial;
  22. }
  23. // ---------------------------------------------------------------------
  24. void setRX(unsigned char pin_rx) {
  25. if (_pin_rx == pin_rx) return;
  26. _pin_rx = pin_rx;
  27. _dirty = true;
  28. }
  29. void setTX(unsigned char pin_tx) {
  30. if (_pin_tx == pin_tx) return;
  31. _pin_tx = pin_tx;
  32. _dirty = true;
  33. }
  34. // ---------------------------------------------------------------------
  35. unsigned char getRX() {
  36. return _pin_rx;
  37. }
  38. unsigned char getTX() {
  39. return _pin_tx;
  40. }
  41. // ---------------------------------------------------------------------
  42. // Sensor API
  43. // ---------------------------------------------------------------------
  44. // Initialization method, must be idempotent
  45. void begin() {
  46. if (!_dirty) return;
  47. if (_serial) delete _serial;
  48. _serial = new SoftwareSerial(_pin_rx, _pin_tx);
  49. _serial->enableIntTx(false);
  50. _serial->begin(9600);
  51. _ready = true;
  52. _dirty = false;
  53. }
  54. // Descriptive name of the sensor
  55. String description() {
  56. char buffer[28];
  57. snprintf(buffer, sizeof(buffer), "EZOPH @ SwSerial(%u,%u)", _pin_rx, _pin_tx);
  58. return String(buffer);
  59. }
  60. // Descriptive name of the slot # index
  61. String description(unsigned char index) {
  62. return description();
  63. };
  64. // Address of the sensor (it could be the GPIO or I2C address)
  65. String address(unsigned char index) {
  66. char buffer[6];
  67. snprintf(buffer, sizeof(buffer), "%u:%u", _pin_rx, _pin_tx);
  68. return String(buffer);
  69. }
  70. // Type for slot # index
  71. unsigned char type(unsigned char index) {
  72. if (index == 0) return MAGNITUDE_PH;
  73. return MAGNITUDE_NONE;
  74. }
  75. void tick() {
  76. _setup();
  77. _read();
  78. }
  79. // Current value for slot # index
  80. double value(unsigned char index) {
  81. if (index == 0) return _ph;
  82. return 0;
  83. }
  84. protected:
  85. // ---------------------------------------------------------------------
  86. // Protected
  87. // ---------------------------------------------------------------------
  88. void _setup() {
  89. if (_sync_responded) {
  90. return;
  91. }
  92. _error = SENSOR_ERROR_WARM_UP;
  93. String sync_serial = "";
  94. sync_serial.reserve(30);
  95. if (!_sync_requested) {
  96. _serial->write(67); // C
  97. _serial->write(44); // ,
  98. _serial->write(63); // ?
  99. _serial->write(13); // \r
  100. _serial->flush();
  101. _sync_requested = true;
  102. }
  103. while ((_serial->available() > 0)) {
  104. char sync_char = (char)_serial->read();
  105. sync_serial += sync_char;
  106. if (sync_char == '\r') {
  107. break;
  108. }
  109. }
  110. if (sync_serial.startsWith("?C,")) {
  111. _sync_interval = sync_serial.substring(sync_serial.indexOf(",") + 1).toInt() * 1000;
  112. if (_sync_interval == 0) {
  113. _error = SENSOR_ERROR_OTHER;
  114. return;
  115. }
  116. }
  117. if (sync_serial.startsWith("*OK")) {
  118. _sync_responded = true;
  119. }
  120. if (!_sync_responded) {
  121. return;
  122. }
  123. _error = SENSOR_ERROR_OK;
  124. }
  125. void _read() {
  126. if (_error != SENSOR_ERROR_OK) {
  127. return;
  128. }
  129. if (millis() - _ts <= _sync_interval) {
  130. return;
  131. }
  132. _ts = millis();
  133. String ph_serial = "";
  134. ph_serial.reserve(30);
  135. while ((_serial->available() > 0)) {
  136. char ph_char = (char)_serial->read();
  137. ph_serial += ph_char;
  138. if (ph_char == '\r') {
  139. break;
  140. }
  141. }
  142. if (ph_serial == "*ER") {
  143. _error = SENSOR_ERROR_OTHER;
  144. return;
  145. }
  146. _ph = ph_serial.toFloat();
  147. _error = SENSOR_ERROR_OK;
  148. }
  149. bool _sync_requested = false;
  150. bool _sync_responded = false;
  151. unsigned long _sync_interval = 100000; // Maximum continuous reading interval allowed is 99000 milliseconds.
  152. unsigned long _ts = 0;
  153. double _ph = 0;
  154. unsigned int _pin_rx;
  155. unsigned int _pin_tx;
  156. SoftwareSerial * _serial = NULL;
  157. };
  158. #endif // SENSOR_SUPPORT && EZOPH_SUPPORT