From e0a8da84d79ea4c0eb5112122f762365b8d87cf7 Mon Sep 17 00:00:00 2001 From: MalteSchm Date: Sun, 23 Apr 2023 11:26:02 +0200 Subject: [PATCH] full solar passthrough --- README_onBattery.md | 3 +- docs/MQTT_Topics.md | 10 ++- include/Configuration.h | 3 + include/PowerLimiter.h | 13 ++- include/defaults.h | 3 + src/Configuration.cpp | 6 ++ src/MqttHandlePowerLimiter.cpp | 13 ++- src/PowerLimiter.cpp | 93 ++++++++++++++++++---- src/WebApi_powerlimiter.cpp | 11 ++- webapp/src/locales/de.json | 5 ++ webapp/src/locales/en.json | 5 ++ webapp/src/locales/fr.json | 40 ++++++++++ webapp/src/types/PowerLimiterConfig.ts | 3 + webapp/src/views/PowerLimiterAdminView.vue | 40 ++++++++++ 14 files changed, 222 insertions(+), 26 deletions(-) diff --git a/README_onBattery.md b/README_onBattery.md index a9b824b5..2d348b8b 100644 --- a/README_onBattery.md +++ b/README_onBattery.md @@ -113,7 +113,8 @@ Other settings are: * Target power consumption and hysteresis set the power range that can be consumed from the grid. * Power limits control the min / max limits of the inverter * Inverter is behind power meter. Select this if your inverter power is measured by the power meter. This is typically the case. -* Battery start and stop threshold can be configured using voltage and / or state of charge values. Stage of charge values require a Pylontech battery at this point. +* Battery start and stop threshold can be configured using voltage and / or state of charge values. Stage of charge values requires a Pylontech battery at this point. +* A Battery full solar passthrough threshold can be configured using voltage or state of charge value. Stage of charge values requires a Pylontech battery at this point. The option can be used if the battery is full and will steer the inverter according to solar power reported by the Victron MPPT Solar Charger. ![image](https://user-images.githubusercontent.com/59169507/222155765-9fff47a4-8ffa-42cf-8671-6359288e0cab.png) diff --git a/docs/MQTT_Topics.md b/docs/MQTT_Topics.md index 6b169e5f..7289ab65 100644 --- a/docs/MQTT_Topics.md +++ b/docs/MQTT_Topics.md @@ -153,6 +153,7 @@ cmd topics are used to set values. Status topics are updated from values set in | battery/charging/chargeImmediately | R | Charge immediately flag | 0 / 1 | ### Huawei AC charger topics + | Topic | R / W | Description | Value / Unit | | --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- | | huawei/cmd/limit_online_voltage | W | Online voltage (i.e. CAN bus connected) | Volt (V) | @@ -168,4 +169,11 @@ cmd topics are used to set values. Status topics are updated from values set in | huawei/output_power | R | Output power | Watt (W) | | huawei/input_temp | R | Input air temperature | °C | | huawei/output_temp | R | Output air temperature | °C | -| huawei/efficiency | R | Efficiency | Percentage | \ No newline at end of file +| huawei/efficiency | R | Efficiency | Percentage | + +### Power Limiter topics + +| Topic | R / W | Description | Value / Unit | +| --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- | +| powerlimiter/cmd/mode | W | Power Limiter operation mode | 0 - Normal operation, 1 - Fully disable, 2 - Solar Passthrough only | +| powerlimiter/status/mode | R | Get Power Limiter operation mode | see above | diff --git a/include/Configuration.h b/include/Configuration.h index 280256ea..e109ab64 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -151,6 +151,9 @@ struct CONFIG_T { float PowerLimiter_VoltageStopThreshold; float PowerLimiter_VoltageLoadCorrectionFactor; int8_t PowerLimiter_RestartHour; + uint32_t PowerLimiter_FullSolarPassThroughSoc; + float PowerLimiter_FullSolarPassThroughStartVoltage; + float PowerLimiter_FullSolarPassThroughStopVoltage; bool Battery_Enabled; bool Huawei_Enabled; diff --git a/include/PowerLimiter.h b/include/PowerLimiter.h index e0fa72a0..4a65f691 100644 --- a/include/PowerLimiter.h +++ b/include/PowerLimiter.h @@ -12,6 +12,11 @@ #define PL_UI_STATE_USE_SOLAR_ONLY 2 #define PL_UI_STATE_USE_SOLAR_AND_BATTERY 3 +#define PL_MODE_ENABLE_NORMAL_OP 0 +#define PL_MODE_FULL_DISABLE 1 +#define PL_MODE_SOLAR_PT_ONLY 2 + + typedef enum { SHUTDOWN = 0, ACTIVE @@ -29,8 +34,8 @@ public: void loop(); uint8_t getPowerLimiterState(); int32_t getLastRequestedPowewrLimit(); - void setDisable(bool disable); - bool getDisable(); + void setMode(uint8_t mode); + bool getMode(); void calcNextInverterRestart(); private: @@ -38,10 +43,11 @@ private: int32_t _lastRequestedPowerLimit = 0; uint32_t _lastLimitSetTime = 0; plStates _plState; - bool _disabled = false; + uint8_t _mode = PL_MODE_ENABLE_NORMAL_OP; bool _batteryDischargeEnabled = false; uint32_t _nextInverterRestart = 0; // Values: 0->not calculated / 1->no restart configured / >1->time of next inverter restart in millis() uint32_t _nextCalculateCheck = 5000; // time in millis for next NTP check to calulate restart + bool _fullSolarPassThroughEnabled = false; float _powerMeter1Power; float _powerMeter2Power; @@ -54,6 +60,7 @@ private: float getLoadCorrectedVoltage(std::shared_ptr inverter); bool isStartThresholdReached(std::shared_ptr inverter); bool isStopThresholdReached(std::shared_ptr inverter); + bool useFullSolarPassthrough(std::shared_ptr inverter); }; extern PowerLimiterClass PowerLimiter; diff --git a/include/defaults.h b/include/defaults.h index 06bba4f1..fd596bb4 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -123,6 +123,9 @@ #define POWERLIMITER_VOLTAGE_STOP_THRESHOLD 49.0 #define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001 #define POWERLIMITER_RESTART_HOUR -1 +#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_SOC 100 +#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_START_VOLTAGE 100 +#define POWERLIMITER_FULL_SOLAR_PASSTHROUGH_STOP_VOLTAGE 100 #define BATTERY_ENABLED false diff --git a/src/Configuration.cpp b/src/Configuration.cpp index ea93e387..9635db6a 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -164,6 +164,9 @@ bool ConfigurationClass::write() powerlimiter["voltage_stop_threshold"] = config.PowerLimiter_VoltageStopThreshold; powerlimiter["voltage_load_correction_factor"] = config.PowerLimiter_VoltageLoadCorrectionFactor; powerlimiter["inverter_restart_hour"] = config.PowerLimiter_RestartHour; + powerlimiter["full_solar_passthrough_soc"] = config.PowerLimiter_FullSolarPassThroughSoc; + powerlimiter["full_solar_passthrough_start_voltage"] = config.PowerLimiter_FullSolarPassThroughStartVoltage; + powerlimiter["full_solar_passthrough_stop_voltage"] = config.PowerLimiter_FullSolarPassThroughStopVoltage; JsonObject battery = doc.createNestedObject("battery"); battery["enabled"] = config.Battery_Enabled; @@ -362,6 +365,9 @@ bool ConfigurationClass::read() config.PowerLimiter_VoltageStopThreshold = powerlimiter["voltage_stop_threshold"] | POWERLIMITER_VOLTAGE_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; + config.PowerLimiter_FullSolarPassThroughStartVoltage = powerlimiter["full_solar_passthrough_start_voltage"] | POWERLIMITER_FULL_SOLAR_PASSTHROUGH_START_VOLTAGE; + config.PowerLimiter_FullSolarPassThroughStopVoltage = powerlimiter["full_solar_passthrough_stop_voltage"] | POWERLIMITER_FULL_SOLAR_PASSTHROUGH_STOP_VOLTAGE; JsonObject battery = doc["battery"]; config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED; diff --git a/src/MqttHandlePowerLimiter.cpp b/src/MqttHandlePowerLimiter.cpp index 5090b1ca..56ec1a16 100644 --- a/src/MqttHandlePowerLimiter.cpp +++ b/src/MqttHandlePowerLimiter.cpp @@ -8,7 +8,7 @@ #include "PowerLimiter.h" #include -#define TOPIC_SUB_POWER_LIMITER "disable" +#define TOPIC_SUB_POWER_LIMITER "mode" MqttHandlePowerLimiterClass MqttHandlePowerLimiter; @@ -38,7 +38,7 @@ void MqttHandlePowerLimiterClass::loop() const CONFIG_T& config = Configuration.get(); if ((millis() - _lastPublish) > (config.Mqtt_PublishInterval * 1000) ) { - MqttSettings.publish("powerlimiter/status/disabled", String(PowerLimiter.getDisable())); + MqttSettings.publish("powerlimiter/status/mode", String(PowerLimiter.getMode())); yield(); _lastPublish = millis(); @@ -77,14 +77,19 @@ void MqttHandlePowerLimiterClass::onMqttMessage(const espMqttClientTypes::Messag delete[] str; if (!strcmp(setting, TOPIC_SUB_POWER_LIMITER)) { + if(payload_val == 2) { + MessageOutput.println("Power limiter full solar PT"); + PowerLimiter.setMode(PL_MODE_SOLAR_PT_ONLY); + return; + } if(payload_val == 1) { MessageOutput.println("Power limiter disabled"); - PowerLimiter.setDisable(true); + PowerLimiter.setMode(PL_MODE_FULL_DISABLE); return; } if(payload_val == 0) { MessageOutput.println("Power limiter enabled"); - PowerLimiter.setDisable(false); + PowerLimiter.setMode(PL_MODE_ENABLE_NORMAL_OP); return; } MessageOutput.println("Power limiter enable / disable - unknown command received. Please use 0 or 1"); diff --git a/src/PowerLimiter.cpp b/src/PowerLimiter.cpp index b96809db..71a6f6d1 100644 --- a/src/PowerLimiter.cpp +++ b/src/PowerLimiter.cpp @@ -15,7 +15,7 @@ PowerLimiterClass PowerLimiter; -// #define POWER_LIMITER_DEBUG +#define POWER_LIMITER_DEBUG void PowerLimiterClass::init() { @@ -75,7 +75,7 @@ void PowerLimiterClass::loop() } // Make sure inverter is turned off if PL is disabled by user/MQTT - if (((!config.PowerLimiter_Enabled || _disabled) && _plState != SHUTDOWN)) { + if (((!config.PowerLimiter_Enabled || _mode == PL_MODE_FULL_DISABLE) && _plState != SHUTDOWN)) { if (inverter->isProducing()) { MessageOutput.printf("PL initiated inverter shutdown.\r\n"); inverter->sendActivePowerControlRequest(static_cast(config.PowerLimiter_LowerPowerLimit), PowerLimitControlType::AbsolutNonPersistent); @@ -91,7 +91,7 @@ void PowerLimiterClass::loop() } // Return if power limiter is disabled - if (!config.PowerLimiter_Enabled || _disabled) { + if (!config.PowerLimiter_Enabled || _mode == PL_MODE_FULL_DISABLE) { #ifdef POWER_LIMITER_DEBUG MessageOutput.printf("[PowerLimiterClass::loop] ******************* PL disabled\r\n"); #endif @@ -206,12 +206,12 @@ int32_t PowerLimiterClass::getLastRequestedPowewrLimit() { return _lastRequestedPowerLimit; } -bool PowerLimiterClass::getDisable() { - return _disabled; +bool PowerLimiterClass::getMode() { + return _mode; } -void PowerLimiterClass::setDisable(bool disable) { - _disabled = disable; +void PowerLimiterClass::setMode(uint8_t mode) { + _mode = mode; } bool PowerLimiterClass::canUseDirectSolarPower() @@ -232,7 +232,13 @@ bool PowerLimiterClass::canUseDirectSolarPower() } - +// Logic table +// | Case # | batteryDischargeEnabled | solarPowerEnabled | useFullSolarPassthrough | Result | +// | 1 | false | false | doesn't matter | PL = 0 | +// | 2 | false | true | doesn't matter | PL = Victron Power | +// | 3 | true | doesn't matter | false | PL = PowerMeter value (Battery can supply unlimited energy) | +// | 4 | true | false | true | PL = PowerMeter value | +// | 5 | true | true | true | PL = max(PowerMeter value, Victron Power) | int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr inverter, bool solarPowerEnabled, bool batteryDischargeEnabled) { @@ -241,7 +247,7 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr inve int32_t newPowerLimit = round(PowerMeter.getPowerTotal()); if (!solarPowerEnabled && !batteryDischargeEnabled) { - // No energy sources available + // Case 1 - No energy sources available return 0; } @@ -256,6 +262,7 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr inve // We're not trying to hit 0 exactly but take an offset into account // This means we never fully compensate the used power with the inverter + // Case 3 newPowerLimit -= config.PowerLimiter_TargetPowerConsumption; // Check if the new value is within the limits of the hysteresis and @@ -268,17 +275,27 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr inve return _lastRequestedPowerLimit; } - // We should use Victron solar power only (corrected by efficiency factor) - if (solarPowerEnabled && !batteryDischargeEnabled) { - float efficiency = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_EFF); - int32_t victronChargePower = this->getDirectSolarPower(); - int32_t adjustedVictronChargePower = victronChargePower * (efficiency > 0.0 ? (efficiency / 100.0) : 1.0); // if inverter is off, use 1.0 + // At this point we've calculated the required energy to compensate for household consumption. + // If the battery is enabled this can always be supplied since we assume that the battery can supply unlimited power + // The next step is to determine if the Solar power as provided by the Victron charger + // actually constrains or dictates another inverter power value + float efficiency = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_EFF) * 0.95 /*Victron efficiency*/; + int32_t victronChargePower = this->getDirectSolarPower(); + int32_t adjustedVictronChargePower = victronChargePower * (efficiency > 0.0 ? (efficiency / 100.0) : 1.0); // if inverter is off, use 1.0 + // Battery can be discharged and we should output max (Victron solar power || power meter value) + if(batteryDischargeEnabled && useFullSolarPassthrough(inverter)) { + // Case 5 + newPowerLimit = newPowerLimit > adjustedVictronChargePower ? newPowerLimit : adjustedVictronChargePower; + } + + // We should use Victron solar power only (corrected by efficiency factor) + if ((solarPowerEnabled && !batteryDischargeEnabled) || (_mode == PL_MODE_SOLAR_PT_ONLY)) { + // Case 2 - Limit power to solar power only MessageOutput.printf("[PowerLimiterClass::loop] Consuming Solar Power Only -> victronChargePower: %d, efficiency: %.2f, powerConsumption: %d \r\n", victronChargePower, efficiency, newPowerLimit); - // Limit power to solar power only - if (adjustedVictronChargePower < newPowerLimit) + if ((adjustedVictronChargePower < newPowerLimit) || (_mode == PL_MODE_SOLAR_PT_ONLY)) newPowerLimit = adjustedVictronChargePower; } @@ -445,4 +462,48 @@ void PowerLimiterClass::calcNextInverterRestart() _nextInverterRestart = 0; } MessageOutput.printf("[PowerLimiterClass::calcNextInverterRestart] _nextInverterRestart @ %d millis\r\n", _nextInverterRestart); +} + +bool PowerLimiterClass::useFullSolarPassthrough(std::shared_ptr inverter) +{ + CONFIG_T& config = Configuration.get(); + + // We only do full solar PT if general solar PT is enabled + if(!config.PowerLimiter_SolarPassThroughEnabled) { + return false; + } + + // Check if the Battery interface is enabled and the SOC stop threshold is reached + if (config.Battery_Enabled + && config.PowerLimiter_FullSolarPassThroughSoc > 0.0 + && (millis() - Battery.stateOfChargeLastUpdate) < 60000 + && Battery.stateOfCharge >= config.PowerLimiter_FullSolarPassThroughSoc) { + return true; + } + + // Otherwise we use the voltage threshold + if (config.PowerLimiter_FullSolarPassThroughStartVoltage <= 0.0 || config.PowerLimiter_FullSolarPassThroughStopVoltage <= 0.0) { + return false; + } + + float dcVoltage = inverter->Statistics()->getChannelFieldValue(TYPE_DC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_UDC); + +#ifdef POWER_LIMITER_DEBUG + MessageOutput.printf("[PowerLimiterClass::loop] useFullSolarPassthrough: FullSolarPT Start %f, FullSolarPT Stop: %f, dcVoltage: %f\r\n", + config.PowerLimiter_FullSolarPassThroughStartVoltage, config.PowerLimiter_FullSolarPassThroughStopVoltage, dcVoltage); +#endif + + if (dcVoltage <= 0.0) { + return false; + } + + if (dcVoltage >= config.PowerLimiter_FullSolarPassThroughStartVoltage) { + _fullSolarPassThroughEnabled = true; + } + + if (dcVoltage <= config.PowerLimiter_FullSolarPassThroughStopVoltage) { + _fullSolarPassThroughEnabled = false; + } + + return _fullSolarPassThroughEnabled; } \ No newline at end of file diff --git a/src/WebApi_powerlimiter.cpp b/src/WebApi_powerlimiter.cpp index 2fc69c22..00bfacbf 100644 --- a/src/WebApi_powerlimiter.cpp +++ b/src/WebApi_powerlimiter.cpp @@ -53,6 +53,9 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request) root[F("voltage_stop_threshold")] = static_cast(config.PowerLimiter_VoltageStopThreshold * 100 +0.5) / 100.0;; root[F("voltage_load_correction_factor")] = config.PowerLimiter_VoltageLoadCorrectionFactor; root[F("inverter_restart_hour")] = config.PowerLimiter_RestartHour; + root[F("full_solar_passthrough_soc")] = config.PowerLimiter_FullSolarPassThroughSoc; + root[F("full_solar_passthrough_start_voltage")] = static_cast(config.PowerLimiter_FullSolarPassThroughStartVoltage * 100 + 0.5) / 100.0; + root[F("full_solar_passthrough_stop_voltage")] = static_cast(config.PowerLimiter_FullSolarPassThroughStopVoltage * 100 + 0.5) / 100.0; response->setLength(); request->send(response); @@ -120,7 +123,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request) CONFIG_T& config = Configuration.get(); config.PowerLimiter_Enabled = root[F("enabled")].as(); - PowerLimiter.setDisable(false); // User input clears the PL internal disable flag + PowerLimiter.setMode(PL_MODE_ENABLE_NORMAL_OP); // User input sets PL to normal operation config.PowerLimiter_SolarPassThroughEnabled = root[F("solar_passtrough_enabled")].as(); config.PowerLimiter_BatteryDrainStategy= root[F("battery_drain_strategy")].as(); config.PowerLimiter_IsInverterBehindPowerMeter = root[F("is_inverter_behind_powermeter")].as(); @@ -138,6 +141,12 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request) config.PowerLimiter_VoltageStopThreshold = static_cast(config.PowerLimiter_VoltageStopThreshold * 100) / 100.0; config.PowerLimiter_VoltageLoadCorrectionFactor = root[F("voltage_load_correction_factor")].as(); config.PowerLimiter_RestartHour = root[F("inverter_restart_hour")].as(); + config.PowerLimiter_FullSolarPassThroughSoc = root[F("full_solar_passthrough_soc")].as(); + config.PowerLimiter_FullSolarPassThroughStartVoltage = static_cast(root[F("full_solar_passthrough_start_voltage")].as() * 100) / 100.0; + config.PowerLimiter_FullSolarPassThroughStopVoltage = static_cast(root[F("full_solar_passthrough_stop_voltage")].as() * 100) / 100.0; + + + Configuration.write(); PowerLimiter.calcNextInverterRestart(); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index bf1276e5..dcaa4264 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -542,8 +542,13 @@ "PowerMeters": "Leistungsmesser", "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.", "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": "Hinweis: Der Battery SOC (State of charge) -Wert kann nur benutzt werden wenn das Battery CAN Bus Interface aktiviert ist. Wenn die Batterie innerhalb der letzten Minute keine Werte geschickt hat, werden als Fallback-Option die Spannungseinstellungen verwendet.", "InverterIsBehindPowerMeter": "Welchselrichter ist hinter Leistungsmesser", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 6ad73897..682a1309 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -546,8 +546,13 @@ "MqttTopicPowerMeter3": "MQTT topic - Power meter #3 (optional)", "BatterySocStartThreshold": "Battery SOC - Start threshold", "BatterySocStopThreshold": "Battery SOC - Stop threshold", + "BatterySocSolarPassthroughStartThreshold": "Battery SOC - Start threshold for full solar passthrough", + "BatterySocSolarPassthroughStartThresholdHint": "Inverter power is set according to Victron MPPT power (minus efficiency factors) if battery SOC is over this limit. Use this if you like to supply excess power to the grid when battery is full", "VoltageStartThreshold": "DC Voltage - Start threshold", "VoltageStopThreshold": "DC Voltage - Stop threshold", + "VoltageSolarPassthroughStartThreshold": "DC Voltage - Start threshold for full solar passthrough", + "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": "Hint: The battery SOC (State of charge) values can only be used when the Battery CAN Bus interface is enabled. If the battery has not reported any updates of SOC in the last minute, the voltage thresholds will be used as fallback.", "InverterIsBehindPowerMeter": "Inverter is behind Power meter", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 1bf2c09f..1a742f15 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -541,6 +541,46 @@ "ResetConfirm": "Remise à zéro !", "Cancel": "@:maintenancereboot.Cancel" }, + "powerlimiteradmin": { + "PowerLimiterSettings": "Power Limiter Settings", + "PowerLimiterConfiguration": "Power Limiter Configuration", + "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.", + "InverterChannelId": "Channel ID", + "InverterChannelIdHint": "Select proper channel where battery is connected to.", + "TargetPowerConsumption": "Target power consumption from grid", + "TargetPowerConsumptionHint": "Set the grid power consumption the limiter tries to achieve.", + "TargetPowerConsumptionHysteresis": "Hysteresis for power consumption from grid", + "TargetPowerConsumptionHysteresisHint": "Value around which the target grid power consumption fluctuates without readjustment.", + "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)", + "BatterySocStartThreshold": "Battery SOC - Start threshold", + "BatterySocStopThreshold": "Battery SOC - Stop threshold", + "BatterySocSolarPassthroughStartThreshold": "Battery SOC - Start threshold for full solar passthrough", + "BatterySocSolarPassthroughStartThresholdHint": "Inverter power is set according to Victron MPPT power (minus efficiency factors) if battery SOC is over this limit. Use this if you like to supply excess power to the grid when battery is full", + "VoltageStartThreshold": "DC Voltage - Start threshold", + "VoltageStopThreshold": "DC Voltage - Stop threshold", + "VoltageSolarPassthroughStartThreshold": "DC Voltage - Start threshold for full solar passthrough", + "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": "Hint: The battery SOC (State of charge) values can only be used when the Battery CAN Bus interface is enabled. If the battery has not reported any updates of SOC in the last minute, the voltage thresholds will be used as fallback.", + "InverterIsBehindPowerMeter": "Inverter is behind Power meter", + "Battery": "DC / Battery", + "VoltageLoadCorrectionInfo": "Hint: 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).", + "Save": "@:dtuadmin.Save" + }, "login": { "Login": "Connexion", "SystemLogin": "Connexion au système", diff --git a/webapp/src/types/PowerLimiterConfig.ts b/webapp/src/types/PowerLimiterConfig.ts index 81e84ae3..6a826587 100644 --- a/webapp/src/types/PowerLimiterConfig.ts +++ b/webapp/src/types/PowerLimiterConfig.ts @@ -15,4 +15,7 @@ export interface PowerLimiterConfig { voltage_stop_threshold: number; voltage_load_correction_factor: number; inverter_restart_hour: number; + full_solar_passthrough_soc: number; + full_solar_passthrough_start_voltage: number; + full_solar_passthrough_stop_voltage: number; } diff --git a/webapp/src/views/PowerLimiterAdminView.vue b/webapp/src/views/PowerLimiterAdminView.vue index b940102d..441f6aae 100644 --- a/webapp/src/views/PowerLimiterAdminView.vue +++ b/webapp/src/views/PowerLimiterAdminView.vue @@ -152,6 +152,20 @@ +
+ +
+
+ + % +
+
+
+
@@ -178,6 +192,32 @@
+
+ +
+
+ + V +
+
+
+ +
+ +
+
+ + V +
+
+
+