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.

104 lines
2.8 KiB

  1. // -----------------------------------------------------------------------------
  2. // Eergy monitor sensor
  3. // -----------------------------------------------------------------------------
  4. #pragma once
  5. #include "Arduino.h"
  6. #include "BaseSensor.h"
  7. class EmonSensor : public BaseSensor {
  8. public:
  9. EmonSensor(double voltage, unsigned char bits, double ref, double ratio): BaseSensor() {
  10. // Cache
  11. _voltage = voltage;
  12. _adc_counts = 1 << bits;
  13. _pivot = _adc_counts >> 1;
  14. _count = 2;
  15. // Calculate factor
  16. _current_factor = ratio * ref / _adc_counts;
  17. // Calculate multiplier
  18. calculateMultiplier();
  19. }
  20. protected:
  21. virtual unsigned int readADC(unsigned char port) {}
  22. void calculateMultiplier() {
  23. unsigned int s = 1;
  24. unsigned int i = 1;
  25. unsigned int m = s * i;
  26. while (m * _current_factor < 1) {
  27. _multiplier = m;
  28. i = (i == 1) ? 2 : (i == 2) ? 5 : 1;
  29. if (i == 1) s *= 10;
  30. m = s * i;
  31. }
  32. }
  33. double read(unsigned long value, unsigned char mode, unsigned char port) {
  34. int sample;
  35. int max = 0;
  36. int min = _adc_counts;
  37. double filtered;
  38. double sum = 0;
  39. unsigned long start = millis();
  40. unsigned long samples = 0;
  41. while (true) {
  42. // Read analog value
  43. sample = readADC(port);
  44. if (sample > max) max = sample;
  45. if (sample < min) min = sample;
  46. // Digital low pass filter extracts the VDC offset
  47. _pivot = (_pivot + (sample - _pivot) / EMON_FILTER_SPEED);
  48. filtered = sample - _pivot;
  49. // Root-mean-square method
  50. sum += (filtered * filtered);
  51. ++samples;
  52. // Exit condition
  53. if (mode == EMON_MODE_SAMPLES) {
  54. if (samples >= value) break;
  55. } else {
  56. if (millis() - start >= value) break;
  57. }
  58. yield();
  59. }
  60. // Quick fix
  61. if (_pivot < min || max < _pivot) {
  62. _pivot = (max + min) / 2.0;
  63. }
  64. double rms = samples > 0 ? sqrt(sum / samples) : 0;
  65. double current = _current_factor * rms;
  66. current = (double) (round(current * _multiplier) - 1) / _multiplier;
  67. if (current < 0) current = 0;
  68. return current;
  69. }
  70. double _voltage;
  71. unsigned int _adc_counts;
  72. unsigned int _multiplier = 1;
  73. double _current_factor;
  74. double _pivot;
  75. };