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
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ struct POWERLIMITER_CONFIG_T {
bool SolarPassThroughEnabled;
uint8_t ConductionLosses;
bool BatteryAlwaysUseAtNight;
bool BatteryPrioritizeCharge;
int16_t TargetPowerConsumption;
uint16_t TargetPowerConsumptionHysteresis;
uint16_t BaseLoadLimit;
Expand Down
1 change: 1 addition & 0 deletions include/PowerLimiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class PowerLimiterClass {
std::deque<std::unique_ptr<PowerLimiterInverter>> _retirees;
bool _batteryDischargeEnabled = false;
bool _nighttimeDischarging = false;
bool _daytimeDischargingLimited = false;
std::pair<bool, uint32_t> _nextInverterRestart = { false, 0 };
bool _fullSolarPassThroughActive = false;
float _loadCorrectedVoltage = 0.0f;
Expand Down
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
#define POWERLIMITER_SOLAR_PASSTHROUGH_ENABLED false
#define POWERLIMITER_CONDUCTION_LOSSES 3
#define POWERLIMITER_BATTERY_ALWAYS_USE_AT_NIGHT false
#define POWERLIMITER_BATTERY_PRIORITIZE_CHARGE false
#define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true
#define POWERLIMITER_USE_OVERSCALING false
#define POWERLIMITER_INVERTER_CHANNEL_ID 0
Expand Down
2 changes: 2 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ void ConfigurationClass::serializePowerLimiterConfig(PowerLimiterConfig const& s
target["solar_passthrough_enabled"] = source.SolarPassThroughEnabled;
target["conduction_losses"] = source.ConductionLosses;
target["battery_always_use_at_night"] = source.BatteryAlwaysUseAtNight;
target["battery_prioritize_charge"] = source.BatteryPrioritizeCharge;
target["target_power_consumption"] = source.TargetPowerConsumption;
target["target_power_consumption_hysteresis"] = source.TargetPowerConsumptionHysteresis;
target["base_load_limit"] = source.BaseLoadLimit;
Expand Down Expand Up @@ -590,6 +591,7 @@ void ConfigurationClass::deserializePowerLimiterConfig(JsonObject const& source,
target.SolarPassThroughEnabled = source["solar_passthrough_enabled"] | POWERLIMITER_SOLAR_PASSTHROUGH_ENABLED;
target.ConductionLosses = source["conduction_losses"] | POWERLIMITER_CONDUCTION_LOSSES;
target.BatteryAlwaysUseAtNight = source["battery_always_use_at_night"] | POWERLIMITER_BATTERY_ALWAYS_USE_AT_NIGHT;
target.BatteryPrioritizeCharge = source["battery_prioritize_charge"] | POWERLIMITER_BATTERY_PRIORITIZE_CHARGE;
target.TargetPowerConsumption = source["target_power_consumption"] | POWERLIMITER_TARGET_POWER_CONSUMPTION;
target.TargetPowerConsumptionHysteresis = source["target_power_consumption_hysteresis"] | POWERLIMITER_TARGET_POWER_CONSUMPTION_HYSTERESIS;
target.BaseLoadLimit = source["base_load_limit"] | POWERLIMITER_BASE_LOAD_LIMIT;
Expand Down
38 changes: 34 additions & 4 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,36 @@ void PowerLimiterClass::loop()

auto isDayPeriod = SunPosition.isDayPeriod();

if (_nighttimeDischarging && isDayPeriod) {
_nighttimeDischarging = false;
return isStartThresholdReached();
// Unify _nighttimeDischarging & _daytimeDischargingLimited:
//
// if it's day
// if _nighttimeDischarging, turn that off & return isStartThresholdReached()
// if !_daytimeDischargingLimited, turn that on, maybe log and return isStartThresholdReached(),
// else
// turn daytimeDischargingLimited off
if (isDayPeriod) {
if (_nighttimeDischarging) {
_nighttimeDischarging = false;
if (_verboseLogging) {
MessageOutput.printf("[DPL] it is now daytime, %sstopping nightly discharge because %s\r\n",
isStartThresholdReached()?"not ":"",
isStartThresholdReached()?"battery is charged enough":"charge is prioritized");
}
return isStartThresholdReached();
}
if (config.PowerLimiter.BatteryPrioritizeCharge) {
if (!_daytimeDischargingLimited) {
_daytimeDischargingLimited = true;
if (_verboseLogging) {
MessageOutput.printf("[DPL] it is now daytime, %sstopping any discharge because %s\r\n",
isStartThresholdReached()?"not ":"",
isStartThresholdReached()?"battery is charged enough":"charge is prioritized");
}
return isStartThresholdReached();
}
}
} else {
_daytimeDischargingLimited = false;
}

if (isStopThresholdReached()) { return false; }
Expand Down Expand Up @@ -343,10 +370,13 @@ void PowerLimiterClass::loop()
config.PowerLimiter.FullSolarPassThroughStopVoltage);
}

MessageOutput.printf("[DPL] start %sreached, stop %sreached, solar-passthrough %sabled, use at night %sabled and %s\r\n",
MessageOutput.printf("[DPL] start %sreached, stop %sreached, solar-passthrough %sabled, " \
"prioritize battery charge %sabled and %s, use at night %sabled and %s\r\n",
(isStartThresholdReached()?"":"NOT "),
(isStopThresholdReached()?"":"NOT "),
(isSolarPassThroughEnabled()?"en":"dis"),
(config.PowerLimiter.BatteryPrioritizeCharge?"en":"dis"),
(_daytimeDischargingLimited?"active":"dormant"),
(config.PowerLimiter.BatteryAlwaysUseAtNight?"en":"dis"),
(_nighttimeDischarging?"active":"dormant"));

Expand Down
2 changes: 2 additions & 0 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,8 @@
"ConductionLossesInfo": "Bei der Übertragung von Energie vom Solarladeregler oder der Batterie zum Inverter sind Leitungsverluste zu erwarten. Diese Verluste werden berücksichtigt, um besser geeignete Wechselrichterlimits zu errechnen.",
"BatteryDischargeAtNight": "Batterie nachts sogar teilweise geladen nutzen",
"BatteryDischargeAtNightHint": "Ermöglicht das Entladen der Batterie in der Nacht, auch wenn der Start-Schwellwert nicht erreicht wurde. Das Entladen stoppt bei Sonnenaufgang, oder sobald der Stop-Schwellwert erreicht wurde.",
"BatteryPrioritizeCharge": "Bei Sonnenaufgang ggf. Entladezyklus beenden",
"BatteryPrioritizeChargeHint": "Sollte der Start-Schwellwert bei Sonnenaufgang unterschritten sein, wird ein Entladezyklus beendet. Das Entladen wird wieder aufgenommen, solabd der Start-Schwellwert erreicht wurde.",
Copy link

Copilot AI May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the German locale: 'solabd' should be corrected to 'sobald'.

Suggested change
"BatteryPrioritizeChargeHint": "Sollte der Start-Schwellwert bei Sonnenaufgang unterschritten sein, wird ein Entladezyklus beendet. Das Entladen wird wieder aufgenommen, solabd der Start-Schwellwert erreicht wurde.",
"BatteryPrioritizeChargeHint": "Sollte der Start-Schwellwert bei Sonnenaufgang unterschritten sein, wird ein Entladezyklus beendet. Das Entladen wird wieder aufgenommen, sobald der Start-Schwellwert erreicht wurde.",

Copilot uses AI. Check for mistakes.
"SolarPassthroughInfo": "Solar-Passthrough ermöglicht den unmittelbaren Verbrauch der verfügbaren Solarleistung. Dazu wird die aktuell vom Laderegler gemeldete Solarleistung als Sollwert für die Wechselrichtergesamtleistung angenommen, selbst wenn sich die Batterie in einem Ladezyklus befindet. Somit wird eine unnötige verlustbehaftete Speicherung der Energie umgangen.",
"DcPowerBusSettings": "Einstellungen DC-Stromschiene",
"SelectInverter": "Inverter auswählen...",
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,8 @@
"ConductionLossesInfo": "Conduction losses are to be expected when transferring energy from the solar charge controller or from the battery to the inverter. These losses are taken into account to calculate better suited inverter limits.",
"BatteryDischargeAtNight": "Use battery at night even if only partially charged",
"BatteryDischargeAtNightHint": "Allows the battery to be discharged at night even if it hasn't reached the Start Threshold. Discharging continues until sunrise or until the Stop Threshold is reached.",
"BatteryPrioritizeCharge": "Prioritize charging of the battery at day",
Copy link

Copilot AI May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider rephrasing the English label to "Prioritize battery charging during the day" for clearer communication of the intended functionality.

Suggested change
"BatteryPrioritizeCharge": "Prioritize charging of the battery at day",
"BatteryPrioritizeCharge": "Prioritize battery charging during the day",

Copilot uses AI. Check for mistakes.
"BatteryPrioritizeChargeHint": "Stops a discharge cycle if the Start Threshold isn't reached at sunrise. Discharging will start again when the Start Threshold is reached.",
"SolarPassthroughInfo": "Solar-Passthrough enables the immediate consumption of the available solar power. For this purpose, the solar power currently reported by the charge controller is assumed as the inverters' output power target, even if the battery is in a charge cycle. This avoids unnecessary lossy energy storage.",
"DcPowerBusSettings": "DC Power Bus Settings",
"SelectInverter": "Select an inverter...",
Expand Down
3 changes: 3 additions & 0 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,9 @@
"ConductionLosses": "Conduction Losses",
"ConductionLossesInfo": "Conduction losses are to be expected when transferring energy from the solar charge controller or from the battery to the inverter. These losses are taken into account to calculate better suited inverter limits.",
"BatteryDischargeAtNight": "Use battery at night even if only partially charged",
"BatteryDischargeAtNightHint": "Allows the battery to be discharged at night even if it hasn't reached the Start Threshold. Discharging continues until sunrise or until the Stop Threshold is reached.",
"BatteryPrioritizeCharge": "Prioritize charging of the battery at day",
"BatteryPrioritizeChargeHint": "Stops a discharge cycle if the Start Threshold isn't reached at sunrise. Discharging will start again when the Start Threshold is reached.",
"SolarPassthroughInfo": "Solar-Passthrough enables the immediate consumption of the available solar power. For this purpose, the solar power currently reported by the charge controller is assumed as the inverters' output power target, even if the battery is in a charge cycle. This avoids unnecessary lossy energy storage.",
"DcPowerBusSettings": "DC Power Bus Settings",
"SelectInverter": "Select an inverter...",
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 @@ -38,6 +38,7 @@ export interface PowerLimiterConfig {
solar_passthrough_enabled: boolean;
conduction_losses: number;
battery_always_use_at_night: boolean;
battery_prioritize_charge: boolean;
target_power_consumption: number;
target_power_consumption_hysteresis: number;
base_load_limit: number;
Expand Down
8 changes: 8 additions & 0 deletions webapp/src/views/PowerLimiterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@
type="checkbox"
wide
/>

<InputElement
:label="$t('powerlimiteradmin.BatteryPrioritizeCharge')"
:tooltip="$t('powerlimiteradmin.BatteryPrioritizeChargeHint')"
v-model="powerLimiterConfigList.battery_prioritize_charge"
type="checkbox"
wide
/>

<div class="row mb-3">
<label for="inverter_serial_for_dc_voltage" class="col-sm-4 col-form-label">
Expand Down