Feature: Implement offset cache for "YieldDay"
Thanks to @broth-itk for the idea! Fix: #1258 #1397
This commit is contained in:
parent
7538b4363c
commit
1de3b48166
@ -48,6 +48,7 @@ struct INVERTER_CONFIG_T {
|
|||||||
uint8_t ReachableThreshold;
|
uint8_t ReachableThreshold;
|
||||||
bool ZeroRuntimeDataIfUnrechable;
|
bool ZeroRuntimeDataIfUnrechable;
|
||||||
bool ZeroYieldDayOnMidnight;
|
bool ZeroYieldDayOnMidnight;
|
||||||
|
bool YieldDayCorrection;
|
||||||
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
|
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,7 @@ void HoymilesClass::loop()
|
|||||||
if (inv->getZeroYieldDayOnMidnight()) {
|
if (inv->getZeroYieldDayOnMidnight()) {
|
||||||
inv->Statistics()->zeroDailyData();
|
inv->Statistics()->zeroDailyData();
|
||||||
}
|
}
|
||||||
|
inv->Statistics()->resetYieldDayCorrection();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastWeekDay = currentWeekDay;
|
lastWeekDay = currentWeekDay;
|
||||||
|
|||||||
@ -82,6 +82,8 @@ void StatisticsParser::clearBuffer()
|
|||||||
{
|
{
|
||||||
memset(_payloadStatistic, 0, STATISTIC_PACKET_SIZE);
|
memset(_payloadStatistic, 0, STATISTIC_PACKET_SIZE);
|
||||||
_statisticLength = 0;
|
_statisticLength = 0;
|
||||||
|
|
||||||
|
memset(_lastYieldDay, 0, sizeof(_lastYieldDay));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t len)
|
void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t len)
|
||||||
@ -94,6 +96,31 @@ void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t
|
|||||||
_statisticLength += len;
|
_statisticLength += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatisticsParser::endAppendFragment()
|
||||||
|
{
|
||||||
|
Parser::endAppendFragment();
|
||||||
|
|
||||||
|
if (!_enableYieldDayCorrection) {
|
||||||
|
resetYieldDayCorrection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& c : getChannelsByType(TYPE_DC)) {
|
||||||
|
// check if current yield day is smaller then last cached yield day
|
||||||
|
if (getChannelFieldValue(TYPE_DC, c, FLD_YD) < _lastYieldDay[static_cast<uint8_t>(c)]) {
|
||||||
|
// currently all values are zero --> Add last known values to offset
|
||||||
|
Hoymiles.getMessageOutput()->printf("Yield Day reset detected!\r\n");
|
||||||
|
|
||||||
|
setChannelFieldOffset(TYPE_DC, c, FLD_YD,
|
||||||
|
getChannelFieldOffset(TYPE_DC, c, FLD_YD) + _lastYieldDay[static_cast<uint8_t>(c)]);
|
||||||
|
|
||||||
|
_lastYieldDay[static_cast<uint8_t>(c)] = 0;
|
||||||
|
} else {
|
||||||
|
_lastYieldDay[static_cast<uint8_t>(c)] = getChannelFieldValue(TYPE_DC, c, FLD_YD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const byteAssign_t* StatisticsParser::getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
const byteAssign_t* StatisticsParser::getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < _byteAssignmentSize; i++) {
|
for (uint8_t i = 0; i < _byteAssignmentSize; i++) {
|
||||||
@ -329,6 +356,16 @@ void StatisticsParser::setLastUpdateFromInternal(uint32_t lastUpdate)
|
|||||||
_lastUpdateFromInternal = lastUpdate;
|
_lastUpdateFromInternal = lastUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StatisticsParser::getYieldDayCorrection()
|
||||||
|
{
|
||||||
|
return _enableYieldDayCorrection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatisticsParser::setYieldDayCorrection(bool enabled)
|
||||||
|
{
|
||||||
|
_enableYieldDayCorrection = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void StatisticsParser::zeroFields(const FieldId_t* fields)
|
void StatisticsParser::zeroFields(const FieldId_t* fields)
|
||||||
{
|
{
|
||||||
// Loop all channels
|
// Loop all channels
|
||||||
@ -344,6 +381,15 @@ void StatisticsParser::zeroFields(const FieldId_t* fields)
|
|||||||
setLastUpdateFromInternal(millis());
|
setLastUpdateFromInternal(millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatisticsParser::resetYieldDayCorrection()
|
||||||
|
{
|
||||||
|
// new day detected, reset counters
|
||||||
|
for (auto& c : getChannelsByType(TYPE_DC)) {
|
||||||
|
setChannelFieldOffset(TYPE_DC, c, FLD_YD, 0);
|
||||||
|
_lastYieldDay[static_cast<uint8_t>(c)] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||||
{
|
{
|
||||||
float yield = 0;
|
float yield = 0;
|
||||||
|
|||||||
@ -106,6 +106,7 @@ public:
|
|||||||
StatisticsParser();
|
StatisticsParser();
|
||||||
void clearBuffer();
|
void clearBuffer();
|
||||||
void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len);
|
void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len);
|
||||||
|
void endAppendFragment();
|
||||||
|
|
||||||
void setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size);
|
void setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size);
|
||||||
|
|
||||||
@ -140,6 +141,7 @@ public:
|
|||||||
|
|
||||||
void zeroRuntimeData();
|
void zeroRuntimeData();
|
||||||
void zeroDailyData();
|
void zeroDailyData();
|
||||||
|
void resetYieldDayCorrection();
|
||||||
|
|
||||||
// Update time when new data from the inverter is received
|
// Update time when new data from the inverter is received
|
||||||
void setLastUpdate(uint32_t lastUpdate);
|
void setLastUpdate(uint32_t lastUpdate);
|
||||||
@ -148,6 +150,8 @@ public:
|
|||||||
uint32_t getLastUpdateFromInternal();
|
uint32_t getLastUpdateFromInternal();
|
||||||
void setLastUpdateFromInternal(uint32_t lastUpdate);
|
void setLastUpdateFromInternal(uint32_t lastUpdate);
|
||||||
|
|
||||||
|
bool getYieldDayCorrection();
|
||||||
|
void setYieldDayCorrection(bool enabled);
|
||||||
private:
|
private:
|
||||||
void zeroFields(const FieldId_t* fields);
|
void zeroFields(const FieldId_t* fields);
|
||||||
|
|
||||||
@ -162,4 +166,7 @@ private:
|
|||||||
|
|
||||||
uint32_t _rxFailureCount = 0;
|
uint32_t _rxFailureCount = 0;
|
||||||
uint32_t _lastUpdateFromInternal = 0;
|
uint32_t _lastUpdateFromInternal = 0;
|
||||||
|
|
||||||
|
bool _enableYieldDayCorrection = false;
|
||||||
|
float _lastYieldDay[CH_CNT];
|
||||||
};
|
};
|
||||||
@ -117,6 +117,7 @@ bool ConfigurationClass::write()
|
|||||||
inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
|
inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
|
||||||
inv["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
|
inv["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
|
||||||
inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
|
inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
|
||||||
|
inv["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;
|
||||||
|
|
||||||
JsonArray channel = inv.createNestedArray("channel");
|
JsonArray channel = inv.createNestedArray("channel");
|
||||||
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
||||||
@ -272,6 +273,7 @@ bool ConfigurationClass::read()
|
|||||||
config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD;
|
config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD;
|
||||||
config.Inverter[i].ZeroRuntimeDataIfUnrechable = inv["zero_runtime"] | false;
|
config.Inverter[i].ZeroRuntimeDataIfUnrechable = inv["zero_runtime"] | false;
|
||||||
config.Inverter[i].ZeroYieldDayOnMidnight = inv["zero_day"] | false;
|
config.Inverter[i].ZeroYieldDayOnMidnight = inv["zero_day"] | false;
|
||||||
|
config.Inverter[i].YieldDayCorrection = inv["yieldday_correction"] | false;
|
||||||
|
|
||||||
JsonArray channel = inv["channel"];
|
JsonArray channel = inv["channel"];
|
||||||
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
||||||
|
|||||||
@ -74,6 +74,7 @@ void InverterSettingsClass::init()
|
|||||||
inv->setReachableThreshold(config.Inverter[i].ReachableThreshold);
|
inv->setReachableThreshold(config.Inverter[i].ReachableThreshold);
|
||||||
inv->setZeroValuesIfUnreachable(config.Inverter[i].ZeroRuntimeDataIfUnrechable);
|
inv->setZeroValuesIfUnreachable(config.Inverter[i].ZeroRuntimeDataIfUnrechable);
|
||||||
inv->setZeroYieldDayOnMidnight(config.Inverter[i].ZeroYieldDayOnMidnight);
|
inv->setZeroYieldDayOnMidnight(config.Inverter[i].ZeroYieldDayOnMidnight);
|
||||||
|
inv->Statistics()->setYieldDayCorrection(config.Inverter[i].YieldDayCorrection);
|
||||||
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
||||||
inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower);
|
inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower);
|
||||||
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset);
|
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset);
|
||||||
|
|||||||
@ -61,6 +61,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
|
|||||||
obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
|
obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
|
||||||
obj["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
|
obj["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
|
||||||
obj["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
|
obj["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
|
||||||
|
obj["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;
|
||||||
|
|
||||||
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
|
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
|
||||||
uint8_t max_channels;
|
uint8_t max_channels;
|
||||||
@ -288,6 +289,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
|
|||||||
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
|
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
|
||||||
inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false;
|
inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false;
|
||||||
inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false;
|
inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false;
|
||||||
|
inverter.YieldDayCorrection = root["yieldday_correction"] | false;
|
||||||
|
|
||||||
arrayCount++;
|
arrayCount++;
|
||||||
}
|
}
|
||||||
@ -321,6 +323,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
|
|||||||
inv->setReachableThreshold(inverter.ReachableThreshold);
|
inv->setReachableThreshold(inverter.ReachableThreshold);
|
||||||
inv->setZeroValuesIfUnreachable(inverter.ZeroRuntimeDataIfUnrechable);
|
inv->setZeroValuesIfUnreachable(inverter.ZeroRuntimeDataIfUnrechable);
|
||||||
inv->setZeroYieldDayOnMidnight(inverter.ZeroYieldDayOnMidnight);
|
inv->setZeroYieldDayOnMidnight(inverter.ZeroYieldDayOnMidnight);
|
||||||
|
inv->Statistics()->setYieldDayCorrection(inverter.YieldDayCorrection);
|
||||||
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
|
||||||
inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower);
|
inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower);
|
||||||
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, inverter.channel[c].YieldTotalOffset);
|
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, inverter.channel[c].YieldTotalOffset);
|
||||||
|
|||||||
@ -494,7 +494,9 @@
|
|||||||
"Cancel": "@:maintenancereboot.Cancel",
|
"Cancel": "@:maintenancereboot.Cancel",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"DeleteMsg": "Soll der Wechselrichter \"{name}\" mit der Seriennummer {serial} wirklich gelöscht werden?",
|
"DeleteMsg": "Soll der Wechselrichter \"{name}\" mit der Seriennummer {serial} wirklich gelöscht werden?",
|
||||||
"Delete": "Löschen"
|
"Delete": "Löschen",
|
||||||
|
"YieldDayCorrection": "Tagesertragskorrektur",
|
||||||
|
"YieldDayCorrectionHint": "Summiert den Tagesertrag, auch wenn der Wechselrichter neu gestartet wird. Der Wert wird um Mitternacht zurückgesetzt"
|
||||||
},
|
},
|
||||||
"configadmin": {
|
"configadmin": {
|
||||||
"ConfigManagement": "Konfigurationsverwaltung",
|
"ConfigManagement": "Konfigurationsverwaltung",
|
||||||
|
|||||||
@ -494,7 +494,9 @@
|
|||||||
"Cancel": "@:maintenancereboot.Cancel",
|
"Cancel": "@:maintenancereboot.Cancel",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"DeleteMsg": "Are you sure you want to delete the inverter \"{name}\" with serial number {serial}?",
|
"DeleteMsg": "Are you sure you want to delete the inverter \"{name}\" with serial number {serial}?",
|
||||||
"Delete": "Delete"
|
"Delete": "Delete",
|
||||||
|
"YieldDayCorrection": "Yield Day Correction",
|
||||||
|
"YieldDayCorrectionHint": "Sum up daily yield even if the inverter is restarted. Value will be reset at midnight"
|
||||||
},
|
},
|
||||||
"configadmin": {
|
"configadmin": {
|
||||||
"ConfigManagement": "Config Management",
|
"ConfigManagement": "Config Management",
|
||||||
|
|||||||
@ -494,7 +494,9 @@
|
|||||||
"Cancel": "@:maintenancereboot.Cancel",
|
"Cancel": "@:maintenancereboot.Cancel",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"DeleteMsg": "Êtes-vous sûr de vouloir supprimer l'onduleur \"{name}\" avec le numéro de série \"{serial}\" ?",
|
"DeleteMsg": "Êtes-vous sûr de vouloir supprimer l'onduleur \"{name}\" avec le numéro de série \"{serial}\" ?",
|
||||||
"Delete": "Supprimer"
|
"Delete": "Supprimer",
|
||||||
|
"YieldDayCorrection": "Yield Day Correction",
|
||||||
|
"YieldDayCorrectionHint": "Sum up daily yield even if the inverter is restarted. Value will be reset at midnight"
|
||||||
},
|
},
|
||||||
"configadmin": {
|
"configadmin": {
|
||||||
"ConfigManagement": "Gestion de la configuration",
|
"ConfigManagement": "Gestion de la configuration",
|
||||||
|
|||||||
@ -192,6 +192,11 @@
|
|||||||
v-model="selectedInverterData.zero_day"
|
v-model="selectedInverterData.zero_day"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:tooltip="$t('inverteradmin.ZeroDayHint')" wide/>
|
:tooltip="$t('inverteradmin.ZeroDayHint')" wide/>
|
||||||
|
|
||||||
|
<InputElement :label="$t('inverteradmin.YieldDayCorrection')"
|
||||||
|
v-model="selectedInverterData.yieldday_correction"
|
||||||
|
type="checkbox"
|
||||||
|
:tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -269,6 +274,7 @@ declare interface Inverter {
|
|||||||
reachable_threshold: number;
|
reachable_threshold: number;
|
||||||
zero_runtime: boolean;
|
zero_runtime: boolean;
|
||||||
zero_day: boolean;
|
zero_day: boolean;
|
||||||
|
yieldday_correction: boolean;
|
||||||
channel: Array<Channel>;
|
channel: Array<Channel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user