Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ struct POWERLIMITER_INVERTER_CONFIG_T {

enum InverterPowerSource { Battery = 0, Solar = 1, SmartBuffer = 2 };
InverterPowerSource PowerSource;

bool HasPriority;
};
using PowerLimiterInverterConfig = struct POWERLIMITER_INVERTER_CONFIG_T;

Expand Down
2 changes: 2 additions & 0 deletions include/PowerLimiterInverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class PowerLimiterInverter {
bool isSolarPowered() const { return _config.PowerSource == PowerLimiterInverterConfig::InverterPowerSource::Solar; }
bool isSmartBufferPowered() const { return _config.PowerSource == PowerLimiterInverterConfig::InverterPowerSource::SmartBuffer; }

bool hasPriority() const { return _config.HasPriority; }

void debug() const;

enum class Eligibility : unsigned {
Expand Down
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_SOC 100
#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_START_VOLTAGE 66.0
#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_STOP_VOLTAGE 66.0
#define POWERLIMITER_HAS_PRIORITY false

#define BATTERY_ENABLED false
#define BATTERY_PROVIDER 0 // Pylontech CAN receiver
Expand Down
5 changes: 5 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ void ConfigurationClass::serializePowerLimiterConfig(PowerLimiterConfig const& s
t["allow_standby"] = s.AllowStandby;
t["lower_power_limit"] = s.LowerPowerLimit;
t["upper_power_limit"] = s.UpperPowerLimit;
t["has_priority"] = s.HasPriority;
}
}

Expand Down Expand Up @@ -645,6 +646,7 @@ void ConfigurationClass::deserializePowerLimiterConfig(JsonObject const& source,
inv.AllowStandby = s["allow_standby"] | POWERLIMITER_ALLOW_STANDBY;
inv.LowerPowerLimit = s["lower_power_limit"] | POWERLIMITER_LOWER_POWER_LIMIT;
inv.UpperPowerLimit = s["upper_power_limit"] | POWERLIMITER_UPPER_POWER_LIMIT;
inv.HasPriority = s["has_priority"] | POWERLIMITER_HAS_PRIORITY;
}
}

Expand Down Expand Up @@ -1102,6 +1104,9 @@ void ConfigurationClass::migrateOnBattery()
inv.LowerPowerLimit = powerlimiter["lower_power_limit"] | POWERLIMITER_LOWER_POWER_LIMIT;
inv.UpperPowerLimit = powerlimiter["upper_power_limit"] | POWERLIMITER_UPPER_POWER_LIMIT;

inv.HasPriority = powerlimiter["has_priority"] | POWERLIMITER_HAS_PRIORITY;


config.PowerLimiter.TotalUpperPowerLimit = inv.UpperPowerLimit;

config.PowerLimiter.Inverters[1].Serial = 0;
Expand Down
25 changes: 18 additions & 7 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@ static auto sSolarPoweredFilter = [](PowerLimiterInverter const& inv) {

static const char sSolarPoweredExpression[] = "solar-powered";

static auto sSmartBufferPoweredFilter = [](PowerLimiterInverter const& inv) {
return inv.isSmartBufferPowered();
static auto sSecondarySmartBufferPoweredFilter = [](PowerLimiterInverter const& inv) {
return inv.isSmartBufferPowered() && !inv.hasPriority();
};

static const char sSmartBufferPoweredExpression[] = "smart-buffer-powered";
static const char sSecondarySmartBufferPoweredExpression[] = "secondary-smart-buffer-powered";

static auto sPrimarySmartBufferPoweredFilter = [](PowerLimiterInverter const& inv) {
return inv.isSmartBufferPowered() && inv.hasPriority();
};

static const char sPrimarySmartBufferPoweredExpression[] = "primary-smart-buffer-powered";

PowerLimiterClass PowerLimiter;

Expand Down Expand Up @@ -359,14 +365,19 @@ void PowerLimiterClass::loop()

auto coveredBySolar = updateInverterLimits(inverterTotalPower, sSolarPoweredFilter, sSolarPoweredExpression);
auto remainingAfterSolar = (inverterTotalPower >= coveredBySolar) ? inverterTotalPower - coveredBySolar : 0;
auto coveredBySmartBuffer = updateInverterLimits(remainingAfterSolar, sSmartBufferPoweredFilter, sSmartBufferPoweredExpression);
auto remainingAfterSmartBuffer = (remainingAfterSolar >= coveredBySmartBuffer) ? remainingAfterSolar - coveredBySmartBuffer : 0;
auto powerBusUsage = calcPowerBusUsage(remainingAfterSmartBuffer);

auto coveredByPrimarySmartBuffer = updateInverterLimits(remainingAfterSolar, sPrimarySmartBufferPoweredFilter, sPrimarySmartBufferPoweredExpression);
auto remainingAfterPrimarySmartBuffer = (remainingAfterSolar >= coveredByPrimarySmartBuffer) ? remainingAfterSolar - coveredByPrimarySmartBuffer : 0;

auto coveredBySecondarySmartBuffer = updateInverterLimits(remainingAfterPrimarySmartBuffer, sSecondarySmartBufferPoweredFilter, sSecondarySmartBufferPoweredExpression);
auto remainingAfterSecondarySmartBuffer = (remainingAfterPrimarySmartBuffer >= coveredBySecondarySmartBuffer) ? remainingAfterPrimarySmartBuffer - coveredBySecondarySmartBuffer : 0;

auto powerBusUsage = calcPowerBusUsage(remainingAfterSecondarySmartBuffer);
auto coveredByBattery = updateInverterLimits(powerBusUsage, sBatteryPoweredFilter, sBatteryPoweredExpression);

for (auto const &upInv : _inverters) { upInv->debug(); }

_lastExpectedInverterOutput = coveredBySolar + coveredBySmartBuffer + coveredByBattery;
_lastExpectedInverterOutput = coveredBySolar + coveredByPrimarySmartBuffer + coveredBySecondarySmartBuffer + coveredByBattery;

bool limitUpdated = updateInverters();

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 @@ -749,7 +749,9 @@
"VoltageThresholds": "Batterie Spannungs-Schwellwerte ",
"VoltageLoadCorrectionInfo": "<b>Hinweis:</b> Wenn Leistung von der Batterie abgegeben wird, bricht ihre Spannung etwas ein. Der Spannungseinbruch skaliert mit dem Entladestrom. Damit Wechselrichter nicht vorzeitig ausgeschaltet werden sobald der Stop-Schwellenwert unterschritten wurde, wird der hier angegebene Korrekturfaktor mit einberechnet, um die Spannung zu errechnen, die der Akku in Ruhe hätte. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) * Korrekturfaktor).",
"InverterRestartHour": "Uhrzeit für automatischen Wechselrichterneustart",
"InverterRestartHint": "Der Wechselrichter wird täglich zur gewünschten Zeit automatisch neu gestartet. Dies ist notwendig, da sich die Wechselrichter möglicherweise unerwartet verhalten, wenn sie nicht neu gestartet oder längere Zeit (Tage/Wochen/Monate) am Stück in Betrieb sind, und um den täglichen Ertrag zurückzusetzen."
"InverterRestartHint": "Der Wechselrichter wird täglich zur gewünschten Zeit automatisch neu gestartet. Dies ist notwendig, da sich die Wechselrichter möglicherweise unerwartet verhalten, wenn sie nicht neu gestartet oder längere Zeit (Tage/Wochen/Monate) am Stück in Betrieb sind, und um den täglichen Ertrag zurückzusetzen.",
"HasPriority": "Wechselrichter priorisieren",
"HasPriorityHint": "Nutze diesen Wechselrichter mit höherer Priorität als andere Smart Buffer Batterie Wechselrichter. Hilfreich, wenn mehrere Smart Buffer Batterien mit unterschiedlicher Solarleistung oder Batteriekapazität verwendet werden."
},
"batteryadmin": {
"BatterySettings": "Batterie Einstellungen",
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 @@ -749,7 +749,9 @@
"VoltageThresholds": "Battery Voltage Thresholds",
"VoltageLoadCorrectionInfo": "<b>Hint:</b> When the battery is discharged, its voltage drops. The voltage drop scales with the discharge current. In order to not stop inverters too early (stop threshold), this load correction factor can be specified to calculate the battery voltage if it was idle. Corrected voltage = DC Voltage + (Current power * correction factor).",
"InverterRestartHour": "Automatic Inverter Restart Time",
"InverterRestartHint": "The inverter(s) will be automatically restarted daily at the desired time. This is necessary because the inverter may behave unexpectedly if not restarted and powered continuously for days/weeks/months. A restart is also required to reset the daily yield."
"InverterRestartHint": "The inverter(s) will be automatically restarted daily at the desired time. This is necessary because the inverter may behave unexpectedly if not restarted and powered continuously for days/weeks/months. A restart is also required to reset the daily yield.",
"HasPriority": "Prioritize Inverter",
"HasPriorityHint": "Prioritize this inverter over other smart buffer powerd inverters. This may be useful if multiple smart buffer powered inverters with different solar power or battery capacity are used"
},
"batteryadmin": {
"BatterySettings": "Battery Settings",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/types/PowerLimiterConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface PowerLimiterInverterConfig {
allow_standby: boolean;
lower_power_limit: number;
upper_power_limit: number;
has_priority: boolean;
}

export interface PowerLimiterConfig {
Expand Down
9 changes: 9 additions & 0 deletions webapp/src/views/PowerLimiterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@
wide
/>

<InputElement
v-if="inv.power_source == 2"
:label="$t('powerlimiteradmin.HasPriority')"
v-model="inv.has_priority"
:tooltip="$t('powerlimiteradmin.HasPriorityHint')"
type="checkbox"
wide
/>

<InputElement
:label="$t('powerlimiteradmin.LowerPowerLimit')"
:tooltip="$t('powerlimiteradmin.LowerPowerLimitHint')"
Expand Down