Implement battery drain strategies:

- empty when full
- empty at night
This commit is contained in:
helgeerbe 2023-03-16 17:48:22 +01:00
parent 32a96bbd06
commit 46ce6ad50f
11 changed files with 36 additions and 1 deletions

View File

@ -101,6 +101,7 @@ struct CONFIG_T {
bool PowerLimiter_Enabled;
bool PowerLimiter_SolarPassTroughEnabled;
uint8_t PowerLimiter_BatteryDrainStategy;
uint32_t PowerLimiter_Interval;
char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];

View File

@ -14,6 +14,11 @@ typedef enum {
STATE_NORMAL_OPERATION
} plStates;
typedef enum {
EMPTY_WHEN_FULL= 0,
EMPTY_AT_NIGTH
} batDrainStrategy;
class PowerLimiterClass {
public:

View File

@ -94,6 +94,7 @@
#define POWERLIMITER_ENABLED false
#define POWERLIMITER_SOLAR_PASSTROUGH_ENABLED true
#define POWERLIMITER_BATTERY_DRAIN_STRATEGY 0
#define POWERLIMITER_INTERVAL 10
#define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true
#define POWERLIMITER_INVERTER_ID 0

View File

@ -118,6 +118,7 @@ bool ConfigurationClass::write()
JsonObject powerlimiter = doc.createNestedObject("powerlimiter");
powerlimiter["enabled"] = config.PowerLimiter_Enabled;
powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled;
powerlimiter["battery_drain_strategy"] = config.PowerLimiter_BatteryDrainStategy;
powerlimiter["interval"] = config.PowerLimiter_Interval;
powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1;
powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2;
@ -283,6 +284,7 @@ bool ConfigurationClass::read()
JsonObject powerlimiter = doc["powerlimiter"];
config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_ENABLED;
config.PowerLimiter_SolarPassTroughEnabled = powerlimiter["solar_passtrough_enabled"] | POWERLIMITER_SOLAR_PASSTROUGH_ENABLED;
config.PowerLimiter_BatteryDrainStategy = powerlimiter["battery_drain_strategy"] | POWERLIMITER_BATTERY_DRAIN_STRATEGY;
config.PowerLimiter_Interval = POWERLIMITER_INTERVAL;
strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, powerlimiter["mqtt_topic_powermeter_1"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter1));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, powerlimiter["mqtt_topic_powermeter_2"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter2));

View File

@ -149,7 +149,7 @@ void PowerLimiterClass::loop()
int32_t newPowerLimit = calcPowerLimit(inverter, true);
if (!inverter->isProducing()
|| isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
|| (newPowerLimit < config.PowerLimiter_LowerPowerLimit && config.PowerLimiter_BatteryDrainStategy == EMPTY_WHEN_FULL)) {
_plState = STATE_OFF;
break;
}

View File

@ -37,6 +37,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
root[F("enabled")] = config.PowerLimiter_Enabled;
root[F("solar_passtrough_enabled")] = config.PowerLimiter_SolarPassTroughEnabled;
root[F("battery_drain_strategy")] = config.PowerLimiter_BatteryDrainStategy;
root[F("mqtt_topic_powermeter_1")] = config.PowerLimiter_MqttTopicPowerMeter1;
root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2;
root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3;
@ -120,6 +121,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get();
config.PowerLimiter_Enabled = root[F("enabled")].as<bool>();
config.PowerLimiter_SolarPassTroughEnabled = root[F("solar_passtrough_enabled")].as<bool>();
config.PowerLimiter_BatteryDrainStategy= root[F("battery_drain_strategy")].as<uint8_t>();
strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, root[F("mqtt_topic_powermeter_1")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter1));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, root[F("mqtt_topic_powermeter_2")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter2));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, root[F("mqtt_topic_powermeter_3")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter3));

View File

@ -458,6 +458,9 @@
"General": "Allgemein",
"Enable": "Aktiviert",
"EnableSolarPasstrough": "Aktiviere Solar Pass-trough",
"BatteryDrainStrategy": "Strategie zur Batterieentleerung",
"BatteryDrainWhenFull": "Leeren, wenn voll",
"BatteryDrainAtNight": "Leeren zur Nacht",
"SolarpasstroughInfo": "Diese Einstellung aktiviert die direkte Weitergabe der aktuell vom Laderegler gemeldeten Solarleistung an den Wechselrichter um eine unnötige Speicherung zu vermeiden und die Energieverluste zu minimieren.",
"InverterId": "Wechselrichter ID",
"InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.",

View File

@ -458,6 +458,9 @@
"General": "General",
"Enable": "Enable",
"EnableSolarPasstrough": "Enable Solar-Passtrough",
"BatteryDrainStrategy": "Battery drain strategy",
"BatteryDrainWhenFull": "Empty when full",
"BatteryDrainAtNight": "Empty at night",
"SolarpasstroughInfo": "When the sun is shining, this setting enables the sychronization of the inverter limit with the current solar power of the Victron MPPT charger. This optimizes battery degradation and loses.",
"InverterId": "Inverter ID",
"InverterIdHint": "Select proper inverter ID where battery is connected to.",

View File

@ -1,6 +1,7 @@
export interface PowerLimiterConfig {
enabled: boolean;
solar_passtrough_enabled: boolean;
battery_drain_strategy: number;
mqtt_topic_powermeter_1: string;
mqtt_topic_powermeter_2: string;
mqtt_topic_powermeter_3: string;

View File

@ -15,6 +15,19 @@
v-model="powerLimiterConfigList.solar_passtrough_enabled"
type="checkbox" wide/>
<div class="row mb-3" v-show="powerLimiterConfigList.enabled && powerLimiterConfigList.solar_passtrough_enabled">
<label for="inputTimezone" class="col-sm-2 col-form-label">
{{ $t('powerlimiteradmin.BatteryDrainStrategy') }}:
</label>
<div class="col-sm-10">
<select class="form-select" v-model="powerLimiterConfigList.battery_drain_strategy">
<option v-for="batteryDrainStrategy in batteryDrainStrategyList" :key="batteryDrainStrategy.key" :value="batteryDrainStrategy.key">
{{ $t(batteryDrainStrategy.value) }}
</option>
</select>
</div>
</div>
<div class="alert alert-secondary" v-show="powerLimiterConfigList.enabled" role="alert" v-html="$t('powerlimiteradmin.SolarpasstroughInfo')"></div>
<div class="row mb-3" v-show="powerLimiterConfigList.enabled">
@ -256,6 +269,10 @@ export default defineComponent({
{ key: 2, value: "CH 2" },
{ key: 3, value: "CH 3" },
],
batteryDrainStrategyList: [
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
],
alertMessage: "",
alertType: "info",
showAlert: false,

Binary file not shown.