Skip to content

Commit

Permalink
Feature: Implement offset cache for "YieldDay"
Browse files Browse the repository at this point in the history
Thanks to @broth-itk for the idea!
Fix: #1258 #1397
  • Loading branch information
tbnobody committed Nov 22, 2023
1 parent 7538b43 commit 1de3b48
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct INVERTER_CONFIG_T {
uint8_t ReachableThreshold;
bool ZeroRuntimeDataIfUnrechable;
bool ZeroYieldDayOnMidnight;
bool YieldDayCorrection;
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
};

Expand Down
1 change: 1 addition & 0 deletions lib/Hoymiles/src/Hoymiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ void HoymilesClass::loop()
if (inv->getZeroYieldDayOnMidnight()) {
inv->Statistics()->zeroDailyData();
}
inv->Statistics()->resetYieldDayCorrection();
}

lastWeekDay = currentWeekDay;
Expand Down
46 changes: 46 additions & 0 deletions lib/Hoymiles/src/parser/StatisticsParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ void StatisticsParser::clearBuffer()
{
memset(_payloadStatistic, 0, STATISTIC_PACKET_SIZE);
_statisticLength = 0;

memset(_lastYieldDay, 0, sizeof(_lastYieldDay));
}

void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t len)
Expand All @@ -94,6 +96,31 @@ void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t
_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)
{
for (uint8_t i = 0; i < _byteAssignmentSize; i++) {
Expand Down Expand Up @@ -329,6 +356,16 @@ void StatisticsParser::setLastUpdateFromInternal(uint32_t lastUpdate)
_lastUpdateFromInternal = lastUpdate;
}

bool StatisticsParser::getYieldDayCorrection()
{
return _enableYieldDayCorrection;
}

void StatisticsParser::setYieldDayCorrection(bool enabled)
{
_enableYieldDayCorrection = enabled;
}

void StatisticsParser::zeroFields(const FieldId_t* fields)
{
// Loop all channels
Expand All @@ -344,6 +381,15 @@ void StatisticsParser::zeroFields(const FieldId_t* fields)
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)
{
float yield = 0;
Expand Down
7 changes: 7 additions & 0 deletions lib/Hoymiles/src/parser/StatisticsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class StatisticsParser : public Parser {
StatisticsParser();
void clearBuffer();
void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len);
void endAppendFragment();

void setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size);

Expand Down Expand Up @@ -140,6 +141,7 @@ class StatisticsParser : public Parser {

void zeroRuntimeData();
void zeroDailyData();
void resetYieldDayCorrection();

// Update time when new data from the inverter is received
void setLastUpdate(uint32_t lastUpdate);
Expand All @@ -148,6 +150,8 @@ class StatisticsParser : public Parser {
uint32_t getLastUpdateFromInternal();
void setLastUpdateFromInternal(uint32_t lastUpdate);

bool getYieldDayCorrection();
void setYieldDayCorrection(bool enabled);
private:
void zeroFields(const FieldId_t* fields);

Expand All @@ -162,4 +166,7 @@ class StatisticsParser : public Parser {

uint32_t _rxFailureCount = 0;
uint32_t _lastUpdateFromInternal = 0;

bool _enableYieldDayCorrection = false;
float _lastYieldDay[CH_CNT];
};
2 changes: 2 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ bool ConfigurationClass::write()
inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
inv["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
inv["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;

JsonArray channel = inv.createNestedArray("channel");
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
Expand Down Expand Up @@ -272,6 +273,7 @@ bool ConfigurationClass::read()
config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD;
config.Inverter[i].ZeroRuntimeDataIfUnrechable = inv["zero_runtime"] | false;
config.Inverter[i].ZeroYieldDayOnMidnight = inv["zero_day"] | false;
config.Inverter[i].YieldDayCorrection = inv["yieldday_correction"] | false;

JsonArray channel = inv["channel"];
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
Expand Down
1 change: 1 addition & 0 deletions src/InverterSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ void InverterSettingsClass::init()
inv->setReachableThreshold(config.Inverter[i].ReachableThreshold);
inv->setZeroValuesIfUnreachable(config.Inverter[i].ZeroRuntimeDataIfUnrechable);
inv->setZeroYieldDayOnMidnight(config.Inverter[i].ZeroYieldDayOnMidnight);
inv->Statistics()->setYieldDayCorrection(config.Inverter[i].YieldDayCorrection);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
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);
Expand Down
3 changes: 3 additions & 0 deletions src/WebApi_inverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
obj["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
obj["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
obj["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;

auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
uint8_t max_channels;
Expand Down Expand Up @@ -288,6 +289,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false;
inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false;
inverter.YieldDayCorrection = root["yieldday_correction"] | false;

arrayCount++;
}
Expand Down Expand Up @@ -321,6 +323,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
inv->setReachableThreshold(inverter.ReachableThreshold);
inv->setZeroValuesIfUnreachable(inverter.ZeroRuntimeDataIfUnrechable);
inv->setZeroYieldDayOnMidnight(inverter.ZeroYieldDayOnMidnight);
inv->Statistics()->setYieldDayCorrection(inverter.YieldDayCorrection);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower);
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, inverter.channel[c].YieldTotalOffset);
Expand Down
4 changes: 3 additions & 1 deletion webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,9 @@
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"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": {
"ConfigManagement": "Konfigurationsverwaltung",
Expand Down
4 changes: 3 additions & 1 deletion webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,9 @@
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"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": {
"ConfigManagement": "Config Management",
Expand Down
4 changes: 3 additions & 1 deletion webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,9 @@
"Cancel": "@:maintenancereboot.Cancel",
"Save": "@:dtuadmin.Save",
"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": {
"ConfigManagement": "Gestion de la configuration",
Expand Down
6 changes: 6 additions & 0 deletions webapp/src/views/InverterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
v-model="selectedInverterData.zero_day"
type="checkbox"
:tooltip="$t('inverteradmin.ZeroDayHint')" wide/>

<InputElement :label="$t('inverteradmin.YieldDayCorrection')"
v-model="selectedInverterData.yieldday_correction"
type="checkbox"
:tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide/>
</div>
</div>
</form>
Expand Down Expand Up @@ -269,6 +274,7 @@ declare interface Inverter {
reachable_threshold: number;
zero_runtime: boolean;
zero_day: boolean;
yieldday_correction: boolean;
channel: Array<Channel>;
}
Expand Down

0 comments on commit 1de3b48

Please sign in to comment.