Skip to content

Commit

Permalink
Feature: DPL: add switch allowing to ignore SoC
Browse files Browse the repository at this point in the history
unfortunately, the battery SoC values reported by battery BMSs are
unreliable, at least for some users, or at least without regular
(manual) full charge cycles to calibrate the BMS. it offers great
advantages to connect OpenDTU-OnBattery to a BMS (MQTT publishing of
values, Home Assistent integration, etc.), but previously the users
were then forced to configure the DPL by SoC values.

this change allows to configure the DPL such that SoC values are
ignored. instead, the voltage limits are used to make DPL decisions, as
if no SoC was available in the first place.

the SoC related setting are hidden from the DPL settings view if SoC
values are configured to be ignored.

closes #654.
  • Loading branch information
schlimmchen committed Feb 18, 2024
1 parent b794f46 commit 921302b
Show file tree
Hide file tree
Showing 10 changed files with 30 additions and 18 deletions.
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ struct CONFIG_T {
int32_t TargetPowerConsumptionHysteresis;
int32_t LowerPowerLimit;
int32_t UpperPowerLimit;
bool IgnoreSoc;
uint32_t BatterySocStartThreshold;
uint32_t BatterySocStopThreshold;
float VoltageStartThreshold;
Expand Down
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
#define POWERLIMITER_TARGET_POWER_CONSUMPTION_HYSTERESIS 0
#define POWERLIMITER_LOWER_POWER_LIMIT 10
#define POWERLIMITER_UPPER_POWER_LIMIT 800
#define POWERLIMITER_IGNORE_SOC false
#define POWERLIMITER_BATTERY_SOC_START_THRESHOLD 80
#define POWERLIMITER_BATTERY_SOC_STOP_THRESHOLD 20
#define POWERLIMITER_VOLTAGE_START_THRESHOLD 50.0
Expand Down
2 changes: 2 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ bool ConfigurationClass::write()
powerlimiter["target_power_consumption_hysteresis"] = config.PowerLimiter.TargetPowerConsumptionHysteresis;
powerlimiter["lower_power_limit"] = config.PowerLimiter.LowerPowerLimit;
powerlimiter["upper_power_limit"] = config.PowerLimiter.UpperPowerLimit;
powerlimiter["ignore_soc"] = config.PowerLimiter.IgnoreSoc;
powerlimiter["battery_soc_start_threshold"] = config.PowerLimiter.BatterySocStartThreshold;
powerlimiter["battery_soc_stop_threshold"] = config.PowerLimiter.BatterySocStopThreshold;
powerlimiter["voltage_start_threshold"] = config.PowerLimiter.VoltageStartThreshold;
Expand Down Expand Up @@ -435,6 +436,7 @@ bool ConfigurationClass::read()
config.PowerLimiter.TargetPowerConsumptionHysteresis = powerlimiter["target_power_consumption_hysteresis"] | POWERLIMITER_TARGET_POWER_CONSUMPTION_HYSTERESIS;
config.PowerLimiter.LowerPowerLimit = powerlimiter["lower_power_limit"] | POWERLIMITER_LOWER_POWER_LIMIT;
config.PowerLimiter.UpperPowerLimit = powerlimiter["upper_power_limit"] | POWERLIMITER_UPPER_POWER_LIMIT;
config.PowerLimiter.IgnoreSoc = powerlimiter["ignore_soc"] | POWERLIMITER_IGNORE_SOC;
config.PowerLimiter.BatterySocStartThreshold = powerlimiter["battery_soc_start_threshold"] | POWERLIMITER_BATTERY_SOC_START_THRESHOLD;
config.PowerLimiter.BatterySocStopThreshold = powerlimiter["battery_soc_stop_threshold"] | POWERLIMITER_BATTERY_SOC_STOP_THRESHOLD;
config.PowerLimiter.VoltageStartThreshold = powerlimiter["voltage_start_threshold"] | POWERLIMITER_VOLTAGE_START_THRESHOLD;
Expand Down
11 changes: 7 additions & 4 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,13 @@ void PowerLimiterClass::loop()
}

if (_verboseLogging) {
MessageOutput.printf("[DPL::loop] battery interface %s, SoC: %d %%, StartTH: %d %%, StopTH: %d %%, SoC age: %d s\r\n",
MessageOutput.printf("[DPL::loop] battery interface %s, SoC: %d %%, StartTH: %d %%, StopTH: %d %%, SoC age: %d s, ignore: %s\r\n",
(config.Battery.Enabled?"enabled":"disabled"),
Battery.getStats()->getSoC(),
config.PowerLimiter.BatterySocStartThreshold,
config.PowerLimiter.BatterySocStopThreshold,
Battery.getStats()->getSoCAgeSeconds());
Battery.getStats()->getSoCAgeSeconds(),
(config.PowerLimiter.IgnoreSoc?"yes":"no"));

float dcVoltage = _inverter->Statistics()->getChannelFieldValue(TYPE_DC, (ChannelNum_t)config.PowerLimiter.InverterChannelId, FLD_UDC);
MessageOutput.printf("[DPL::loop] dcVoltage: %.2f V, loadCorrectedVoltage: %.2f V, StartTH: %.2f V, StopTH: %.2f V\r\n",
Expand Down Expand Up @@ -608,8 +609,10 @@ bool PowerLimiterClass::testThreshold(float socThreshold, float voltThreshold,
{
CONFIG_T& config = Configuration.get();

// prefer SoC provided through battery interface
if (config.Battery.Enabled && socThreshold > 0.0
// prefer SoC provided through battery interface, unless disabled by user
if (!config.PowerLimiter.IgnoreSoc
&& config.Battery.Enabled
&& socThreshold > 0.0
&& Battery.getStats()->isValid()
&& Battery.getStats()->getSoCAgeSeconds() < 60) {
return compare(Battery.getStats()->getSoC(), socThreshold);
Expand Down
2 changes: 2 additions & 0 deletions src/WebApi_powerlimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
root["target_power_consumption_hysteresis"] = config.PowerLimiter.TargetPowerConsumptionHysteresis;
root["lower_power_limit"] = config.PowerLimiter.LowerPowerLimit;
root["upper_power_limit"] = config.PowerLimiter.UpperPowerLimit;
root["ignore_soc"] = config.PowerLimiter.IgnoreSoc;
root["battery_soc_start_threshold"] = config.PowerLimiter.BatterySocStartThreshold;
root["battery_soc_stop_threshold"] = config.PowerLimiter.BatterySocStopThreshold;
root["voltage_start_threshold"] = static_cast<int>(config.PowerLimiter.VoltageStartThreshold * 100 +0.5) / 100.0;
Expand Down Expand Up @@ -133,6 +134,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
config.PowerLimiter.TargetPowerConsumptionHysteresis = root["target_power_consumption_hysteresis"].as<int32_t>();
config.PowerLimiter.LowerPowerLimit = root["lower_power_limit"].as<int32_t>();
config.PowerLimiter.UpperPowerLimit = root["upper_power_limit"].as<int32_t>();
config.PowerLimiter.IgnoreSoc = root["ignore_soc"].as<bool>();
config.PowerLimiter.BatterySocStartThreshold = root["battery_soc_start_threshold"].as<uint32_t>();
config.PowerLimiter.BatterySocStopThreshold = root["battery_soc_stop_threshold"].as<uint32_t>();
config.PowerLimiter.VoltageStartThreshold = root["voltage_start_threshold"].as<float>();
Expand Down
5 changes: 3 additions & 2 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -595,17 +595,18 @@
"LowerPowerLimit": "Unteres Leistungslimit",
"UpperPowerLimit": "Oberes Leistungslimit",
"PowerMeters": "Leistungsmesser",
"IgnoreSoc": "Batterie SoC ignorieren",
"BatterySocStartThreshold": "Akku SoC - Start",
"BatterySocStopThreshold": "Akku SoC - Stop",
"BatterySocSolarPassthroughStartThreshold": "Akku SoC - Start solar passthrough",
"BatterySocSolarPassthroughStartThresholdHint": "Wenn der Batterie SOC über diesem Limit ist wird die Inverter Leistung entsprechend der Victron MPPT Leistung gesetzt (abzüglich Effizienzkorrekturfaktor). Kann verwendet werden um überschüssige Solarleistung an das Netz zu liefern wenn die Batterie voll ist.",
"BatterySocSolarPassthroughStartThresholdHint": "Wenn der Batterie SoC über diesem Limit ist wird die Inverter Leistung entsprechend der Victron MPPT Leistung gesetzt (abzüglich Effizienzkorrekturfaktor). Kann verwendet werden um überschüssige Solarleistung an das Netz zu liefern wenn die Batterie voll ist.",
"VoltageStartThreshold": "DC Spannung - Start",
"VoltageStopThreshold": "DC Spannung - Stop",
"VoltageSolarPassthroughStartThreshold": "DC Spannung - Start Solar-Passthrough",
"VoltageSolarPassthroughStopThreshold": "DC Spannung - Stop Solar-Passthrough",
"VoltageSolarPassthroughStartThresholdHint": "Wenn der Batteriespannung über diesem Limit ist wird die Inverter Leistung entsprechend der Victron MPPT Leistung gesetzt (abzüglich Effizienzkorrekturfaktor). Kann verwendet werden um überschüssige Solarleistung an das Netz zu liefern wenn die Batterie voll ist. Dieser Mode wird aktiv wenn das Start Spannungslimit überschritten wird und inaktiv wenn das Stop Spannungslimit unterschritten wird.",
"VoltageLoadCorrectionFactor": "DC Spannung - Lastkorrekturfaktor",
"BatterySocInfo": "<b>Hinweis:</b> Die Akku SoC (State of Charge) Werte können nur benutzt werden, wenn die Batterie-Kommunikationsschnittstelle aktiviert ist. Wenn die Batterie innerhalb der letzten Minute keine Werte geschickt hat, werden als Fallback-Option die Spannungseinstellungen verwendet.",
"BatterySocInfo": "<b>Hinweis:</b> Die Akku SoC (State of Charge) Werte werden nur benutzt, wenn die Batterie-Kommunikationsschnittstelle innerhalb der letzten Minute gültige Werte geschickt hat. Andernfalls werden als Fallback-Option die Spannungseinstellungen verwendet.",
"InverterIsBehindPowerMeter": "Welchselrichter ist hinter Leistungsmesser",
"Battery": "DC / Akku",
"VoltageLoadCorrectionInfo": "<b>Hinweis:</b> Wenn Leistung von der Batterie abgegeben wird, bricht normalerweise die Spannung etwas ein. Damit nicht vorzeitig der Wechelrichter ausgeschaltet wird sobald der \"Stop\"-Schwellenwert erreicht wird, wird der hier angegebene Korrekturfaktor mit einberechnet. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) * Korrekturfaktor).",
Expand Down
6 changes: 2 additions & 4 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -601,9 +601,7 @@
"LowerPowerLimit": "Lower power limit",
"UpperPowerLimit": "Upper power limit",
"PowerMeters": "Power meter",
"MqttTopicPowerMeter1": "MQTT topic - Power meter #1",
"MqttTopicPowerMeter2": "MQTT topic - Power meter #2 (optional)",
"MqttTopicPowerMeter3": "MQTT topic - Power meter #3 (optional)",
"IgnoreSoc": "Ignore Battery SoC",
"BatterySocStartThreshold": "Battery SoC - Start threshold",
"BatterySocStopThreshold": "Battery SoC - Stop threshold",
"BatterySocSolarPassthroughStartThreshold": "Battery SoC - Start threshold for full solar passthrough",
Expand All @@ -614,7 +612,7 @@
"VoltageSolarPassthroughStopThreshold": "DC Voltage - Stop threshold for full solar passthrough",
"VoltageSolarPassthroughStartThresholdHint": "Inverter power is set according to Victron MPPT power (minus efficiency factors) when full solar passthrough is active. Use this if you like to supply excess power to the grid when battery is full. This is started when battery voltage goes over this limit and stopped if voltage drops below stop limit.",
"VoltageLoadCorrectionFactor": "DC Voltage - Load correction factor",
"BatterySocInfo": "<b>Hint:</b> The battery SoC (State of Charge) values can only be used if the battery communication interface is enabled. If the battery has not reported any SoC updates in the last minute, the voltage thresholds will be used as fallback.",
"BatterySocInfo": "<b>Hint:</b> The battery SoC (State of Charge) values are only used if the battery communication interface reported SoC updates in the last minute. Otherwise the voltage thresholds will be used as fallback.",
"InverterIsBehindPowerMeter": "Inverter is behind Power meter",
"Battery": "DC / Battery",
"VoltageLoadCorrectionInfo": "<b>Hint:</b> When the power output is higher, the voltage is usually decreasing. In order to not stop the inverter too early (Stop treshold), a power factor can be specified here to correct this. Corrected voltage = DC Voltage + (Current power * correction factor).",
Expand Down
6 changes: 2 additions & 4 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -648,9 +648,7 @@
"LowerPowerLimit": "Lower power limit",
"UpperPowerLimit": "Upper power limit",
"PowerMeters": "Power meter",
"MqttTopicPowerMeter1": "MQTT topic - Power meter #1",
"MqttTopicPowerMeter2": "MQTT topic - Power meter #2 (optional)",
"MqttTopicPowerMeter3": "MQTT topic - Power meter #3 (optional)",
"IgnoreSoc": "Ignore Battery SoC",
"BatterySocStartThreshold": "Battery SoC - Start threshold",
"BatterySocStopThreshold": "Battery SoC - Stop threshold",
"BatterySocSolarPassthroughStartThreshold": "Battery SoC - Start threshold for full solar passthrough",
Expand All @@ -661,7 +659,7 @@
"VoltageSolarPassthroughStopThreshold": "DC Voltage - Stop threshold for full solar passthrough",
"VoltageSolarPassthroughStartThresholdHint": "Inverter power is set according to Victron MPPT power (minus efficiency factors) when full solar passthrough is active. Use this if you like to supply excess power to the grid when battery is full. This is started when battery voltage goes over this limit and stopped if voltage drops below stop limit.",
"VoltageLoadCorrectionFactor": "DC Voltage - Load correction factor",
"BatterySocInfo": "<b>Hint:</b> The battery SoC (State of Charge) values can only be used if the battery communication interface is enabled. If the battery has not reported any SoC updates in the last minute, the voltage thresholds will be used as fallback.",
"BatterySocInfo": "<b>Hint:</b> The battery SoC (State of Charge) values are only used if the battery communication interface reported SoC updates in the last minute. Otherwise the voltage thresholds will be used as fallback.",
"InverterIsBehindPowerMeter": "Inverter is behind Power meter",
"Battery": "DC / Battery",
"VoltageLoadCorrectionInfo": "<b>Hint:</b> When the power output is higher, the voltage is usually decreasing. In order to not stop the inverter too early (Stop treshold), a power factor can be specified here to correct this. Corrected voltage = DC Voltage + (Current power * correction factor)."
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 @@ -11,6 +11,7 @@ export interface PowerLimiterConfig {
target_power_consumption_hysteresis: number;
lower_power_limit: number;
upper_power_limit: number;
ignore_soc: boolean;
battery_soc_start_threshold: number;
battery_soc_stop_threshold: number;
voltage_start_threshold: number;
Expand Down
13 changes: 9 additions & 4 deletions webapp/src/views/PowerLimiterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,12 @@
<CardElement :text="$t('powerlimiteradmin.Battery')" textVariant="text-bg-primary" add-space
v-show="powerLimiterConfigList.enabled"
>
<div class="row mb-3">
<InputElement
:label="$t('powerlimiteradmin.IgnoreSoc')"
v-model="powerLimiterConfigList.ignore_soc"
type="checkbox"/>

<div class="row mb-3" v-show="!powerLimiterConfigList.ignore_soc">
<label for="batterySocStartThreshold" class="col-sm-2 col-form-label">{{ $t('powerlimiteradmin.BatterySocStartThreshold') }}:</label>
<div class="col-sm-10">
<div class="input-group">
Expand All @@ -154,7 +159,7 @@
</div>
</div>

<div class="row mb-3">
<div class="row mb-3" v-show="!powerLimiterConfigList.ignore_soc">
<label for="batterySocStopThreshold" class="col-sm-2 col-form-label">{{ $t('powerlimiteradmin.BatterySocStopThreshold') }}</label>
<div class="col-sm-10">
<div class="input-group">
Expand All @@ -166,7 +171,7 @@
</div>
</div>

<div class="row mb-3" v-show="powerLimiterConfigList.solar_passthrough_enabled">
<div class="row mb-3" v-show="powerLimiterConfigList.solar_passthrough_enabled && !powerLimiterConfigList.ignore_soc">
<label for="batterySocSolarPassthroughStartThreshold" class="col-sm-2 col-form-label">{{ $t('powerlimiteradmin.BatterySocSolarPassthroughStartThreshold') }}
<BIconInfoCircle v-tooltip :title="$t('powerlimiteradmin.BatterySocSolarPassthroughStartThresholdHint')" />
</label>
Expand All @@ -180,7 +185,7 @@
</div>
</div>

<div class="alert alert-secondary" role="alert" v-html="$t('powerlimiteradmin.BatterySocInfo')"></div>
<div class="alert alert-secondary" role="alert" v-html="$t('powerlimiteradmin.BatterySocInfo')" v-show="!powerLimiterConfigList.ignore_soc"></div>

<div class="row mb-3">
<label for="inputVoltageStartThreshold" class="col-sm-2 col-form-label">{{ $t('powerlimiteradmin.VoltageStartThreshold') }}:</label>
Expand Down

0 comments on commit 921302b

Please sign in to comment.