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_Enabled;
bool PowerLimiter_SolarPassTroughEnabled; bool PowerLimiter_SolarPassTroughEnabled;
uint8_t PowerLimiter_BatteryDrainStategy;
uint32_t PowerLimiter_Interval; uint32_t PowerLimiter_Interval;
char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1]; char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1]; char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];

View File

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

View File

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

View File

@ -118,6 +118,7 @@ bool ConfigurationClass::write()
JsonObject powerlimiter = doc.createNestedObject("powerlimiter"); JsonObject powerlimiter = doc.createNestedObject("powerlimiter");
powerlimiter["enabled"] = config.PowerLimiter_Enabled; powerlimiter["enabled"] = config.PowerLimiter_Enabled;
powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled; powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled;
powerlimiter["battery_drain_strategy"] = config.PowerLimiter_BatteryDrainStategy;
powerlimiter["interval"] = config.PowerLimiter_Interval; powerlimiter["interval"] = config.PowerLimiter_Interval;
powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1; powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1;
powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2; powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2;
@ -283,6 +284,7 @@ bool ConfigurationClass::read()
JsonObject powerlimiter = doc["powerlimiter"]; JsonObject powerlimiter = doc["powerlimiter"];
config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_ENABLED; config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_ENABLED;
config.PowerLimiter_SolarPassTroughEnabled = powerlimiter["solar_passtrough_enabled"] | POWERLIMITER_SOLAR_PASSTROUGH_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; config.PowerLimiter_Interval = POWERLIMITER_INTERVAL;
strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, powerlimiter["mqtt_topic_powermeter_1"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter1)); 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)); 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); int32_t newPowerLimit = calcPowerLimit(inverter, true);
if (!inverter->isProducing() if (!inverter->isProducing()
|| isStopThresholdReached(inverter) || isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) { || (newPowerLimit < config.PowerLimiter_LowerPowerLimit && config.PowerLimiter_BatteryDrainStategy == EMPTY_WHEN_FULL)) {
_plState = STATE_OFF; _plState = STATE_OFF;
break; break;
} }

View File

@ -37,6 +37,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
root[F("enabled")] = config.PowerLimiter_Enabled; root[F("enabled")] = config.PowerLimiter_Enabled;
root[F("solar_passtrough_enabled")] = config.PowerLimiter_SolarPassTroughEnabled; 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_1")] = config.PowerLimiter_MqttTopicPowerMeter1;
root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2; root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2;
root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3; root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3;
@ -120,6 +121,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
config.PowerLimiter_Enabled = root[F("enabled")].as<bool>(); config.PowerLimiter_Enabled = root[F("enabled")].as<bool>();
config.PowerLimiter_SolarPassTroughEnabled = root[F("solar_passtrough_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_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_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)); 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", "General": "Allgemein",
"Enable": "Aktiviert", "Enable": "Aktiviert",
"EnableSolarPasstrough": "Aktiviere Solar Pass-trough", "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.", "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", "InverterId": "Wechselrichter ID",
"InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.", "InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.",

View File

@ -458,6 +458,9 @@
"General": "General", "General": "General",
"Enable": "Enable", "Enable": "Enable",
"EnableSolarPasstrough": "Enable Solar-Passtrough", "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.", "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", "InverterId": "Inverter ID",
"InverterIdHint": "Select proper inverter ID where battery is connected to.", "InverterIdHint": "Select proper inverter ID where battery is connected to.",

View File

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

View File

@ -14,6 +14,19 @@
:label="$t('powerlimiteradmin.EnableSolarPasstrough')" :label="$t('powerlimiteradmin.EnableSolarPasstrough')"
v-model="powerLimiterConfigList.solar_passtrough_enabled" v-model="powerLimiterConfigList.solar_passtrough_enabled"
type="checkbox" wide/> 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="alert alert-secondary" v-show="powerLimiterConfigList.enabled" role="alert" v-html="$t('powerlimiteradmin.SolarpasstroughInfo')"></div>
@ -256,6 +269,10 @@ export default defineComponent({
{ key: 2, value: "CH 2" }, { key: 2, value: "CH 2" },
{ key: 3, value: "CH 3" }, { key: 3, value: "CH 3" },
], ],
batteryDrainStrategyList: [
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
],
alertMessage: "", alertMessage: "",
alertType: "info", alertType: "info",
showAlert: false, showAlert: false,

Binary file not shown.