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.

165 lines
4.1 KiB

  1. /*
  2. EMON MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if ENABLE_EMON
  6. #include <EmonLiteESP.h>
  7. #include <EEPROM.h>
  8. EmonLiteESP emon;
  9. double _current = 0;
  10. unsigned int _power = 0;
  11. double _energy = 0;
  12. // -----------------------------------------------------------------------------
  13. // EMON
  14. // -----------------------------------------------------------------------------
  15. void setCurrentRatio(float value) {
  16. emon.setCurrentRatio(value);
  17. }
  18. unsigned int getPower() {
  19. return _power;
  20. }
  21. double getEnergy() {
  22. return _energy;
  23. }
  24. double getCurrent() {
  25. return _current;
  26. }
  27. unsigned int currentCallback() {
  28. return analogRead(EMON_CURRENT_PIN);
  29. }
  30. void retrieveEnergy() {
  31. unsigned long energy = EEPROM.read(EEPROM_POWER_COUNT + 1);
  32. energy = (energy << 8) + EEPROM.read(EEPROM_POWER_COUNT);
  33. if (energy == 0xFFFF) energy = 0;
  34. _energy = energy;
  35. }
  36. void saveEnergy() {
  37. unsigned int energy = (int) _energy;
  38. EEPROM.write(EEPROM_POWER_COUNT, energy & 0xFF);
  39. EEPROM.write(EEPROM_POWER_COUNT + 1, (energy >> 8) & 0xFF);
  40. EEPROM.commit();
  41. }
  42. void powerMonitorSetup() {
  43. // backwards compatibility
  44. String tmp;
  45. tmp = getSetting("pwMainsVoltage", EMON_MAINS_VOLTAGE);
  46. setSetting("emonMains", tmp);
  47. delSetting("pwMainsVoltage");
  48. tmp = getSetting("pwCurrentRatio", EMON_CURRENT_RATIO);
  49. setSetting("emonRatio", tmp);
  50. delSetting("pwCurrentRatio");
  51. emon.initCurrent(
  52. currentCallback,
  53. EMON_ADC_BITS,
  54. EMON_REFERENCE_VOLTAGE,
  55. getSetting("emonRatio", EMON_CURRENT_RATIO).toFloat()
  56. );
  57. emon.setPrecision(EMON_CURRENT_PRECISION);
  58. apiRegister("/api/power", "power", [](char * buffer, size_t len) {
  59. snprintf(buffer, len, "%d", _power);
  60. });
  61. apiRegister("/api/energy", "energy", [](char * buffer, size_t len) {
  62. snprintf(buffer, len, "%ld", (unsigned long) _energy);
  63. });
  64. retrieveEnergy();
  65. }
  66. void powerMonitorLoop() {
  67. static unsigned long next_measurement = millis();
  68. static bool warmup = true;
  69. static byte measurements = 0;
  70. static double max = 0;
  71. static double min = 0;
  72. static double sum = 0;
  73. if (!mqttConnected()) return;
  74. if (warmup) {
  75. warmup = false;
  76. emon.warmup();
  77. }
  78. if (millis() > next_measurement) {
  79. // Safety check: do not read current if relay is OFF
  80. if (!relayStatus(0)) {
  81. _current = 0;
  82. } else {
  83. _current = emon.getCurrent(EMON_SAMPLES);
  84. _current -= EMON_CURRENT_OFFSET;
  85. if (_current < 0) _current = 0;
  86. }
  87. if (measurements == 0) {
  88. max = min = _current;
  89. } else {
  90. if (_current > max) max = _current;
  91. if (_current < min) min = _current;
  92. }
  93. sum += _current;
  94. ++measurements;
  95. float mainsVoltage = getSetting("emonMains", EMON_MAINS_VOLTAGE).toFloat();
  96. //DEBUG_MSG("[ENERGY] Power now: %dW\n", int(_current * mainsVoltage));
  97. // Update websocket clients
  98. char text[20];
  99. sprintf_P(text, PSTR("{\"emonPower\": %d}"), int(_current * mainsVoltage));
  100. wsSend(text);
  101. // Send MQTT messages averaged every EMON_MEASUREMENTS
  102. if (measurements == EMON_MEASUREMENTS) {
  103. _power = (int) ((sum - max - min) * mainsVoltage / (measurements - 2));
  104. double window = (double) EMON_INTERVAL * EMON_MEASUREMENTS / 1000.0 / 3600.0;
  105. _energy += _power * window;
  106. saveEnergy();
  107. sum = 0;
  108. measurements = 0;
  109. char power[6];
  110. snprintf(power, 6, "%d", _power);
  111. char energy[8];
  112. snprintf(energy, 6, "%ld", (unsigned long) _energy);
  113. mqttSend(getSetting("emonPowerTopic", EMON_POWER_TOPIC).c_str(), power);
  114. mqttSend(getSetting("emonEnergyTopic", EMON_ENERGY_TOPIC).c_str(), energy);
  115. #if ENABLE_DOMOTICZ
  116. {
  117. char buffer[20];
  118. snprintf(buffer, 20, "%s;%s", power, energy);
  119. domoticzSend("dczPowIdx", 0, buffer);
  120. }
  121. #endif
  122. }
  123. next_measurement += EMON_INTERVAL;
  124. }
  125. }
  126. #endif