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.

254 lines
7.3 KiB

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