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.

207 lines
5.3 KiB

  1. /*
  2. POWER ECH1560 MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if POWER_PROVIDER == POWER_PROVIDER_ECH1560
  6. // -----------------------------------------------------------------------------
  7. // MODULE GLOBALS AND CACHE
  8. // -----------------------------------------------------------------------------
  9. volatile long _ech1560_bits_count = 0;
  10. volatile long _ech1560_clk_count = 0;
  11. volatile bool _ech1560_dosync = false;
  12. volatile bool _ech1560_nextbit = true;
  13. double _ech1560_apparent = 0;
  14. double _ech1560_voltage = 0;
  15. double _ech1560_current = 0;
  16. // -----------------------------------------------------------------------------
  17. // HAL
  18. // -----------------------------------------------------------------------------
  19. void _ech1560_sync() {
  20. unsigned int byte1 = 0;
  21. unsigned int byte2 = 0;
  22. unsigned int byte3 = 0;
  23. _ech1560_bits_count = 0;
  24. while (_ech1560_bits_count < 40); // skip the uninteresting 5 first bytes
  25. _ech1560_bits_count = 0;
  26. while (_ech1560_bits_count < 24) { // loop through the next 3 Bytes (6-8) and save byte 6 and 7 in Ba and Bb
  27. if (_ech1560_nextbit) {
  28. if (_ech1560_bits_count < 9) { // first Byte/8 bits in Ba
  29. byte1 = byte1 << 1;
  30. if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte1 |= 1;
  31. _ech1560_nextbit = false;
  32. } else if (_ech1560_bits_count < 17) { // bit 9-16 is byte 7, stor in Bb
  33. byte2 = byte2 << 1;
  34. if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte2 |= 1;
  35. _ech1560_nextbit = false;
  36. }
  37. }
  38. }
  39. if (byte2 != 3) { // if bit Bb is not 3, we have reached the important part, U is allready in Ba and Bb and next 8 Bytes will give us the Power.
  40. // voltage = 2 * (Ba + Bb / 255)
  41. _ech1560_voltage = 2.0 * ((float) byte1 + (float) byte2 / 255.0);
  42. // power:
  43. _ech1560_bits_count = 0;
  44. while (_ech1560_bits_count < 40); // skip the uninteresting 5 first bytes
  45. _ech1560_bits_count = 0;
  46. byte1 = 0;
  47. byte2 = 0;
  48. byte3 = 0;
  49. while (_ech1560_bits_count < 24) { //store byte 6, 7 and 8 in Ba and Bb & Bc.
  50. if (_ech1560_nextbit) {
  51. if (_ech1560_bits_count < 9) {
  52. byte1 = byte1 << 1;
  53. if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte1 |= 1;
  54. _ech1560_nextbit = false;
  55. } else if (_ech1560_bits_count < 17) {
  56. byte2 = byte2 << 1;
  57. if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte2 |= 1;
  58. _ech1560_nextbit = false;
  59. } else {
  60. byte3 = byte3 << 1;
  61. if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte3 |= 1;
  62. _ech1560_nextbit = false;
  63. }
  64. }
  65. }
  66. #if ECH1560_INVERTED
  67. byte1 = 255 - byte1;
  68. byte2 = 255 - byte2;
  69. byte3 = 255 - byte3;
  70. #endif
  71. // power = (Ba*255+Bb+Bc/255)/2
  72. _ech1560_apparent = ( (float) byte1 * 255 + (float) byte2 + (float) byte3 / 255.0) / 2;
  73. _ech1560_current = _ech1560_apparent / _ech1560_voltage;
  74. _power_newdata = true;
  75. _ech1560_dosync = false;
  76. }
  77. // If Bb is not 3 or something else than 0, something is wrong!
  78. if (byte2 == 0) _ech1560_dosync = false;
  79. }
  80. void ICACHE_RAM_ATTR _ech1560_isr() {
  81. // if we are trying to find the sync-time (CLK goes high for 1-2ms)
  82. if (_ech1560_dosync == false) {
  83. _ech1560_clk_count = 0;
  84. // register how long the ClkHigh is high to evaluate if we are at the part wher clk goes high for 1-2 ms
  85. while (digitalRead(ECH1560_CLK_PIN) == HIGH) {
  86. _ech1560_clk_count += 1;
  87. delayMicroseconds(30); //can only use delayMicroseconds in an interrupt.
  88. }
  89. // if the Clk was high between 1 and 2 ms than, its a start of a SPI-transmission
  90. if (_ech1560_clk_count >= 33 && _ech1560_clk_count <= 67) {
  91. _ech1560_dosync = true;
  92. }
  93. // we are in sync and logging CLK-highs
  94. } else {
  95. // increment an integer to keep track of how many bits we have read.
  96. _ech1560_bits_count += 1;
  97. _ech1560_nextbit = true;
  98. }
  99. }
  100. // -----------------------------------------------------------------------------
  101. // POWER API
  102. // -----------------------------------------------------------------------------
  103. double _powerCurrent() {
  104. return _ech1560_current;
  105. }
  106. double _powerVoltage() {
  107. return _ech1560_voltage;
  108. }
  109. double _powerActivePower() {
  110. return 0;
  111. }
  112. double _powerApparentPower() {
  113. return _ech1560_apparent;
  114. }
  115. double _powerReactivePower() {
  116. return 0;
  117. }
  118. double _powerPowerFactor() {
  119. return 1;
  120. }
  121. void _powerEnabledProvider() {
  122. // Nothing to do
  123. }
  124. void _powerConfigureProvider() {
  125. // Nothing to do
  126. }
  127. void _powerCalibrateProvider(unsigned char magnitude, double value) {
  128. // Nothing to do
  129. }
  130. void _powerResetCalibrationProvider() {
  131. // Nothing to do
  132. }
  133. void _powerSetupProvider() {
  134. pinMode(ECH1560_CLK_PIN, INPUT);
  135. pinMode(ECH1560_MISO_PIN, INPUT);
  136. attachInterrupt(ECH1560_CLK_PIN, _ech1560_isr, RISING);
  137. }
  138. void _powerLoopProvider(bool before) {
  139. if (!before) {
  140. if (_ech1560_dosync) _ech1560_sync();
  141. }
  142. }
  143. #endif // POWER_PROVIDER == POWER_PROVIDER_ECH1560