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.

242 lines
7.1 KiB

  1. // -----------------------------------------------------------------------------
  2. // V9261F based power monitor
  3. // Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. // -----------------------------------------------------------------------------
  5. #pragma once
  6. #include "Arduino.h"
  7. #include "BaseSensor.h"
  8. #include <SoftwareSerial.h>
  9. class V9261FSensor : public BaseSensor {
  10. public:
  11. // ---------------------------------------------------------------------
  12. // Public
  13. // ---------------------------------------------------------------------
  14. V9261FSensor(): BaseSensor() {
  15. _count = 6;
  16. _sensor_id = SENSOR_V9261F_ID;
  17. }
  18. // ---------------------------------------------------------------------
  19. void setRX(unsigned char pin_rx) {
  20. if (_pin_rx == pin_rx) return;
  21. _pin_rx = pin_rx;
  22. _dirty = true;
  23. }
  24. void setInverted(bool inverted) {
  25. if (_inverted == inverted) return;
  26. _inverted = inverted;
  27. _dirty = true;
  28. }
  29. // ---------------------------------------------------------------------
  30. unsigned char getRX() {
  31. return _pin_rx;
  32. }
  33. bool getInverted() {
  34. return _inverted;
  35. }
  36. // ---------------------------------------------------------------------
  37. // Sensor API
  38. // ---------------------------------------------------------------------
  39. // Initialization method, must be idempotent
  40. void begin() {
  41. if (!_dirty) return;
  42. _dirty = false;
  43. if (_serial) delete _serial;
  44. _serial = new SoftwareSerial(_pin_rx, SW_SERIAL_UNUSED_PIN, _inverted, 256);
  45. _serial->begin(V9261F_BAUDRATE);
  46. }
  47. // Descriptive name of the sensor
  48. String description() {
  49. char buffer[28];
  50. snprintf(buffer, sizeof(buffer), "V9261F @ SwSerial(%i,NULL)", _pin_rx);
  51. return String(buffer);
  52. }
  53. // Loop-like method, call it in your main loop
  54. void tick() {
  55. _read();
  56. }
  57. // Type for slot # index
  58. magnitude_t type(unsigned char index) {
  59. _error = SENSOR_ERROR_OK;
  60. if (index == 0) return MAGNITUDE_CURRENT;
  61. if (index == 1) return MAGNITUDE_VOLTAGE;
  62. if (index == 2) return MAGNITUDE_POWER_ACTIVE;
  63. if (index == 3) return MAGNITUDE_POWER_REACTIVE;
  64. if (index == 4) return MAGNITUDE_POWER_APPARENT;
  65. if (index == 5) return MAGNITUDE_POWER_FACTOR;
  66. _error = SENSOR_ERROR_OUT_OF_RANGE;
  67. return MAGNITUDE_NONE;
  68. }
  69. // Current value for slot # index
  70. double value(unsigned char index) {
  71. _error = SENSOR_ERROR_OK;
  72. if (index == 0) return _current;
  73. if (index == 1) return _voltage;
  74. if (index == 2) return _active;
  75. if (index == 3) return _reactive;
  76. if (index == 4) return _apparent;
  77. if (index == 5) return _apparent > 0 ? 100 * _active / _apparent : 100;
  78. _error = SENSOR_ERROR_OUT_OF_RANGE;
  79. return 0;
  80. }
  81. protected:
  82. // ---------------------------------------------------------------------
  83. // Protected
  84. // ---------------------------------------------------------------------
  85. void _read() {
  86. static unsigned char state = 0;
  87. static unsigned long last = 0;
  88. static bool found = false;
  89. static unsigned char index = 0;
  90. if (state == 0) {
  91. while (_serial->available()) {
  92. _serial->flush();
  93. found = true;
  94. last = millis();
  95. }
  96. if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
  97. _serial->flush();
  98. index = 0;
  99. state = 1;
  100. }
  101. } else if (state == 1) {
  102. while (_serial->available()) {
  103. _serial->read();
  104. if (index++ >= 7) {
  105. _serial->flush();
  106. index = 0;
  107. state = 2;
  108. }
  109. }
  110. } else if (state == 2) {
  111. while (_serial->available()) {
  112. _data[index] = _serial->read();
  113. if (index++ >= 19) {
  114. _serial->flush();
  115. last = millis();
  116. state = 3;
  117. }
  118. }
  119. } else if (state == 3) {
  120. if (_checksum()) {
  121. _active = (double) (
  122. (_data[3]) +
  123. (_data[4] << 8) +
  124. (_data[5] << 16) +
  125. (_data[6] << 24)
  126. ) / _ratioP;
  127. _reactive = (double) (
  128. (_data[7]) +
  129. (_data[8] << 8) +
  130. (_data[9] << 16) +
  131. (_data[10] << 24)
  132. ) / _ratioR;
  133. _voltage = (double) (
  134. (_data[11]) +
  135. (_data[12] << 8) +
  136. (_data[13] << 16) +
  137. (_data[14] << 24)
  138. ) / _ratioV;
  139. _current = (double) (
  140. (_data[15]) +
  141. (_data[16] << 8) +
  142. (_data[17] << 16) +
  143. (_data[18] << 24)
  144. ) / _ratioC;
  145. if (_active < 0) _active = 0;
  146. if (_reactive < 0) _reactive = 0;
  147. if (_voltage < 0) _voltage = 0;
  148. if (_current < 0) _current = 0;
  149. _apparent = sqrt(_reactive * _reactive + _active * _active);
  150. }
  151. last = millis();
  152. index = 0;
  153. state = 4;
  154. } else if (state == 4) {
  155. while (_serial->available()) {
  156. _serial->flush();
  157. last = millis();
  158. }
  159. if (millis() - last > V9261F_SYNC_INTERVAL) {
  160. state = 1;
  161. }
  162. }
  163. }
  164. bool _checksum() {
  165. unsigned char checksum = 0;
  166. for (unsigned char i = 0; i < 19; i++) {
  167. checksum = checksum + _data[i];
  168. }
  169. checksum = ~checksum + 0x33;
  170. return checksum == _data[19];
  171. }
  172. // ---------------------------------------------------------------------
  173. unsigned int _pin_rx = V9261F_PIN;
  174. bool _inverted = V9261F_PIN_INVERSE;
  175. SoftwareSerial * _serial = NULL;
  176. double _active = 0;
  177. double _reactive = 0;
  178. double _voltage = 0;
  179. double _current = 0;
  180. double _apparent = 0;
  181. double _ratioP = V9261F_POWER_FACTOR;
  182. double _ratioC = V9261F_CURRENT_FACTOR;
  183. double _ratioV = V9261F_VOLTAGE_FACTOR;
  184. double _ratioR = V9261F_RPOWER_FACTOR;
  185. unsigned char _data[24];
  186. };