DPL: check more requirements and fix backoff initialization (#290)

* DPL: wait for valid time information

we know that the Hoymiles library refuses to send any message to any
inverter until the system has valid time information. until then we can
do nothing, not even shutdown the inverter.

* DPL: wait for device info to be ready

a calculated power limit will always be limited to the reported
device's max power. that upper limit is only known after the first
DevInfoSimpleCommand succeeded. wait for that information to be
available.

* DPL: fix initial calculcation backoff

if the calculation backoff is initialized to zero, the backoff will be
doubled to zero until a new, different power limit was calculated for
the first time. this lead to the DPL recalculating a power limit
hundreds of times without a backoff after startup.
This commit is contained in:
Bernhard Kirchen 2023-07-04 12:05:10 +02:00 committed by GitHub
parent e457ab73f9
commit 107182f948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 2 deletions

View File

@ -28,6 +28,7 @@ public:
Initializing,
DisabledByConfig,
DisabledByMqtt,
WaitingForValidTimestamp,
PowerMeterDisabled,
PowerMeterTimeout,
PowerMeterPending,
@ -37,6 +38,7 @@ public:
InverterCommandsDisabled,
InverterLimitPending,
InverterPowerCmdPending,
InverterDevInfoPending,
InverterStatsPending,
UnconditionalSolarPassthrough,
NoVeDirect,
@ -59,7 +61,8 @@ private:
Status _lastStatus = Status::Initializing;
uint32_t _lastStatusPrinted = 0;
uint32_t _lastCalculation = 0;
uint32_t _calculationBackoffMs = 0;
static constexpr uint32_t _calculationBackoffMsDefault = 128;
uint32_t _calculationBackoffMs = _calculationBackoffMsDefault;
uint8_t _mode = PL_MODE_ENABLE_NORMAL_OP;
std::shared_ptr<InverterAbstract> _inverter = nullptr;
bool _batteryDischargeEnabled = false;

View File

@ -30,6 +30,7 @@ std::string const& PowerLimiterClass::getStatusText(PowerLimiterClass::Status st
{ Status::Initializing, "initializing (should not see me)" },
{ Status::DisabledByConfig, "disabled by configuration" },
{ Status::DisabledByMqtt, "disabled by MQTT" },
{ Status::WaitingForValidTimestamp, "waiting for valid date and time to be available" },
{ Status::PowerMeterDisabled, "no power meter is configured/enabled" },
{ Status::PowerMeterTimeout, "power meter readings are outdated" },
{ Status::PowerMeterPending, "waiting for sufficiently recent power meter reading" },
@ -39,6 +40,7 @@ std::string const& PowerLimiterClass::getStatusText(PowerLimiterClass::Status st
{ Status::InverterCommandsDisabled, "inverter configuration prohibits sending commands" },
{ Status::InverterLimitPending, "waiting for a power limit command to complete" },
{ Status::InverterPowerCmdPending, "waiting for a start/stop/restart command to complete" },
{ Status::InverterDevInfoPending, "waiting for inverter device information to be available" },
{ Status::InverterStatsPending, "waiting for sufficiently recent inverter data" },
{ Status::UnconditionalSolarPassthrough, "unconditionally passing through all solar power (MQTT override)" },
{ Status::NoVeDirect, "VE.Direct disabled, connection broken, or data outdated" },
@ -97,6 +99,14 @@ void PowerLimiterClass::loop()
{
CONFIG_T& config = Configuration.get();
// we know that the Hoymiles library refuses to send any message to any
// inverter until the system has valid time information. until then we can
// do nothing, not even shutdown the inverter.
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 5)) {
return announceStatus(Status::WaitingForValidTimestamp);
}
if (_shutdownInProgress) {
// we transition from SHUTDOWN to OFF when we know the inverter was
// shut down. until then, we retry shutting it down. in this case we
@ -152,6 +162,13 @@ void PowerLimiterClass::loop()
return announceStatus(Status::InverterPowerCmdPending);
}
// a calculated power limit will always be limited to the reported
// device's max power. that upper limit is only known after the first
// DevInfoSimpleCommand succeeded.
if (_inverter->DevInfo()->getMaxPower() <= 0) {
return announceStatus(Status::InverterDevInfoPending);
}
if (PL_MODE_SOLAR_PT_ONLY == _mode) {
// handle this mode of operation separately
return unconditionalSolarPassthrough(_inverter);
@ -275,7 +292,7 @@ void PowerLimiterClass::loop()
return announceStatus(Status::Stable);
}
_calculationBackoffMs = 128;
_calculationBackoffMs = _calculationBackoffMsDefault;
}
/**