Skip to content

Commit

Permalink
Feature: DPL Stop Discharge if UVP cell is reached
Browse files Browse the repository at this point in the history
Feature: DPL Stop Discharge if UVP cell is reached
  • Loading branch information
Robert-Schimanek committed Jul 15, 2024
1 parent f079245 commit b877384
Show file tree
Hide file tree
Showing 14 changed files with 47 additions and 1 deletion.
11 changes: 11 additions & 0 deletions include/BatteryStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class BatteryStats {
float getVoltage() const { return _voltage; }
uint32_t getVoltageAgeSeconds() const { return (millis() - _lastUpdateVoltage) / 1000; }

float getVoltageCellMin() const { return _voltageCellMin; }
uint32_t getVoltageCellMinAgeSeconds() const { return (millis() - _lastUpdateVoltageCellMin) / 1000; }


// convert stats to JSON for web application live view
virtual void getLiveViewData(JsonVariant& root) const;

Expand Down Expand Up @@ -57,6 +61,11 @@ class BatteryStats {
_lastUpdateVoltage = _lastUpdate = timestamp;
}

void setVoltageCellMin(float voltageCellMin, uint32_t timestamp) {
_voltageCellMin = voltageCellMin;
_lastUpdateVoltageCellMin = _lastUpdate = timestamp;
}

String _manufacturer = "unknown";
String _hwversion = "";
String _fwversion = "";
Expand All @@ -69,6 +78,8 @@ class BatteryStats {
uint32_t _lastUpdateSoC = 0;
float _voltage = 0; // total battery pack voltage
uint32_t _lastUpdateVoltage = 0;
float _voltageCellMin = 0; // total battery pack voltage
uint32_t _lastUpdateVoltageCellMin = 0;
};

class PylontechBatteryStats : public BatteryStats {
Expand Down
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ struct CONFIG_T {
uint32_t BatterySocStopThreshold;
float VoltageStartThreshold;
float VoltageStopThreshold;
float VoltageCellStopThreshold;
float VoltageLoadCorrectionFactor;
int8_t RestartHour;
uint32_t FullSolarPassThroughSoc;
Expand Down
1 change: 1 addition & 0 deletions include/PowerLimiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class PowerLimiterClass {
std::function<bool(float, float)> compare);
bool isStartThresholdReached();
bool isStopThresholdReached();
bool isCellStopThresholdReached();
bool isBelowStopThreshold();
bool useFullSolarPassthrough();
};
Expand Down
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
#define POWERLIMITER_BATTERY_SOC_STOP_THRESHOLD 20
#define POWERLIMITER_VOLTAGE_START_THRESHOLD 50.0
#define POWERLIMITER_VOLTAGE_STOP_THRESHOLD 49.0
#define POWERLIMITER_VOLTAGE_CELL_STOP_THRESHOLD 2.9
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001
#define POWERLIMITER_RESTART_HOUR -1
#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_SOC 100
Expand Down
2 changes: 2 additions & 0 deletions src/BatteryStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ void JkBmsBatteryStats::updateFrom(JkBms::DataPointContainer const& dp)
_cellMaxMilliVolt = std::max(_cellMaxMilliVolt, iter->second);
}
_cellVoltageTimestamp = millis();
BatteryStats::setVoltageCellMin(static_cast<float>(_cellMinMilliVolt) / 1000,
_cellVoltageTimestamp);
}

auto oVersion = _dataPoints.get<Label::BmsSoftwareVersion>();
Expand Down
2 changes: 2 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ bool ConfigurationClass::write()
powerlimiter["battery_soc_stop_threshold"] = config.PowerLimiter.BatterySocStopThreshold;
powerlimiter["voltage_start_threshold"] = config.PowerLimiter.VoltageStartThreshold;
powerlimiter["voltage_stop_threshold"] = config.PowerLimiter.VoltageStopThreshold;
powerlimiter["voltage_cell_stop_threshold"] = config.PowerLimiter.VoltageCellStopThreshold;
powerlimiter["voltage_load_correction_factor"] = config.PowerLimiter.VoltageLoadCorrectionFactor;
powerlimiter["inverter_restart_hour"] = config.PowerLimiter.RestartHour;
powerlimiter["full_solar_passthrough_soc"] = config.PowerLimiter.FullSolarPassThroughSoc;
Expand Down Expand Up @@ -469,6 +470,7 @@ bool ConfigurationClass::read()
config.PowerLimiter.BatterySocStopThreshold = powerlimiter["battery_soc_stop_threshold"] | POWERLIMITER_BATTERY_SOC_STOP_THRESHOLD;
config.PowerLimiter.VoltageStartThreshold = powerlimiter["voltage_start_threshold"] | POWERLIMITER_VOLTAGE_START_THRESHOLD;
config.PowerLimiter.VoltageStopThreshold = powerlimiter["voltage_stop_threshold"] | POWERLIMITER_VOLTAGE_STOP_THRESHOLD;
config.PowerLimiter.VoltageCellStopThreshold = powerlimiter["voltage_cell_stop_threshold"] | POWERLIMITER_VOLTAGE_CELL_STOP_THRESHOLD;
config.PowerLimiter.VoltageLoadCorrectionFactor = powerlimiter["voltage_load_correction_factor"] | POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR;
config.PowerLimiter.RestartHour = powerlimiter["inverter_restart_hour"] | POWERLIMITER_RESTART_HOUR;
config.PowerLimiter.FullSolarPassThroughSoc = powerlimiter["full_solar_passthrough_soc"] | POWERLIMITER_FULL_SOLAR_PASSTHROUGH_SOC;
Expand Down
17 changes: 17 additions & 0 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ void PowerLimiterClass::loop()
auto getBatteryPower = [this,&config]() -> bool {
if (config.PowerLimiter.IsInverterSolarPowered) { return false; }

if (isCellStopThresholdReached()) { return false; }

if (isStopThresholdReached()) { return false; }

if (isStartThresholdReached()) { return true; }
Expand Down Expand Up @@ -913,6 +915,10 @@ bool PowerLimiterClass::testThreshold(float socThreshold, float voltThreshold,
return compare(stats->getSoC(), socThreshold);
}

// if volThreshold for one cell check if min cell voltage is reached
if (voltThreshold <= 5) {
return compare(stats->getVoltageCellMin(), voltThreshold);
}
// use voltage threshold as fallback
if (voltThreshold <= 0.0) { return false; }

Expand Down Expand Up @@ -941,6 +947,17 @@ bool PowerLimiterClass::isStopThresholdReached()
);
}

bool PowerLimiterClass::isCellStopThresholdReached()
{
CONFIG_T& config = Configuration.get();

return testThreshold(
config.PowerLimiter.BatterySocStopThreshold,
config.PowerLimiter.VoltageCellStopThreshold,
[](float a, float b) -> bool { return a <= b; }
);
}

bool PowerLimiterClass::isBelowStopThreshold()
{
CONFIG_T& config = Configuration.get();
Expand Down
5 changes: 4 additions & 1 deletion src/WebApi_powerlimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
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;
root["voltage_stop_threshold"] = static_cast<int>(config.PowerLimiter.VoltageStopThreshold * 100 +0.5) / 100.0;;
root["voltage_stop_threshold"] = static_cast<int>(config.PowerLimiter.VoltageStopThreshold * 100 +0.5) / 100.0;
root["voltage_cell_stop_threshold"] = static_cast<int>(config.PowerLimiter.VoltageCellStopThreshold * 100 +0.5) / 100.0;
root["voltage_load_correction_factor"] = config.PowerLimiter.VoltageLoadCorrectionFactor;
root["inverter_restart_hour"] = config.PowerLimiter.RestartHour;
root["full_solar_passthrough_soc"] = config.PowerLimiter.FullSolarPassThroughSoc;
Expand Down Expand Up @@ -187,6 +188,8 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
config.PowerLimiter.VoltageStartThreshold = static_cast<int>(config.PowerLimiter.VoltageStartThreshold * 100) / 100.0;
config.PowerLimiter.VoltageStopThreshold = root["voltage_stop_threshold"].as<float>();
config.PowerLimiter.VoltageStopThreshold = static_cast<int>(config.PowerLimiter.VoltageStopThreshold * 100) / 100.0;
config.PowerLimiter.VoltageCellStopThreshold = root["voltage_cell_stop_threshold"].as<float>();
config.PowerLimiter.VoltageCellStopThreshold = static_cast<int>(config.PowerLimiter.VoltageCellStopThreshold * 100) / 100.0;
config.PowerLimiter.VoltageLoadCorrectionFactor = root["voltage_load_correction_factor"].as<float>();
config.PowerLimiter.RestartHour = root["inverter_restart_hour"].as<int8_t>();

Expand Down
1 change: 1 addition & 0 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@
"IgnoreSoc": "Batterie SoC ignorieren",
"StartThreshold": "Batterienutzung Start-Schwellwert",
"StopThreshold": "Batterienutzung Stop-Schwellwert",
"CellStopThreshold": "Batterienutzung Mindestspannung der schwächsten Zelle",
"FullSolarPassthroughStartThreshold": "Full-Solar-Passthrough Start-Schwellwert",
"FullSolarPassthroughStartThresholdHint": "Oberhalb dieses Schwellwertes wird die Inverterleistung der Victron-MPPT-Leistung gleichgesetzt (abzüglich Effizienzkorrekturfaktor). Kann verwendet werden um überschüssige Solarleistung an das Netz zu liefern wenn die Batterie voll ist.",
"VoltageSolarPassthroughStopThreshold": "Full-Solar-Passthrough Stop-Schwellwert",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@
"IgnoreSoc": "Ignore Battery SoC",
"StartThreshold": "Start Threshold for Battery Discharging",
"StopThreshold": "Stop Threshold for Battery Discharging",
"CellStopThreshold": "Stop Threshold for Discharging regarding weakest battery cell",
"FullSolarPassthroughStartThreshold": "Full Solar-Passthrough Start Threshold",
"FullSolarPassthroughStartThresholdHint": "Inverter power is set equal to Victron MPPT power (minus efficiency factors) while above this threshold. Use this if you want to supply excess power to the grid when the battery is full.",
"VoltageSolarPassthroughStopThreshold": "Full Solar-Passthrough Stop Threshold",
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 @@ -41,6 +41,7 @@ export interface PowerLimiterConfig {
battery_soc_stop_threshold: number;
voltage_start_threshold: number;
voltage_stop_threshold: number;
voltage_cell_stop_threshold: number;
voltage_load_correction_factor: number;
inverter_restart_hour: number;
full_solar_passthrough_soc: number;
Expand Down
5 changes: 5 additions & 0 deletions webapp/src/views/PowerLimiterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@
</CardElement>

<CardElement :text="$t('powerlimiteradmin.VoltageThresholds')" textVariant="text-bg-primary" add-space v-if="canUseVoltageThresholds()">
<InputElement :label="$t('powerlimiteradmin.CellStopThreshold')"
v-model="powerLimiterConfigList.voltage_cell_stop_threshold"
placeholder="2.9" min="2.5" max="4.3" postfix="V"
type="number" step="0.001" wide/>

<InputElement :label="$t('powerlimiteradmin.StartThreshold')"
v-model="powerLimiterConfigList.voltage_start_threshold"
placeholder="50" min="16" max="66" postfix="V"
Expand Down
Binary file modified webapp_dist/index.html.gz
Binary file not shown.
Binary file modified webapp_dist/js/app.js.gz
Binary file not shown.

0 comments on commit b877384

Please sign in to comment.