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.

234 lines
6.2 KiB

  1. /*
  2. POWER V9261F MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if POWER_PROVIDER == POWER_PROVIDER_V9261F
  6. // -----------------------------------------------------------------------------
  7. // MODULE GLOBALS AND CACHE
  8. // -----------------------------------------------------------------------------
  9. #include <SoftwareSerial.h>
  10. SoftwareSerial * _v9261f_uart;
  11. double _v9261f_active = 0;
  12. double _v9261f_reactive = 0;
  13. double _v9261f_voltage = 0;
  14. double _v9261f_current = 0;
  15. double _v9261f_ratioP = V9261F_POWER_FACTOR;
  16. double _v9261f_ratioC = V9261F_CURRENT_FACTOR;
  17. double _v9261f_ratioV = V9261F_VOLTAGE_FACTOR;
  18. double _v9261f_ratioR = V9261F_RPOWER_FACTOR;
  19. unsigned char _v9261f_data[24];
  20. // -----------------------------------------------------------------------------
  21. // HAL
  22. // -----------------------------------------------------------------------------
  23. void _v9261fRead() {
  24. static unsigned char state = 0;
  25. static unsigned long last = 0;
  26. static bool found = false;
  27. static unsigned char index = 0;
  28. if (state == 0) {
  29. while (_v9261f_uart->available()) {
  30. _v9261f_uart->flush();
  31. found = true;
  32. last = millis();
  33. }
  34. if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
  35. _v9261f_uart->flush();
  36. index = 0;
  37. state = 1;
  38. }
  39. } else if (state == 1) {
  40. while (_v9261f_uart->available()) {
  41. _v9261f_uart->read();
  42. if (index++ >= 7) {
  43. _v9261f_uart->flush();
  44. index = 0;
  45. state = 2;
  46. }
  47. }
  48. } else if (state == 2) {
  49. while (_v9261f_uart->available()) {
  50. _v9261f_data[index] = _v9261f_uart->read();
  51. if (index++ >= 19) {
  52. _v9261f_uart->flush();
  53. last = millis();
  54. state = 3;
  55. }
  56. }
  57. } else if (state == 3) {
  58. if (_v9261fChecksum()) {
  59. _v9261f_active = (double) (
  60. (_v9261f_data[3]) +
  61. (_v9261f_data[4] << 8) +
  62. (_v9261f_data[5] << 16) +
  63. (_v9261f_data[6] << 24)
  64. ) / _v9261f_ratioP;
  65. _v9261f_reactive = (double) (
  66. (_v9261f_data[7]) +
  67. (_v9261f_data[8] << 8) +
  68. (_v9261f_data[9] << 16) +
  69. (_v9261f_data[10] << 24)
  70. ) / _v9261f_ratioR;
  71. _v9261f_voltage = (double) (
  72. (_v9261f_data[11]) +
  73. (_v9261f_data[12] << 8) +
  74. (_v9261f_data[13] << 16) +
  75. (_v9261f_data[14] << 24)
  76. ) / _v9261f_ratioV;
  77. _v9261f_current = (double) (
  78. (_v9261f_data[15]) +
  79. (_v9261f_data[16] << 8) +
  80. (_v9261f_data[17] << 16) +
  81. (_v9261f_data[18] << 24)
  82. ) / _v9261f_ratioC;
  83. if (_v9261f_active < 0) _v9261f_active = 0;
  84. if (_v9261f_reactive < 0) _v9261f_reactive = 0;
  85. if (_v9261f_voltage < 0) _v9261f_voltage = 0;
  86. if (_v9261f_current < 0) _v9261f_current = 0;
  87. _power_newdata = true;
  88. }
  89. last = millis();
  90. index = 0;
  91. state = 4;
  92. } else if (state == 4) {
  93. while (_v9261f_uart->available()) {
  94. _v9261f_uart->flush();
  95. last = millis();
  96. }
  97. if (millis() - last > V9261F_SYNC_INTERVAL) {
  98. state = 1;
  99. }
  100. }
  101. }
  102. bool _v9261fChecksum() {
  103. unsigned char checksum = 0;
  104. for (unsigned char i = 0; i < 19; i++) {
  105. checksum = checksum + _v9261f_data[i];
  106. }
  107. checksum = ~checksum + 0x33;
  108. return checksum == _v9261f_data[19];
  109. }
  110. // -----------------------------------------------------------------------------
  111. // POWER API
  112. // -----------------------------------------------------------------------------
  113. double _powerCurrent() {
  114. return _v9261f_current;
  115. }
  116. double _powerVoltage() {
  117. return _v9261f_voltage;
  118. }
  119. double _powerActivePower() {
  120. return _v9261f_active;
  121. }
  122. double _powerApparentPower() {
  123. return sqrt(_v9261f_reactive * _v9261f_reactive + _v9261f_active * _v9261f_active);
  124. }
  125. double _powerReactivePower() {
  126. return _v9261f_reactive;
  127. }
  128. double _powerPowerFactor() {
  129. double apparent = _powerApparentPower();
  130. if (apparent > 0) return _powerActivePower() / apparent;
  131. return 1;
  132. }
  133. void _powerEnabledProvider() {
  134. // Nothing to do
  135. }
  136. void _powerConfigureProvider() {
  137. _v9261f_ratioP = getSetting("pwrRatioP", V9261F_POWER_FACTOR).toFloat();
  138. _v9261f_ratioV = getSetting("pwrRatioV", V9261F_VOLTAGE_FACTOR).toFloat();
  139. _v9261f_ratioC = getSetting("pwrRatioC", V9261F_CURRENT_FACTOR).toFloat();
  140. _v9261f_ratioR = getSetting("pwrRatioR", V9261F_RPOWER_FACTOR).toFloat();
  141. }
  142. void _powerCalibrateProvider(unsigned char magnitude, double value) {
  143. if (value <= 0) return;
  144. if (magnitude == POWER_MAGNITUDE_ACTIVE) {
  145. _v9261f_ratioP = _v9261f_ratioP * (_v9261f_active / value);
  146. setSetting("pwrRatioP", _v9261f_ratioP);
  147. }
  148. if (magnitude == POWER_MAGNITUDE_CURRENT) {
  149. _v9261f_ratioC = _v9261f_ratioC * (_v9261f_current / value);
  150. setSetting("pwrRatioC", _v9261f_ratioC);
  151. }
  152. if (magnitude == POWER_MAGNITUDE_VOLTAGE) {
  153. _v9261f_ratioV = _v9261f_ratioV * (_v9261f_voltage / value);
  154. setSetting("pwrRatioV", _v9261f_ratioV);
  155. }
  156. if (magnitude == POWER_MAGNITUDE_POWER_FACTOR) {
  157. if (value < 100) {
  158. double apparent = _v9261f_ratioP / (value / 100);
  159. value = sqrt(apparent * apparent - _v9261f_ratioP * _v9261f_ratioP);
  160. _v9261f_ratioR = _v9261f_ratioR * (_v9261f_reactive / value);
  161. setSetting("pwrRatioR", _v9261f_ratioR);
  162. }
  163. }
  164. saveSettings();
  165. }
  166. void _powerResetCalibrationProvider() {
  167. delSetting("pwrRatioP");
  168. delSetting("pwrRatioC");
  169. delSetting("pwrRatioV");
  170. delSetting("pwrRatioR");
  171. _powerConfigureProvider();
  172. saveSettings();
  173. }
  174. void _powerSetupProvider() {
  175. _v9261f_uart = new SoftwareSerial(V9261F_PIN, SW_SERIAL_UNUSED_PIN, V9261F_PIN_INVERSE, 256);
  176. _v9261f_uart->begin(V9261F_BAUDRATE);
  177. }
  178. void _powerLoopProvider(bool before) {
  179. if (before) {
  180. _v9261fRead();
  181. }
  182. }
  183. #endif // POWER_PROVIDER & POWER_PROVIDER_EMON