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.

191 lines
4.6 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. unsigned char _v9261f_data[24];
  16. // -----------------------------------------------------------------------------
  17. // HAL
  18. // -----------------------------------------------------------------------------
  19. void _v9261fRead() {
  20. static unsigned char state = 0;
  21. static unsigned long last = 0;
  22. static bool found = false;
  23. static unsigned char index = 0;
  24. if (state == 0) {
  25. while (_v9261f_uart->available()) {
  26. _v9261f_uart->flush();
  27. found = true;
  28. last = millis();
  29. }
  30. if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
  31. _v9261f_uart->flush();
  32. index = 0;
  33. state = 1;
  34. }
  35. } else if (state == 1) {
  36. while (_v9261f_uart->available()) {
  37. _v9261f_uart->read();
  38. if (index++ >= 7) {
  39. _v9261f_uart->flush();
  40. index = 0;
  41. state = 2;
  42. }
  43. }
  44. } else if (state == 2) {
  45. while (_v9261f_uart->available()) {
  46. _v9261f_data[index] = _v9261f_uart->read();
  47. if (index++ >= 19) {
  48. _v9261f_uart->flush();
  49. last = millis();
  50. state = 3;
  51. }
  52. }
  53. } else if (state == 3) {
  54. if (_v9261fChecksum()) {
  55. _v9261f_active = (double) (
  56. (_v9261f_data[3]) +
  57. (_v9261f_data[4] << 8) +
  58. (_v9261f_data[5] << 16) +
  59. (_v9261f_data[6] << 24)
  60. ) / V9261F_POWER_FACTOR;
  61. _v9261f_reactive = (double) (
  62. (_v9261f_data[7]) +
  63. (_v9261f_data[8] << 8) +
  64. (_v9261f_data[9] << 16) +
  65. (_v9261f_data[10] << 24)
  66. ) / V9261F_RPOWER_FACTOR;
  67. _v9261f_voltage = (double) (
  68. (_v9261f_data[11]) +
  69. (_v9261f_data[12] << 8) +
  70. (_v9261f_data[13] << 16) +
  71. (_v9261f_data[14] << 24)
  72. ) / V9261F_VOLTAGE_FACTOR;
  73. _v9261f_current = (double) (
  74. (_v9261f_data[15]) +
  75. (_v9261f_data[16] << 8) +
  76. (_v9261f_data[17] << 16) +
  77. (_v9261f_data[18] << 24)
  78. ) / V9261F_CURRENT_FACTOR;
  79. if (_v9261f_active < 0) _v9261f_active = 0;
  80. if (_v9261f_reactive < 0) _v9261f_reactive = 0;
  81. if (_v9261f_voltage < 0) _v9261f_voltage = 0;
  82. if (_v9261f_current < 0) _v9261f_current = 0;
  83. _power_newdata = true;
  84. }
  85. last = millis();
  86. index = 0;
  87. state = 4;
  88. } else if (state == 4) {
  89. while (_v9261f_uart->available()) {
  90. _v9261f_uart->flush();
  91. last = millis();
  92. }
  93. if (millis() - last > V9261F_SYNC_INTERVAL) {
  94. state = 1;
  95. }
  96. }
  97. }
  98. bool _v9261fChecksum() {
  99. unsigned char checksum = 0;
  100. for (unsigned char i = 0; i < 19; i++) {
  101. checksum = checksum + _v9261f_data[i];
  102. }
  103. checksum = ~checksum + 0x33;
  104. return checksum == _v9261f_data[19];
  105. }
  106. // -----------------------------------------------------------------------------
  107. // POWER API
  108. // -----------------------------------------------------------------------------
  109. double _powerCurrent() {
  110. return _v9261f_current;
  111. }
  112. double _powerVoltage() {
  113. return _v9261f_voltage;
  114. }
  115. double _powerActivePower() {
  116. return _v9261f_active;
  117. }
  118. double _powerApparentPower() {
  119. return sqrt(_v9261f_reactive * _v9261f_reactive + _v9261f_active * _v9261f_active);
  120. }
  121. double _powerReactivePower() {
  122. return _v9261f_reactive;
  123. }
  124. double _powerPowerFactor() {
  125. double apparent = _powerApparentPower();
  126. if (apparent > 0) return _powerActivePower() / apparent;
  127. return 1;
  128. }
  129. void _powerEnabledProvider() {
  130. // Nothing to do
  131. }
  132. void _powerConfigureProvider() {
  133. // Nothing to do
  134. }
  135. void _powerSetupProvider() {
  136. _v9261f_uart = new SoftwareSerial(V9261F_PIN, SW_SERIAL_UNUSED_PIN, V9261F_PIN_INVERSE, 256);
  137. _v9261f_uart->begin(V9261F_BAUDRATE);
  138. }
  139. void _powerLoopProvider(bool before) {
  140. if (before) {
  141. _v9261fRead();
  142. }
  143. }
  144. #endif // POWER_PROVIDER & POWER_PROVIDER_EMON