diff --git a/include/Configuration.h b/include/Configuration.h index 2eac8a0c..6b0e2c17 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -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]; diff --git a/include/PowerLimiter.h b/include/PowerLimiter.h index 31025e4a..a2ad7ebf 100644 --- a/include/PowerLimiter.h +++ b/include/PowerLimiter.h @@ -13,6 +13,11 @@ typedef enum { STATE_CONSUME_SOLAR_POWER_ONLY, STATE_NORMAL_OPERATION } plStates; + +typedef enum { + EMPTY_WHEN_FULL= 0, + EMPTY_AT_NIGTH +} batDrainStrategy; class PowerLimiterClass { diff --git a/include/defaults.h b/include/defaults.h index 18c211e7..fd6df35d 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -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 diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 53a2df84..50002326 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -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)); diff --git a/src/PowerLimiter.cpp b/src/PowerLimiter.cpp index 89672560..bfc9bb79 100644 --- a/src/PowerLimiter.cpp +++ b/src/PowerLimiter.cpp @@ -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; } diff --git a/src/WebApi_powerlimiter.cpp b/src/WebApi_powerlimiter.cpp index 05e75ad8..08f08355 100644 --- a/src/WebApi_powerlimiter.cpp +++ b/src/WebApi_powerlimiter.cpp @@ -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(); config.PowerLimiter_SolarPassTroughEnabled = root[F("solar_passtrough_enabled")].as(); + config.PowerLimiter_BatteryDrainStategy= root[F("battery_drain_strategy")].as(); strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, root[F("mqtt_topic_powermeter_1")].as().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter1)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, root[F("mqtt_topic_powermeter_2")].as().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter2)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, root[F("mqtt_topic_powermeter_3")].as().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter3)); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index f2e31bbc..e13d95e6 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -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.", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index be095abe..e4d7e133 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -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.", diff --git a/webapp/src/types/PowerLimiterConfig.ts b/webapp/src/types/PowerLimiterConfig.ts index 6cbdd612..09521dfe 100644 --- a/webapp/src/types/PowerLimiterConfig.ts +++ b/webapp/src/types/PowerLimiterConfig.ts @@ -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; diff --git a/webapp/src/views/PowerLimiterAdminView.vue b/webapp/src/views/PowerLimiterAdminView.vue index 4ac0c6e9..2c00301d 100644 --- a/webapp/src/views/PowerLimiterAdminView.vue +++ b/webapp/src/views/PowerLimiterAdminView.vue @@ -14,6 +14,19 @@ :label="$t('powerlimiteradmin.EnableSolarPasstrough')" v-model="powerLimiterConfigList.solar_passtrough_enabled" type="checkbox" wide/> + +
+ +
+ +
+
@@ -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, diff --git a/webapp_dist/js/app.js.gz b/webapp_dist/js/app.js.gz index 503a7797..10892b57 100644 Binary files a/webapp_dist/js/app.js.gz and b/webapp_dist/js/app.js.gz differ