Skip to content

Commit

Permalink
DPL: improve verbose logging (more variables logged)
Browse files Browse the repository at this point in the history
  • Loading branch information
schlimmchen committed Mar 22, 2024
1 parent 03435f6 commit 13e4205
Showing 1 changed file with 70 additions and 42 deletions.
112 changes: 70 additions & 42 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ void PowerLimiterClass::announceStatus(PowerLimiterClass::Status status)
// should just be silent while it is disabled.
if (status == Status::DisabledByConfig && _lastStatus == status) { return; }

MessageOutput.printf("[%11.3f] DPL: %s\r\n",
static_cast<double>(millis())/1000, getStatusText(status).data());
MessageOutput.printf("[DPL::announceStatus] %s\r\n",
getStatusText(status).data());

_lastStatus = status;
_lastStatusPrinted = millis();
Expand Down Expand Up @@ -266,14 +266,7 @@ void PowerLimiterClass::loop()

_batteryDischargeEnabled = getBatteryPower();

auto logging = [this,&config]() -> void {
MessageOutput.printf("[DPL::loop] PowerMeter: %d W, target consumption: %d W, solar power: %d W\r\n",
static_cast<int32_t>(round(PowerMeter.getPowerTotal())),
config.PowerLimiter.TargetPowerConsumption,
getSolarPower());

if (config.PowerLimiter.IsInverterSolarPowered) { return; }

if (_verboseLogging && !config.PowerLimiter.IsInverterSolarPowered) {
MessageOutput.printf("[DPL::loop] battery interface %s, SoC: %d %%, StartTH: %d %%, StopTH: %d %%, SoC age: %d s, ignore: %s\r\n",
(config.Battery.Enabled?"enabled":"disabled"),
Battery.getStats()->getSoC(),
Expand All @@ -288,19 +281,13 @@ void PowerLimiterClass::loop()
config.PowerLimiter.VoltageStartThreshold,
config.PowerLimiter.VoltageStopThreshold);

MessageOutput.printf("[DPL::loop] StartTH reached: %s, StopTH reached: %s, inverter %s producing\r\n",
MessageOutput.printf("[DPL::loop] StartTH reached: %s, StopTH reached: %s, SolarPT %sabled, use at night: %s\r\n",
(isStartThresholdReached()?"yes":"no"),
(isStopThresholdReached()?"yes":"no"),
(_inverter->isProducing()?"is":"is NOT"));

MessageOutput.printf("[DPL::loop] battery discharging %s, SolarPT %s, use at night: %i\r\n",
(_batteryDischargeEnabled?"allowed":"prevented"),
(config.PowerLimiter.SolarPassThroughEnabled?"enabled":"disabled"),
config.PowerLimiter.BatteryAlwaysUseAtNight);
(config.PowerLimiter.SolarPassThroughEnabled?"en":"dis"),
(config.PowerLimiter.BatteryAlwaysUseAtNight?"yes":"no"));
};

if (_verboseLogging) { logging(); }

// Calculate and set Power Limit (NOTE: might reset _inverter to nullptr!)
bool limitUpdated = calcPowerLimit(_inverter, getSolarPower(), _batteryDischargeEnabled);

Expand All @@ -325,7 +312,7 @@ void PowerLimiterClass::loop()
float PowerLimiterClass::getBatteryVoltage(bool log) {
if (!_inverter) {
// there should be no need to call this method if no target inverter is known
MessageOutput.println("DPL getBatteryVoltage: no inverter (programmer error)");
MessageOutput.println("[DPL::getBatteryVoltage] no inverter (programmer error)");
return 0.0;
}

Expand Down Expand Up @@ -426,7 +413,12 @@ uint8_t PowerLimiterClass::getPowerLimiterState() {

bool PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t solarPowerDC, bool batteryPower)
{
if (solarPowerDC == 0 && !batteryPower) {
if (_verboseLogging) {
MessageOutput.printf("[DPL::calcPowerLimit] battery use %s, solar power (DC): %d W\r\n",
(batteryPower?"allowed":"prevented"), solarPowerDC);
}

if (solarPowerDC <= 0 && !batteryPower) {
return shutdown(Status::NoEnergy);
}

Expand All @@ -439,40 +431,66 @@ bool PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inverte
return shutdown(Status::HuaweiPsu);
}

int32_t newPowerLimit = round(PowerMeter.getPowerTotal());
auto powerMeter = static_cast<int32_t>(PowerMeter.getPowerTotal());

auto inverterOutput = static_cast<int32_t>(inverter->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PAC));

auto solarPowerAC = inverterPowerDcToAc(inverter, solarPowerDC);

auto const& config = Configuration.get();

if (_verboseLogging) {
MessageOutput.printf("[DPL::calcPowerLimit] power meter: %d W, "
"target consumption: %d W, inverter output: %d W, solar power (AC): %d\r\n",
powerMeter,
config.PowerLimiter.TargetPowerConsumption,
inverterOutput,
solarPowerAC);
}

auto newPowerLimit = powerMeter;

if (config.PowerLimiter.IsInverterBehindPowerMeter) {
// If the inverter the behind the power meter (part of measurement),
// the produced power of this inverter has also to be taken into account.
// We don't use FLD_PAC from the statistics, because that
// data might be too old and unreliable.
auto acPower = inverter->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PAC);
newPowerLimit += acPower;
newPowerLimit += inverterOutput;
}

// We're not trying to hit 0 exactly but take an offset into account
// This means we never fully compensate the used power with the inverter
// Case 3
newPowerLimit -= config.PowerLimiter.TargetPowerConsumption;

int32_t solarPowerAC = inverterPowerDcToAc(inverter, solarPowerDC);

if (!batteryPower) {
newPowerLimit = std::min(newPowerLimit, solarPowerAC);

// do not drain the battery. use as much power as needed to match the
// household consumption, but not more than the available solar power.
if (_verboseLogging) {
MessageOutput.printf("[DPL::loop] Consuming Solar Power Only -> solarPowerAC: %d W, newPowerLimit: %d W\r\n",
solarPowerAC, newPowerLimit);
MessageOutput.printf("[DPL::calcPowerLimit] limited to solar power: %d W\r\n",
newPowerLimit);
}

return setNewPowerLimit(inverter, std::min(newPowerLimit, solarPowerAC));
return setNewPowerLimit(inverter, newPowerLimit);
}

// convert all solar power if full solar-passthrough is active
if (useFullSolarPassthrough()) {
return setNewPowerLimit(inverter, std::max(newPowerLimit, solarPowerAC));
newPowerLimit = std::max(newPowerLimit, solarPowerAC);

if (_verboseLogging) {
MessageOutput.printf("[DPL::calcPowerLimit] full solar-passthrough active: %d W\r\n",
newPowerLimit);
}

return setNewPowerLimit(inverter, newPowerLimit);
}

if (_verboseLogging) {
MessageOutput.printf("[DPL::calcPowerLimit] match power meter with limit of %d W\r\n",
newPowerLimit);
}

return setNewPowerLimit(inverter, newPowerLimit);
Expand Down Expand Up @@ -566,7 +584,7 @@ bool PowerLimiterClass::updateInverter()
uint32_t lastLimitCommandMillis = _inverter->SystemConfigPara()->getLastUpdateCommand();
if ((lastLimitCommandMillis - *_oUpdateStartMillis) < halfOfAllMillis &&
CMD_OK == lastLimitCommandState) {
MessageOutput.printf("[DPL:updateInverter] actual limit is %.1f %% "
MessageOutput.printf("[DPL::updateInverter] actual limit is %.1f %% "
"(%.0f W respectively), effective %d ms after update started, "
"requested were %.1f %%\r\n",
currentRelativeLimit,
Expand All @@ -575,7 +593,7 @@ bool PowerLimiterClass::updateInverter()
newRelativeLimit);

if (std::abs(newRelativeLimit - currentRelativeLimit) > 2.0) {
MessageOutput.printf("[DPL:updateInverter] NOTE: expected limit of %.1f %% "
MessageOutput.printf("[DPL::updateInverter] NOTE: expected limit of %.1f %% "
"and actual limit of %.1f %% mismatch by more than 2 %%, "
"is the DPL in exclusive control over the inverter?\r\n",
newRelativeLimit, currentRelativeLimit);
Expand Down Expand Up @@ -652,9 +670,10 @@ static int32_t scalePowerLimit(std::shared_ptr<InverterAbstract> inverter, int32

if (dcProdChnls == 0 || dcProdChnls == dcTotalChnls) { return newLimit; }

MessageOutput.printf("[DPL::scalePowerLimit] %d channels total, %d producing "
"channels, scaling power limit\r\n", dcTotalChnls, dcProdChnls);
return round(newLimit * static_cast<float>(dcTotalChnls) / dcProdChnls);
auto scaled = static_cast<int32_t>(newLimit * static_cast<float>(dcTotalChnls) / dcProdChnls);
MessageOutput.printf("[DPL::scalePowerLimit] %d/%d channels are producing, "
"scaling from %d to %d W\r\n", dcProdChnls, dcTotalChnls, newLimit, scaled);
return scaled;
}

/**
Expand All @@ -666,13 +685,22 @@ static int32_t scalePowerLimit(std::shared_ptr<InverterAbstract> inverter, int32
bool PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit)
{
auto const& config = Configuration.get();
auto lowerLimit = config.PowerLimiter.LowerPowerLimit;
auto upperLimit = config.PowerLimiter.UpperPowerLimit;
auto hysteresis = config.PowerLimiter.TargetPowerConsumptionHysteresis;

if (newPowerLimit < config.PowerLimiter.LowerPowerLimit) {
if (_verboseLogging) {
MessageOutput.printf("[DPL::setNewPowerLimit] input limit: %d W, "
"lower limit: %d W, upper limit: %d W, hysteresis: %d W\r\n",
newPowerLimit, lowerLimit, upperLimit, hysteresis);
}

if (newPowerLimit < lowerLimit) {
return shutdown(Status::CalculatedLimitBelowMinLimit);
}

// enforce configured upper power limit
int32_t effPowerLimit = std::min(newPowerLimit, config.PowerLimiter.UpperPowerLimit);
int32_t effPowerLimit = std::min(newPowerLimit, upperLimit);

// early in the loop we make it a pre-requisite that this
// value is non-zero, so we can assume it to be valid.
Expand All @@ -686,12 +714,12 @@ bool PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inver
effPowerLimit = std::min<int32_t>(effPowerLimit, maxPower);

auto diff = std::abs(currentLimitAbs - effPowerLimit);
auto hysteresis = config.PowerLimiter.TargetPowerConsumptionHysteresis;

if (_verboseLogging) {
MessageOutput.printf("[DPL::setNewPowerLimit] calculated: %d W, "
"requesting: %d W, reported: %d W, diff: %d W, hysteresis: %d W\r\n",
newPowerLimit, effPowerLimit, currentLimitAbs, diff, hysteresis);
MessageOutput.printf("[DPL::setNewPowerLimit] inverter max: %d W, "
"inverter %s producing, requesting: %d W, reported: %d W, "
"diff: %d W\r\n", maxPower, (inverter->isProducing()?"is":"is NOT"),
effPowerLimit, currentLimitAbs, diff);
}

if (diff > hysteresis) {
Expand Down Expand Up @@ -728,7 +756,7 @@ float PowerLimiterClass::getLoadCorrectedVoltage()
{
if (!_inverter) {
// there should be no need to call this method if no target inverter is known
MessageOutput.println("DPL getLoadCorrectedVoltage: no inverter (programmer error)");
MessageOutput.println("[DPL::getLoadCorrectedVoltage] no inverter (programmer error)");
return 0.0;
}

Expand Down

0 comments on commit 13e4205

Please sign in to comment.