DPL: consider the system stable when reusing the old limit

a new status is needed to communicate that no update was sent to the
inverter because its power limit is still valid. in this case,
calculating a new power limit is delayed by an exponentially increasing
backoff. the maximum backoff time is ~1s, which is still plenty fast.

the backoff is actually necessary for another reason: at least
currently, a lot of debug messages are printed to the console. printing
all that information in every DPL loop() is too much.
This commit is contained in:
Bernhard Kirchen 2023-06-30 19:21:44 +02:00
parent 461fce8ff4
commit 9aeb1583b5
2 changed files with 29 additions and 6 deletions

View File

@ -41,6 +41,7 @@ public:
UnconditionalSolarPassthrough, UnconditionalSolarPassthrough,
NoVeDirect, NoVeDirect,
Settling, Settling,
Stable,
LowerLimitUndercut LowerLimitUndercut
}; };
@ -57,6 +58,8 @@ private:
bool _shutdownInProgress; bool _shutdownInProgress;
Status _lastStatus = Status::Initializing; Status _lastStatus = Status::Initializing;
uint32_t _lastStatusPrinted = 0; uint32_t _lastStatusPrinted = 0;
uint32_t _lastCalculation = 0;
uint32_t _calculationBackoffMs = 0;
uint8_t _mode = PL_MODE_ENABLE_NORMAL_OP; uint8_t _mode = PL_MODE_ENABLE_NORMAL_OP;
std::shared_ptr<InverterAbstract> _inverter = nullptr; std::shared_ptr<InverterAbstract> _inverter = nullptr;
bool _batteryDischargeEnabled = false; bool _batteryDischargeEnabled = false;
@ -72,7 +75,7 @@ private:
bool canUseDirectSolarPower(); bool canUseDirectSolarPower();
int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool solarPowerEnabled, bool batteryDischargeEnabled); int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool solarPowerEnabled, bool batteryDischargeEnabled);
void commitPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t limit, bool enablePowerProduction); void commitPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t limit, bool enablePowerProduction);
void setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit); bool setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit);
int32_t getSolarChargePower(); int32_t getSolarChargePower();
float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter); float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter);
bool isStartThresholdReached(std::shared_ptr<InverterAbstract> inverter); bool isStartThresholdReached(std::shared_ptr<InverterAbstract> inverter);

View File

@ -42,6 +42,7 @@ std::string const& PowerLimiterClass::getStatusText(PowerLimiterClass::Status st
{ Status::UnconditionalSolarPassthrough, "unconditionally passing through all solar power (MQTT override)" }, { Status::UnconditionalSolarPassthrough, "unconditionally passing through all solar power (MQTT override)" },
{ Status::NoVeDirect, "VE.Direct disabled, connection broken, or data outdated" }, { Status::NoVeDirect, "VE.Direct disabled, connection broken, or data outdated" },
{ Status::Settling, "waiting for the system to settle" }, { Status::Settling, "waiting for the system to settle" },
{ Status::Stable, "the system is stable, the last power limit is still valid" },
{ Status::LowerLimitUndercut, "calculated power limit undercuts configured lower limit" } { Status::LowerLimitUndercut, "calculated power limit undercuts configured lower limit" }
}; };
@ -184,6 +185,12 @@ void PowerLimiterClass::loop()
return announceStatus(Status::PowerMeterPending); return announceStatus(Status::PowerMeterPending);
} }
// since _lastCalculation and _calculationBackoffMs are initialized to
// zero, this test is passed the first time the condition is checked.
if (millis() < (_lastCalculation + _calculationBackoffMs)) {
return announceStatus(Status::Stable);
}
#ifdef POWER_LIMITER_DEBUG #ifdef POWER_LIMITER_DEBUG
MessageOutput.println("[PowerLimiterClass::loop] ******************* ENTER **********************"); MessageOutput.println("[PowerLimiterClass::loop] ******************* ENTER **********************");
#endif #endif
@ -248,7 +255,7 @@ void PowerLimiterClass::loop()
} }
// Calculate and set Power Limit // Calculate and set Power Limit
int32_t newPowerLimit = calcPowerLimit(_inverter, canUseDirectSolarPower(), _batteryDischargeEnabled); int32_t newPowerLimit = calcPowerLimit(_inverter, canUseDirectSolarPower(), _batteryDischargeEnabled);
setNewPowerLimit(_inverter, newPowerLimit); bool limitUpdated = setNewPowerLimit(_inverter, newPowerLimit);
#ifdef POWER_LIMITER_DEBUG #ifdef POWER_LIMITER_DEBUG
MessageOutput.printf("[PowerLimiterClass::loop] Status: SolarPT enabled %i, Drain Strategy: %i, canUseDirectSolarPower: %i, Batt discharge: %i\r\n", MessageOutput.printf("[PowerLimiterClass::loop] Status: SolarPT enabled %i, Drain Strategy: %i, canUseDirectSolarPower: %i, Batt discharge: %i\r\n",
config.PowerLimiter_SolarPassThroughEnabled, config.PowerLimiter_BatteryDrainStategy, canUseDirectSolarPower(), _batteryDischargeEnabled); config.PowerLimiter_SolarPassThroughEnabled, config.PowerLimiter_BatteryDrainStategy, canUseDirectSolarPower(), _batteryDischargeEnabled);
@ -258,6 +265,16 @@ void PowerLimiterClass::loop()
config.Battery_Enabled, Battery.stateOfCharge, config.PowerLimiter_BatterySocStartThreshold, config.PowerLimiter_BatterySocStopThreshold, millis() - Battery.stateOfChargeLastUpdate); config.Battery_Enabled, Battery.stateOfCharge, config.PowerLimiter_BatterySocStartThreshold, config.PowerLimiter_BatterySocStopThreshold, millis() - Battery.stateOfChargeLastUpdate);
MessageOutput.printf("[PowerLimiterClass::loop] ******************* Leaving PL, PL set to: %i, SP: %i, Batt: %i, PM: %f\r\n", newPowerLimit, canUseDirectSolarPower(), _batteryDischargeEnabled, round(PowerMeter.getPowerTotal())); MessageOutput.printf("[PowerLimiterClass::loop] ******************* Leaving PL, PL set to: %i, SP: %i, Batt: %i, PM: %f\r\n", newPowerLimit, canUseDirectSolarPower(), _batteryDischargeEnabled, round(PowerMeter.getPowerTotal()));
#endif #endif
_lastCalculation = millis();
if (!limitUpdated) {
// increase polling backoff if system seems to be stable
_calculationBackoffMs = std::min<uint32_t>(1024, _calculationBackoffMs * 2);
return announceStatus(Status::Stable);
}
_calculationBackoffMs = 128;
} }
/** /**
@ -433,15 +450,17 @@ void PowerLimiterClass::commitPowerLimit(std::shared_ptr<InverterAbstract> inver
/** /**
* enforces limits and a hystersis on the requested power limit, after scaling * enforces limits and a hystersis on the requested power limit, after scaling
* the power limit to the ratio of total and producing inverter channels. * the power limit to the ratio of total and producing inverter channels.
* commits the sanitized power limit. * commits the sanitized power limit. returns true if a limit update was
* committed, false otherwise.
*/ */
void PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit) bool PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit)
{ {
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
// Stop the inverter if limit is below threshold. // Stop the inverter if limit is below threshold.
if (newPowerLimit < config.PowerLimiter_LowerPowerLimit) { if (newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
return shutdown(Status::LowerLimitUndercut); shutdown(Status::LowerLimitUndercut);
return true;
} }
// enforce configured upper power limit // enforce configured upper power limit
@ -473,13 +492,14 @@ void PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inver
if ( diff < config.PowerLimiter_TargetPowerConsumptionHysteresis) { if ( diff < config.PowerLimiter_TargetPowerConsumptionHysteresis) {
MessageOutput.printf("[PowerLimiterClass::setNewPowerLimit] reusing old limit: %d W, diff: %d, hysteresis: %d\r\n", MessageOutput.printf("[PowerLimiterClass::setNewPowerLimit] reusing old limit: %d W, diff: %d, hysteresis: %d\r\n",
_lastRequestedPowerLimit, diff, config.PowerLimiter_TargetPowerConsumptionHysteresis); _lastRequestedPowerLimit, diff, config.PowerLimiter_TargetPowerConsumptionHysteresis);
return; return false;
} }
MessageOutput.printf("[PowerLimiterClass::setNewPowerLimit] using new limit: %d W, requested power limit: %d\r\n", MessageOutput.printf("[PowerLimiterClass::setNewPowerLimit] using new limit: %d W, requested power limit: %d\r\n",
effPowerLimit, newPowerLimit); effPowerLimit, newPowerLimit);
commitPowerLimit(inverter, effPowerLimit, true); commitPowerLimit(inverter, effPowerLimit, true);
return true;
} }
int32_t PowerLimiterClass::getSolarChargePower() int32_t PowerLimiterClass::getSolarChargePower()