Fix: Prevent partly calculated total data in web ui and display
Leads to zeros where no zeros should be.
This commit is contained in:
parent
bd891f9a6d
commit
24f063dd7b
@ -2,6 +2,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <TimeoutHelper.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
class DatastoreClass {
|
||||
public:
|
||||
@ -10,52 +12,69 @@ public:
|
||||
void loop();
|
||||
|
||||
// Sum of yield total of all enabled inverters, a inverter which is just disabled at night is also included
|
||||
float totalAcYieldTotalEnabled = 0;
|
||||
float getTotalAcYieldTotalEnabled();
|
||||
|
||||
// Sum of yield day of all enabled inverters, a inverter which is just disabled at night is also included
|
||||
float totalAcYieldDayEnabled = 0;
|
||||
float getTotalAcYieldDayEnabled();
|
||||
|
||||
// Sum of total AC power of all enabled inverters
|
||||
float totalAcPowerEnabled = 0;
|
||||
float getTotalAcPowerEnabled();
|
||||
|
||||
// Sum of total DC power of all enabled inverters
|
||||
float totalDcPowerEnabled = 0;
|
||||
float getTotalDcPowerEnabled();
|
||||
|
||||
// Sum of total DC power of all enabled inverters with maxStringPower set
|
||||
float totalDcPowerIrradiation = 0;
|
||||
float getTotalDcPowerIrradiation();
|
||||
|
||||
// Sum of total installed irradiation of all enabled inverters
|
||||
float totalDcIrradiationInstalled = 0;
|
||||
float getTotalDcIrradiationInstalled();
|
||||
|
||||
// Percentage (1-100) of total irradiation
|
||||
float totalDcIrradiation = 0;
|
||||
float getTotalDcIrradiation();
|
||||
|
||||
// Amount of relevant digits for yield total
|
||||
unsigned int totalAcYieldTotalDigits = 0;
|
||||
unsigned int getTotalAcYieldTotalDigits();
|
||||
|
||||
// Amount of relevant digits for yield total
|
||||
unsigned int totalAcYieldDayDigits = 0;
|
||||
unsigned int getTotalAcYieldDayDigits();
|
||||
|
||||
// Amount of relevant digits for AC power
|
||||
unsigned int totalAcPowerDigits = 0;
|
||||
unsigned int getTotalAcPowerDigits();
|
||||
|
||||
// Amount of relevant digits for DC power
|
||||
unsigned int totalDcPowerDigits = 0;
|
||||
unsigned int getTotalDcPowerDigits();
|
||||
|
||||
// True, if at least one inverter is reachable
|
||||
bool isAtLeastOneReachable = false;
|
||||
bool getIsAtLeastOneReachable();
|
||||
|
||||
// True if at least one inverter is producing
|
||||
bool isAtLeastOneProducing = false;
|
||||
bool getIsAtLeastOneProducing();
|
||||
|
||||
// True if all enabled inverters are producing
|
||||
bool isAllEnabledProducing = false;
|
||||
bool getIsAllEnabledProducing();
|
||||
|
||||
// True if all enabled inverters are reachable
|
||||
bool isAllEnabledReachable = false;
|
||||
bool getIsAllEnabledReachable();
|
||||
|
||||
private:
|
||||
TimeoutHelper _updateTimeout;
|
||||
SemaphoreHandle_t _xSemaphore;
|
||||
|
||||
float _totalAcYieldTotalEnabled = 0;
|
||||
float _totalAcYieldDayEnabled = 0;
|
||||
float _totalAcPowerEnabled = 0;
|
||||
float _totalDcPowerEnabled = 0;
|
||||
float _totalDcPowerIrradiation = 0;
|
||||
float _totalDcIrradiationInstalled = 0;
|
||||
float _totalDcIrradiation = 0;
|
||||
unsigned int _totalAcYieldTotalDigits = 0;
|
||||
unsigned int _totalAcYieldDayDigits = 0;
|
||||
unsigned int _totalAcPowerDigits = 0;
|
||||
unsigned int _totalDcPowerDigits = 0;
|
||||
bool _isAtLeastOneReachable = false;
|
||||
bool _isAtLeastOneProducing = false;
|
||||
bool _isAllEnabledProducing = false;
|
||||
bool _isAllEnabledReachable = false;
|
||||
};
|
||||
|
||||
extern DatastoreClass Datastore;
|
||||
@ -6,10 +6,17 @@
|
||||
#include "Configuration.h"
|
||||
#include <Hoymiles.h>
|
||||
|
||||
#define DAT_SEMAPHORE_TAKE() \
|
||||
do { \
|
||||
} while (xSemaphoreTake(_xSemaphore, portMAX_DELAY) != pdPASS)
|
||||
#define DAT_SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore)
|
||||
|
||||
DatastoreClass Datastore;
|
||||
|
||||
DatastoreClass::DatastoreClass()
|
||||
{
|
||||
_xSemaphore = xSemaphoreCreateMutex();
|
||||
DAT_SEMAPHORE_GIVE(); // release before first use
|
||||
}
|
||||
|
||||
void DatastoreClass::init()
|
||||
@ -24,23 +31,25 @@ void DatastoreClass::loop()
|
||||
uint8_t isProducing = 0;
|
||||
uint8_t isReachable = 0;
|
||||
|
||||
totalAcYieldTotalEnabled = 0;
|
||||
totalAcYieldTotalDigits = 0;
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
|
||||
totalAcYieldDayEnabled = 0;
|
||||
totalAcYieldDayDigits = 0;
|
||||
_totalAcYieldTotalEnabled = 0;
|
||||
_totalAcYieldTotalDigits = 0;
|
||||
|
||||
totalAcPowerEnabled = 0;
|
||||
totalAcPowerDigits = 0;
|
||||
_totalAcYieldDayEnabled = 0;
|
||||
_totalAcYieldDayDigits = 0;
|
||||
|
||||
totalDcPowerEnabled = 0;
|
||||
totalDcPowerDigits = 0;
|
||||
_totalAcPowerEnabled = 0;
|
||||
_totalAcPowerDigits = 0;
|
||||
|
||||
totalDcPowerIrradiation = 0;
|
||||
totalDcIrradiationInstalled = 0;
|
||||
_totalDcPowerEnabled = 0;
|
||||
_totalDcPowerDigits = 0;
|
||||
|
||||
isAllEnabledProducing = true;
|
||||
isAllEnabledReachable = true;
|
||||
_totalDcPowerIrradiation = 0;
|
||||
_totalDcIrradiationInstalled = 0;
|
||||
|
||||
_isAllEnabledProducing = true;
|
||||
_isAllEnabledReachable = true;
|
||||
|
||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||
auto inv = Hoymiles.getInverterByPos(i);
|
||||
@ -57,7 +66,7 @@ void DatastoreClass::loop()
|
||||
isProducing++;
|
||||
} else {
|
||||
if (inv->getEnablePolling()) {
|
||||
isAllEnabledProducing = false;
|
||||
_isAllEnabledProducing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,42 +74,164 @@ void DatastoreClass::loop()
|
||||
isReachable++;
|
||||
} else {
|
||||
if (inv->getEnablePolling()) {
|
||||
isAllEnabledReachable = false;
|
||||
_isAllEnabledReachable = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
if (cfg->Poll_Enable) {
|
||||
totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
|
||||
totalAcYieldTotalDigits = max<unsigned int>(totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
||||
totalAcYieldDayDigits = max<unsigned int>(totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
||||
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
||||
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
||||
}
|
||||
if (inv->getEnablePolling()) {
|
||||
totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
totalAcPowerDigits = max<unsigned int>(totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
||||
_totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
_totalAcPowerDigits = max<unsigned int>(_totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_DC)) {
|
||||
if (inv->getEnablePolling()) {
|
||||
totalDcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||
totalDcPowerDigits = max<unsigned int>(totalDcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_DC, c, FLD_PDC));
|
||||
_totalDcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||
_totalDcPowerDigits = max<unsigned int>(_totalDcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_DC, c, FLD_PDC));
|
||||
|
||||
if (inv->Statistics()->getStringMaxPower(c) > 0) {
|
||||
totalDcPowerIrradiation += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||
totalDcIrradiationInstalled += inv->Statistics()->getStringMaxPower(c);
|
||||
_totalDcPowerIrradiation += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||
_totalDcIrradiationInstalled += inv->Statistics()->getStringMaxPower(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isAtLeastOneProducing = isProducing > 0;
|
||||
isAtLeastOneReachable = isReachable > 0;
|
||||
_isAtLeastOneProducing = isProducing > 0;
|
||||
_isAtLeastOneReachable = isReachable > 0;
|
||||
|
||||
totalDcIrradiation = totalDcIrradiationInstalled > 0 ? totalDcPowerIrradiation / totalDcIrradiationInstalled * 100.0f : 0;
|
||||
_totalDcIrradiation = _totalDcIrradiationInstalled > 0 ? _totalDcPowerIrradiation / _totalDcIrradiationInstalled * 100.0f : 0;
|
||||
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
|
||||
_updateTimeout.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalAcYieldTotalEnabled()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalAcYieldTotalEnabled;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalAcYieldDayEnabled()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalAcYieldDayEnabled;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalAcPowerEnabled()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalAcPowerEnabled;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalDcPowerEnabled()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalDcPowerEnabled;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalDcPowerIrradiation()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalDcPowerIrradiation;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalDcIrradiationInstalled()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalDcIrradiationInstalled;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
float DatastoreClass::getTotalDcIrradiation()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
float retval = _totalDcIrradiation;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned int DatastoreClass::getTotalAcYieldTotalDigits()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
unsigned int retval = _totalAcYieldTotalDigits;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned int DatastoreClass::getTotalAcYieldDayDigits()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
unsigned int retval = _totalAcYieldDayDigits;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned int DatastoreClass::getTotalAcPowerDigits()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
unsigned int retval = _totalAcPowerDigits;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned int DatastoreClass::getTotalDcPowerDigits()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
unsigned int retval = _totalDcPowerDigits;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool DatastoreClass::getIsAtLeastOneReachable()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
bool retval = _isAtLeastOneReachable;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool DatastoreClass::getIsAtLeastOneProducing()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
bool retval = _isAtLeastOneProducing;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool DatastoreClass::getIsAllEnabledProducing()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
bool retval = _isAllEnabledProducing;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool DatastoreClass::getIsAllEnabledReachable()
|
||||
{
|
||||
DAT_SEMAPHORE_TAKE();
|
||||
bool retval = _isAllEnabledReachable;
|
||||
DAT_SEMAPHORE_GIVE();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -141,12 +141,12 @@ void DisplayGraphicClass::loop()
|
||||
_display->clearBuffer();
|
||||
|
||||
//=====> Actual Production ==========
|
||||
if (Datastore.isAtLeastOneReachable) {
|
||||
if (Datastore.getIsAtLeastOneReachable()) {
|
||||
_display->setPowerSave(false);
|
||||
if (Datastore.totalAcPowerEnabled > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], (Datastore.totalAcPowerEnabled / 1000));
|
||||
if (Datastore.getTotalAcPowerEnabled() > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], (Datastore.getTotalAcPowerEnabled() / 1000));
|
||||
} else {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], Datastore.totalAcPowerEnabled);
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], Datastore.getTotalAcPowerEnabled());
|
||||
}
|
||||
printText(_fmtText, 0);
|
||||
_previousMillis = millis();
|
||||
@ -164,10 +164,10 @@ void DisplayGraphicClass::loop()
|
||||
//<=======================
|
||||
|
||||
//=====> Today & Total Production =======
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.totalAcYieldDayEnabled);
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.getTotalAcYieldDayEnabled());
|
||||
printText(_fmtText, 1);
|
||||
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.totalAcYieldTotalEnabled);
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.getTotalAcYieldTotalEnabled());
|
||||
printText(_fmtText, 2);
|
||||
//<=======================
|
||||
|
||||
|
||||
@ -59,10 +59,10 @@ void LedSingleClass::loop()
|
||||
_ledState[1] = LedState_t::Off;
|
||||
if (Hoymiles.getNumInverters()) {
|
||||
// set LED status
|
||||
if (Datastore.isAllEnabledReachable && Datastore.isAllEnabledProducing) {
|
||||
if (Datastore.getIsAllEnabledReachable() && Datastore.getIsAllEnabledProducing()) {
|
||||
_ledState[1] = LedState_t::On;
|
||||
}
|
||||
if (Datastore.isAllEnabledReachable && !Datastore.isAllEnabledProducing) {
|
||||
if (Datastore.getIsAllEnabledReachable() && !Datastore.getIsAllEnabledProducing()) {
|
||||
_ledState[1] = LedState_t::Blink;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,13 +22,13 @@ void MqttHandleInverterTotalClass::loop()
|
||||
}
|
||||
|
||||
if (_lastPublish.occured()) {
|
||||
MqttSettings.publish("ac/power", String(Datastore.totalAcPowerEnabled, Datastore.totalAcPowerDigits));
|
||||
MqttSettings.publish("ac/yieldtotal", String(Datastore.totalAcYieldTotalEnabled, Datastore.totalAcYieldTotalDigits));
|
||||
MqttSettings.publish("ac/yieldday", String(Datastore.totalAcYieldDayEnabled, Datastore.totalAcYieldDayDigits));
|
||||
MqttSettings.publish("ac/is_valid", String(Datastore.isAllEnabledReachable));
|
||||
MqttSettings.publish("dc/power", String(Datastore.totalDcPowerEnabled, Datastore.totalDcPowerDigits));
|
||||
MqttSettings.publish("dc/irradiation", String(Datastore.totalDcIrradiation, 3));
|
||||
MqttSettings.publish("dc/is_valid", String(Datastore.isAllEnabledReachable));
|
||||
MqttSettings.publish("ac/power", String(Datastore.getTotalAcPowerEnabled(), Datastore.getTotalAcPowerDigits()));
|
||||
MqttSettings.publish("ac/yieldtotal", String(Datastore.getTotalAcYieldTotalEnabled(), Datastore.getTotalAcYieldTotalDigits()));
|
||||
MqttSettings.publish("ac/yieldday", String(Datastore.getTotalAcYieldDayEnabled(), Datastore.getTotalAcYieldDayDigits()));
|
||||
MqttSettings.publish("ac/is_valid", String(Datastore.getIsAllEnabledReachable()));
|
||||
MqttSettings.publish("dc/power", String(Datastore.getTotalDcPowerEnabled(), Datastore.getTotalDcPowerDigits()));
|
||||
MqttSettings.publish("dc/irradiation", String(Datastore.getTotalDcIrradiation(), 3));
|
||||
MqttSettings.publish("dc/is_valid", String(Datastore.getIsAllEnabledReachable()));
|
||||
|
||||
_lastPublish.set(Configuration.get().Mqtt_PublishInterval * 1000);
|
||||
}
|
||||
|
||||
@ -160,9 +160,9 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
}
|
||||
|
||||
JsonObject totalObj = root.createNestedObject("total");
|
||||
addTotalField(totalObj, "Power", Datastore.totalAcPowerEnabled, "W", Datastore.totalAcPowerDigits);
|
||||
addTotalField(totalObj, "YieldDay", Datastore.totalAcYieldDayEnabled, "Wh", Datastore.totalAcYieldDayDigits);
|
||||
addTotalField(totalObj, "YieldTotal", Datastore.totalAcYieldTotalEnabled, "kWh", Datastore.totalAcYieldTotalDigits);
|
||||
addTotalField(totalObj, "Power", Datastore.getTotalAcPowerEnabled(), "W", Datastore.getTotalAcPowerDigits());
|
||||
addTotalField(totalObj, "YieldDay", Datastore.getTotalAcYieldDayEnabled(), "Wh", Datastore.getTotalAcYieldDayDigits());
|
||||
addTotalField(totalObj, "YieldTotal", Datastore.getTotalAcYieldTotalEnabled(), "kWh", Datastore.getTotalAcYieldTotalDigits());
|
||||
|
||||
JsonObject hintObj = root.createNestedObject("hints");
|
||||
struct tm timeinfo;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user