Skip to content

Commit

Permalink
refactor state machine
Browse files Browse the repository at this point in the history
merging
  • Loading branch information
MalteSchm committed Apr 13, 2023
1 parent ee82c8c commit 9999fa2
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 92 deletions.
8 changes: 3 additions & 5 deletions include/PowerLimiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
#include <memory>

typedef enum {
STATE_DISCOVER = 0,
STATE_OFF,
STATE_CONSUME_SOLAR_POWER_ONLY,
STATE_NORMAL_OPERATION
STATE_PL_SHUTDOWN = 0,
STATE_ACTIVE
} plStates;

typedef enum {
Expand All @@ -34,7 +32,7 @@ class PowerLimiterClass {
uint32_t _lastLoop = 0;
int32_t _lastRequestedPowerLimit = 0;
uint32_t _lastLimitSetTime = 0;
plStates _plState = STATE_DISCOVER;
plStates _plState = STATE_ACTIVE;
bool _disabled = false;

float _powerMeter1Power;
Expand Down
136 changes: 49 additions & 87 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,46 @@ void PowerLimiterClass::init()
void PowerLimiterClass::loop()
{
CONFIG_T& config = Configuration.get();

if (!config.PowerLimiter_Enabled
|| _disabled
|| !config.PowerMeter_Enabled

// Run inital checks to make sure we have met the basic conditions
if ( !config.PowerMeter_Enabled
|| !Hoymiles.getRadio()->isIdle()
|| (millis() - _lastCommandSent) < (config.PowerLimiter_Interval * 1000)
|| (millis() - _lastLoop) < (config.PowerLimiter_Interval * 1000)) {
if (!config.PowerLimiter_Enabled
|| _disabled)
_plState = STATE_DISCOVER; // ensure STATE_DISCOVER is set, if PowerLimiter will be enabled.
return;
}

_lastLoop = millis();

// Debug state transistions


MessageOutput.printf("****************** PL STATE: %i\r\n", _plState);

std::shared_ptr<InverterAbstract> inverter = Hoymiles.getInverterByPos(config.PowerLimiter_InverterId);
if (inverter == nullptr || !inverter->isReachable()) {
return;
}

// Make sure inverter is turned off if PL is disabled by user
// Make sure inverter is turned off when lower battery threshold is reached
// In this case we willbe in some state and want to reach STATE_PL_SHUTDOWN
if ((!config.PowerLimiter_Enabled && _plState != STATE_PL_SHUTDOWN)
|| isStopThresholdReached(inverter)) {
if (inverter->isProducing()) {
MessageOutput.printf("PL initiated inverter shutdown.\r\n");
inverter->sendPowerControlRequest(Hoymiles.getRadio(), false);
} else {
_plState = STATE_PL_SHUTDOWN;
}
return;
}

// PL is disabled
if (!config.PowerLimiter_Enabled) {
return;
}

float dcVoltage = inverter->Statistics()->getChannelFieldValue(TYPE_DC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_UDC);
float acPower = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_PAC);
float correctedDcVoltage = dcVoltage + (acPower * config.PowerLimiter_VoltageLoadCorrectionFactor);
Expand All @@ -61,87 +81,26 @@ void PowerLimiterClass::loop()
dcVoltage, config.PowerLimiter_VoltageStartThreshold, config.PowerLimiter_VoltageStopThreshold, inverter->isProducing());
}

while(true) {
switch(_plState) {
case STATE_DISCOVER:
if (!inverter->isProducing() || isStopThresholdReached(inverter)) {
_plState = STATE_OFF;
}
else if (canUseDirectSolarPower()) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY;
}
else {
_plState = STATE_NORMAL_OPERATION;
}
break;
case STATE_OFF:
// if on turn off
if (inverter->isProducing()) {
MessageOutput.printf("[PowerLimiterClass::loop] DC voltage: %.2f Corrected DC voltage: %.2f...\r\n",
dcVoltage, correctedDcVoltage);
setNewPowerLimit(inverter, -1);
return;
}

// do nothing if battery is empty
if (isStopThresholdReached(inverter))
return;
// check for possible state changes
if (canUseDirectSolarPower()) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY;
}
if (isStartThresholdReached(inverter)) {
_plState = STATE_NORMAL_OPERATION;
}
return;
break;
case STATE_CONSUME_SOLAR_POWER_ONLY: {
int32_t newPowerLimit = calcPowerLimit(inverter, true);
if (isStopThresholdReached(inverter)) {
_plState = STATE_OFF;
break;
}
if (isStartThresholdReached(inverter)) {
_plState = STATE_NORMAL_OPERATION;
break;
}

if (!canUseDirectSolarPower()) {
if (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGHT)
_plState = STATE_NORMAL_OPERATION;
else
_plState = STATE_OFF;
break;
}

setNewPowerLimit(inverter, newPowerLimit);
return;
break;
}
case STATE_NORMAL_OPERATION: {
int32_t newPowerLimit = calcPowerLimit(inverter, false);
if (isStopThresholdReached(inverter)) {
_plState = STATE_OFF;
break;
}
if (!isStartThresholdReached(inverter) && canUseDirectSolarPower() && (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGHT)) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY;
break;
}

// check if grid power consumption is not within the upper and lower threshold of the target consumption
if (newPowerLimit >= (config.PowerLimiter_TargetPowerConsumption - config.PowerLimiter_TargetPowerConsumptionHysteresis) &&
newPowerLimit <= (config.PowerLimiter_TargetPowerConsumption + config.PowerLimiter_TargetPowerConsumptionHysteresis) &&
_lastRequestedPowerLimit >= (config.PowerLimiter_TargetPowerConsumption - config.PowerLimiter_TargetPowerConsumptionHysteresis) &&
_lastRequestedPowerLimit <= (config.PowerLimiter_TargetPowerConsumption + config.PowerLimiter_TargetPowerConsumptionHysteresis) ) {
return;
}
setNewPowerLimit(inverter, newPowerLimit);;
return;
break;
}
}
// Check if we need to move state away from STATE_PL_SHUTDOWN
if (_plState == STATE_PL_SHUTDOWN) {

// Allow discharge when start threshold reached
// This is also the trigger for drain strategy: EMPTY_WHEN_FULL
if (isStartThresholdReached(inverter)) {
_plState = STATE_ACTIVE;
}

// Allow discharge when drain strategy is EMPTY_AT_NIGHT
if (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGHT) {
_plState = STATE_ACTIVE;
}

return;
}

int32_t newPowerLimit = calcPowerLimit(inverter, canUseDirectSolarPower());
MessageOutput.printf("****************************** Powerlimit: %i\r\n", newPowerLimit);
setNewPowerLimit(inverter, newPowerLimit);
}

plStates PowerLimiterClass::getPowerLimiterState() {
Expand Down Expand Up @@ -177,6 +136,9 @@ bool PowerLimiterClass::canUseDirectSolarPower()
return true;
}




int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool consumeSolarPowerOnly)
{
CONFIG_T& config = Configuration.get();
Expand Down

0 comments on commit 9999fa2

Please sign in to comment.