diff --git a/include/Configuration.h b/include/Configuration.h index ddf29ce0f..a925d74de 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -238,13 +238,16 @@ struct CONFIG_T { struct { bool Enabled; + bool VerboseLogging; uint32_t CAN_Controller_Frequency; bool Auto_Power_Enabled; + bool Auto_Power_BatterySoC_Limits_Enabled; bool Emergency_Charge_Enabled; float Auto_Power_Voltage_Limit; float Auto_Power_Enable_Voltage_Limit; float Auto_Power_Lower_Power_Limit; float Auto_Power_Upper_Power_Limit; + uint8_t Auto_Power_Stop_BatterySoC_Threshold; } Huawei; diff --git a/include/defaults.h b/include/defaults.h index 1a4f686c7..7ea99fbde 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -155,5 +155,6 @@ #define HUAWEI_AUTO_POWER_ENABLE_VOLTAGE_LIMIT 42.0 #define HUAWEI_AUTO_POWER_LOWER_POWER_LIMIT 150 #define HUAWEI_AUTO_POWER_UPPER_POWER_LIMIT 2000 +#define HUAWEI_AUTO_POWER_STOP_BATTERYSOC_THRESHOLD 95 #define VERBOSE_LOGGING true diff --git a/src/Configuration.cpp b/src/Configuration.cpp index b216fb2d7..e99f69140 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -214,13 +214,16 @@ bool ConfigurationClass::write() JsonObject huawei = doc.createNestedObject("huawei"); huawei["enabled"] = config.Huawei.Enabled; + huawei["verbose_logging"] = config.Huawei.VerboseLogging; huawei["can_controller_frequency"] = config.Huawei.CAN_Controller_Frequency; huawei["auto_power_enabled"] = config.Huawei.Auto_Power_Enabled; + huawei["auto_power_batterysoc_limits_enabled"] = config.Huawei.Auto_Power_BatterySoC_Limits_Enabled; huawei["emergency_charge_enabled"] = config.Huawei.Emergency_Charge_Enabled; huawei["voltage_limit"] = config.Huawei.Auto_Power_Voltage_Limit; huawei["enable_voltage_limit"] = config.Huawei.Auto_Power_Enable_Voltage_Limit; huawei["lower_power_limit"] = config.Huawei.Auto_Power_Lower_Power_Limit; huawei["upper_power_limit"] = config.Huawei.Auto_Power_Upper_Power_Limit; + huawei["stop_batterysoc_threshold"] = config.Huawei.Auto_Power_Stop_BatterySoC_Threshold; // Serialize JSON to file if (serializeJson(doc, f) == 0) { @@ -463,13 +466,16 @@ bool ConfigurationClass::read() JsonObject huawei = doc["huawei"]; config.Huawei.Enabled = huawei["enabled"] | HUAWEI_ENABLED; + config.Huawei.VerboseLogging = huawei["verbose_logging"] | VERBOSE_LOGGING; config.Huawei.CAN_Controller_Frequency = huawei["can_controller_frequency"] | HUAWEI_CAN_CONTROLLER_FREQUENCY; config.Huawei.Auto_Power_Enabled = huawei["auto_power_enabled"] | false; + config.Huawei.Auto_Power_BatterySoC_Limits_Enabled = huawei["auto_power_batterysoc_limits_enabled"] | false; config.Huawei.Emergency_Charge_Enabled = huawei["emergency_charge_enabled"] | false; config.Huawei.Auto_Power_Voltage_Limit = huawei["voltage_limit"] | HUAWEI_AUTO_POWER_VOLTAGE_LIMIT; config.Huawei.Auto_Power_Enable_Voltage_Limit = huawei["enable_voltage_limit"] | HUAWEI_AUTO_POWER_ENABLE_VOLTAGE_LIMIT; config.Huawei.Auto_Power_Lower_Power_Limit = huawei["lower_power_limit"] | HUAWEI_AUTO_POWER_LOWER_POWER_LIMIT; config.Huawei.Auto_Power_Upper_Power_Limit = huawei["upper_power_limit"] | HUAWEI_AUTO_POWER_UPPER_POWER_LIMIT; + config.Huawei.Auto_Power_Stop_BatterySoC_Threshold = huawei["stop_batterysoc_threshold"] | HUAWEI_AUTO_POWER_STOP_BATTERYSOC_THRESHOLD; f.close(); return true; diff --git a/src/Huawei_can.cpp b/src/Huawei_can.cpp index db464a20a..4c5e42d39 100644 --- a/src/Huawei_can.cpp +++ b/src/Huawei_can.cpp @@ -8,6 +8,7 @@ #include "PowerMeter.h" #include "PowerLimiter.h" #include "Configuration.h" +#include "Battery.h" #include #include @@ -274,6 +275,8 @@ void HuaweiCanClass::loop() return; } + bool verboseLogging = config.Huawei.VerboseLogging; + processReceivedParameters(); uint8_t com_error = HuaweiCanComm.getErrorCode(true); @@ -285,7 +288,7 @@ void HuaweiCanClass::loop() } // Print updated data - if (HuaweiCanComm.gotNewRxDataFrame(false)) { + if (HuaweiCanComm.gotNewRxDataFrame(false) && verboseLogging) { MessageOutput.printf("[HuaweiCanClass::loop] In: %.02fV, %.02fA, %.02fW\n", _rp.input_voltage, _rp.input_current, _rp.input_power); MessageOutput.printf("[HuaweiCanClass::loop] Out: %.02fV, %.02fA of %.02fA, %.02fW\n", _rp.output_voltage, _rp.output_current, _rp.max_output_current, _rp.output_power); MessageOutput.printf("[HuaweiCanClass::loop] Eff : %.01f%%, Temp in: %.01fC, Temp out: %.01fC\n", _rp.efficiency * 100, _rp.input_temp, _rp.output_temp); @@ -382,7 +385,21 @@ void HuaweiCanClass::loop() // Calculate new power limit float newPowerLimit = -1 * round(PowerMeter.getPowerTotal()); newPowerLimit += _rp.output_power; - MessageOutput.printf("[HuaweiCanClass::loop] PL: %f, OP: %f \r\n", newPowerLimit, _rp.output_power); + if (verboseLogging){ + MessageOutput.printf("[HuaweiCanClass::loop] newPowerLimit: %f, output_power: %f \r\n", newPowerLimit, _rp.output_power); + } + + if (config.Battery.Enabled && config.Huawei.Auto_Power_BatterySoC_Limits_Enabled) { + uint8_t _batterySoC = Battery.getStats()->getSoC(); + if (_batterySoC >= config.Huawei.Auto_Power_Stop_BatterySoC_Threshold) { + newPowerLimit = 0; + if (verboseLogging) { + MessageOutput.printf("[HuaweiCanClass::loop] Current battery SoC %i reached " + "stop threshold %i, set newPowerLimit to %f \r\n", _batterySoC, + config.Huawei.Auto_Power_Stop_BatterySoC_Threshold, newPowerLimit); + } + } + } if (newPowerLimit > config.Huawei.Auto_Power_Lower_Power_Limit) { @@ -415,7 +432,9 @@ void HuaweiCanClass::loop() float outputCurrent = std::min(calculatedCurrent, permissableCurrent); outputCurrent= outputCurrent > 0 ? outputCurrent : 0; - MessageOutput.printf("[HuaweiCanClass::loop] Setting output current to %.2fA. This is the lower value of calculated %.2fA and BMS permissable %.2fA currents\r\n", outputCurrent, calculatedCurrent, permissableCurrent); + if (verboseLogging) { + MessageOutput.printf("[HuaweiCanClass::loop] Setting output current to %.2fA. This is the lower value of calculated %.2fA and BMS permissable %.2fA currents\r\n", outputCurrent, calculatedCurrent, permissableCurrent); + } _autoPowerEnabled = true; _setValue(outputCurrent, HUAWEI_ONLINE_CURRENT); diff --git a/src/WebApi_Huawei.cpp b/src/WebApi_Huawei.cpp index d0975ddfc..61d88bfd9 100644 --- a/src/WebApi_Huawei.cpp +++ b/src/WebApi_Huawei.cpp @@ -186,13 +186,16 @@ void WebApiHuaweiClass::onAdminGet(AsyncWebServerRequest* request) const CONFIG_T& config = Configuration.get(); root["enabled"] = config.Huawei.Enabled; + root["verbose_logging"] = config.Huawei.VerboseLogging; root["can_controller_frequency"] = config.Huawei.CAN_Controller_Frequency; root["auto_power_enabled"] = config.Huawei.Auto_Power_Enabled; + root["auto_power_batterysoc_limits_enabled"] = config.Huawei.Auto_Power_BatterySoC_Limits_Enabled; root["emergency_charge_enabled"] = config.Huawei.Emergency_Charge_Enabled; root["voltage_limit"] = static_cast(config.Huawei.Auto_Power_Voltage_Limit * 100) / 100.0; root["enable_voltage_limit"] = static_cast(config.Huawei.Auto_Power_Enable_Voltage_Limit * 100) / 100.0; root["lower_power_limit"] = config.Huawei.Auto_Power_Lower_Power_Limit; root["upper_power_limit"] = config.Huawei.Auto_Power_Upper_Power_Limit; + root["stop_batterysoc_threshold"] = config.Huawei.Auto_Power_Stop_BatterySoC_Threshold; response->setLength(); request->send(response); @@ -253,13 +256,16 @@ void WebApiHuaweiClass::onAdminPost(AsyncWebServerRequest* request) CONFIG_T& config = Configuration.get(); config.Huawei.Enabled = root["enabled"].as(); + config.Huawei.VerboseLogging = root["verbose_logging"]; config.Huawei.CAN_Controller_Frequency = root["can_controller_frequency"].as(); config.Huawei.Auto_Power_Enabled = root["auto_power_enabled"].as(); + config.Huawei.Auto_Power_BatterySoC_Limits_Enabled = root["auto_power_batterysoc_limits_enabled"].as(); config.Huawei.Emergency_Charge_Enabled = root["emergency_charge_enabled"].as(); config.Huawei.Auto_Power_Voltage_Limit = root["voltage_limit"].as(); config.Huawei.Auto_Power_Enable_Voltage_Limit = root["enable_voltage_limit"].as(); config.Huawei.Auto_Power_Lower_Power_Limit = root["lower_power_limit"].as(); config.Huawei.Auto_Power_Upper_Power_Limit = root["upper_power_limit"].as(); + config.Huawei.Auto_Power_Stop_BatterySoC_Threshold = root["stop_batterysoc_threshold"]; WebApi.writeConfig(retMsg); response->setLength(); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 09613822e..009666478 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -835,9 +835,12 @@ "ChargerSettings": "AC Ladegerät Einstellungen", "Configuration": "AC Ladegerät Konfiguration", "EnableHuawei": "Huawei R4850G2 an CAN Bus Interface aktiv", + "VerboseLogging": "@:base.VerboseLogging", "CanControllerFrequency": "Frequenz des Quarzes am CAN Controller", "EnableAutoPower": "Automatische Leistungssteuerung", + "EnableBatterySoCLimits": "Ladezustand einer angeschlossenen Batterie berücksichtigen", "Limits": "Limits", + "BatterySoCLimits": "Batterie SoC-Limits", "VoltageLimit": "Ladespannungslimit", "enableVoltageLimit": "Start Spannungslimit", "stopVoltageLimitHint": "Maximal Spannung des Ladegeräts. Entspricht der geünschten Ladeschlussspannung der Batterie. Verwendet für die Automatische Leistungssteuerung und beim Notfallladen", @@ -845,6 +848,8 @@ "maxPowerLimitHint": "Maximale Ausgangsleistung. Verwendet für die Automatische Leistungssteuerung und beim Notfallladen", "lowerPowerLimit": "Minimale Leistung", "upperPowerLimit": "Maximale Leistung", + "StopBatterySoCThreshold": "Laden bei SoC beenden", + "StopBatterySoCThresholdHint": "Zur Verlängerung der Akku-Lebensdauer kann der Ladevorgang bei einem bestimmten SoC gestoppt werden.\nHinweis: Manche LiFePO-Akkus müssen gelegentlich voll geladen werden, um die SoC-Anzeige akkurat zu halten.", "Seconds": "@:base.Seconds", "EnableEmergencyCharge": "Notfallladen: Batterie wird mit maximaler Leistung geladen wenn durch das Batterie BMS angefordert" }, diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 5ffac8c5e..47727645e 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -842,9 +842,12 @@ "ChargerSettings": "AC Charger Settings", "Configuration": "AC Charger Configuration", "EnableHuawei": "Enable Huawei R4850G2 on CAN Bus Interface", + "VerboseLogging": "@:base.VerboseLogging", "CanControllerFrequency": "CAN controller quarz frequency", "EnableAutoPower": "Automatic power control", + "EnableBatterySoCLimits": "Use SoC data of a connected battery", "Limits": "Limits", + "BatterySoCLimits": "Battery SoC Limits", "VoltageLimit": "Charge Voltage limit", "enableVoltageLimit": "Re-enable voltage limit", "stopVoltageLimitHint": "Maximum charger voltage. Equals battery charge voltage limit. Used for automatic power control and when emergency charging", @@ -852,6 +855,8 @@ "maxPowerLimitHint": "Maximum output power. Used for automatic power control and when emergency charging", "lowerPowerLimit": "Minimum output power", "upperPowerLimit": "Maximum output power", + "StopBatterySoCThreshold": "Stop charging at SoC", + "StopBatterySoCThresholdHint": "To prolong the battery's lifespan, charging can be stopped at a certain SoC level.\nHint: In order to keep the SoC reading accurate, some LiFePO cells must be charged to full capacity regularly.", "Seconds": "@:base.Seconds", "EnableEmergencyCharge": "Emergency charge. Battery charged with maximum power if requested by Battery BMS" }, diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 519132bff..7bf30bbee 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -833,9 +833,12 @@ "ChargerSettings": "AC Charger Settings", "Configuration": "AC Charger Configuration", "EnableHuawei": "Enable Huawei R4850G2 on CAN Bus Interface", + "VerboseLogging": "@:base.VerboseLogging", "CanControllerFrequency": "CAN controller quarz frequency", "EnableAutoPower": "Automatic power control", + "EnableBatterySoCLimits": "Use SoC data of a connected battery", "Limits": "Limits", + "BatterySoCLimits": "Battery SoC Limits", "VoltageLimit": "Charge Voltage limit", "enableVoltageLimit": "Re-enable voltage limit", "stopVoltageLimitHint": "Maximum charger voltage. Equals battery charge voltage limit. Used for automatic power control and when emergency charging", @@ -843,6 +846,8 @@ "maxPowerLimitHint": "Maximum output power. Used for automatic power control and when emergency charging", "lowerPowerLimit": "Minimum output power", "upperPowerLimit": "Maximum output power", + "StopBatterySoCThreshold": "Stop charging at SoC", + "StopBatterySoCThresholdHint": "To prolong the battery's lifespan, charging can be stopped at a certain SoC level.\nHint: In order to keep the SoC reading accurate, some LiFePO cells must be charged to full capacity regularly.", "Seconds": "@:base.Seconds", "EnableEmergencyCharge": "Emergency charge. Battery charged with maximum power if requested by Battery BMS" }, diff --git a/webapp/src/types/AcChargerConfig.ts b/webapp/src/types/AcChargerConfig.ts index e80a65aaa..9dce2f874 100644 --- a/webapp/src/types/AcChargerConfig.ts +++ b/webapp/src/types/AcChargerConfig.ts @@ -1,10 +1,13 @@ export interface AcChargerConfig { enabled: boolean; + verbose_logging: boolean; can_controller_frequency: number; auto_power_enabled: boolean; + auto_power_batterysoc_limits_enabled: boolean; voltage_limit: number; enable_voltage_limit: number; lower_power_limit: number; upper_power_limit: number; emergency_charge_enabled: boolean; + stop_batterysoc_threshold: number; } diff --git a/webapp/src/views/AcChargerAdminView.vue b/webapp/src/views/AcChargerAdminView.vue index 4f811d26f..1feac505c 100644 --- a/webapp/src/views/AcChargerAdminView.vue +++ b/webapp/src/views/AcChargerAdminView.vue @@ -23,11 +23,21 @@ + + + + + +
+ +
+
+ + % +
+
+
+