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.

176 lines
4.4 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 "brzo_i2c.h"
  8. // ADC121 Registers
  9. #define ADC121_REG_RESULT 0x00
  10. #define ADC121_REG_ALERT 0x01
  11. #define ADC121_REG_CONFIG 0x02
  12. #define ADC121_REG_LIMITL 0x03
  13. #define ADC121_REG_LIMITH 0x04
  14. #define ADC121_REG_HYST 0x05
  15. #define ADC121_REG_CONVL 0x06
  16. #define ADC121_REG_CONVH 0x07
  17. EmonLiteESP emon;
  18. double _current = 0;
  19. unsigned int _power = 0;
  20. // -----------------------------------------------------------------------------
  21. // Provider
  22. // -----------------------------------------------------------------------------
  23. unsigned int currentCallback() {
  24. #if EMON_PROVIDER == EMON_ANALOG_PROVIDER
  25. return analogRead(EMON_CURRENT_PIN);
  26. #endif
  27. #if EMON_PROVIDER == EMON_ADC121_PROVIDER
  28. uint8_t buffer[2];
  29. brzo_i2c_start_transaction(EMON_ADC121_ADDRESS, I2C_SCL_FREQUENCY);
  30. buffer[0] = ADC121_REG_RESULT;
  31. brzo_i2c_write(buffer, 1, false);
  32. brzo_i2c_read(buffer, 2, false);
  33. brzo_i2c_end_transaction();
  34. unsigned int value;
  35. value = (buffer[0] & 0x0F) << 8;
  36. value |= buffer[1];
  37. return value;
  38. #endif
  39. }
  40. // -----------------------------------------------------------------------------
  41. // EMON
  42. // -----------------------------------------------------------------------------
  43. void setCurrentRatio(float value) {
  44. emon.setCurrentRatio(value);
  45. }
  46. unsigned int getPower() {
  47. return _power;
  48. }
  49. double getCurrent() {
  50. return _current;
  51. }
  52. void powerMonitorSetup() {
  53. // backwards compatibility
  54. String tmp;
  55. tmp = getSetting("pwMainsVoltage", EMON_MAINS_VOLTAGE);
  56. setSetting("emonMains", tmp);
  57. delSetting("pwMainsVoltage");
  58. tmp = getSetting("pwCurrentRatio", EMON_CURRENT_RATIO);
  59. setSetting("emonRatio", tmp);
  60. delSetting("pwCurrentRatio");
  61. emon.initCurrent(
  62. currentCallback,
  63. EMON_ADC_BITS,
  64. EMON_REFERENCE_VOLTAGE,
  65. getSetting("emonRatio", EMON_CURRENT_RATIO).toFloat()
  66. );
  67. emon.setPrecision(EMON_CURRENT_PRECISION);
  68. #if EMON_PROVIDER == EMON_ADC121_PROVIDER
  69. uint8_t buffer[2];
  70. buffer[0] = ADC121_REG_CONFIG;
  71. buffer[1] = 0x00;
  72. brzo_i2c_start_transaction(EMON_ADC121_ADDRESS, I2C_SCL_FREQUENCY);
  73. brzo_i2c_write(buffer, 2, false);
  74. brzo_i2c_end_transaction();
  75. #endif
  76. apiRegister("/api/power", "power", [](char * buffer, size_t len) {
  77. snprintf(buffer, len, "%d", _power);
  78. });
  79. }
  80. void powerMonitorLoop() {
  81. static unsigned long next_measurement = millis();
  82. static bool warmup = true;
  83. static byte measurements = 0;
  84. static double max = 0;
  85. static double min = 0;
  86. static double sum = 0;
  87. if (!mqttConnected()) return;
  88. if (warmup) {
  89. warmup = false;
  90. emon.warmup();
  91. }
  92. if (millis() > next_measurement) {
  93. // Safety check: do not read current if relay is OFF
  94. if (!relayStatus(0)) {
  95. _current = 0;
  96. } else {
  97. _current = emon.getCurrent(EMON_SAMPLES);
  98. _current -= EMON_CURRENT_OFFSET;
  99. if (_current < 0) _current = 0;
  100. }
  101. if (measurements == 0) {
  102. max = min = _current;
  103. } else {
  104. if (_current > max) max = _current;
  105. if (_current < min) min = _current;
  106. }
  107. sum += _current;
  108. ++measurements;
  109. float mainsVoltage = getSetting("emonMains", EMON_MAINS_VOLTAGE).toFloat();
  110. char current[6];
  111. dtostrf(_current, 5, 2, current);
  112. DEBUG_MSG("[ENERGY] Current: %sA\n", current);
  113. DEBUG_MSG("[ENERGY] Power: %dW\n", int(_current * mainsVoltage));
  114. // Update websocket clients
  115. char text[20];
  116. sprintf_P(text, PSTR("{\"emonPower\": %d}"), int(_current * mainsVoltage));
  117. wsSend(text);
  118. // Send MQTT messages averaged every EMON_MEASUREMENTS
  119. if (measurements == EMON_MEASUREMENTS) {
  120. _power = (int) ((sum - max - min) * mainsVoltage / (measurements - 2));
  121. sum = 0;
  122. measurements = 0;
  123. char power[6];
  124. snprintf(power, 6, "%d", _power);
  125. mqttSend(getSetting("emonPowerTopic", EMON_POWER_TOPIC).c_str(), power);
  126. #if ENABLE_DOMOTICZ
  127. domoticzSend("dczPowIdx", power);
  128. #endif
  129. }
  130. next_measurement += EMON_INTERVAL;
  131. }
  132. }
  133. #endif