From 17fd33c4d1994cda58870007fea70aa69a747e7b Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Fri, 16 Jun 2023 08:57:17 +0200 Subject: [PATCH 1/6] Float transition - Voltage drop per second --- etc/dbus-serialbattery/battery.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index b4b4623b..01ef336c 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -352,14 +352,17 @@ def manage_charge_voltage_linear(self) -> None: chargeMode = "Float Transition" elif self.charge_mode.startswith("Float Transition"): elapsed_time = int(time()) - self.transition_start_time - # Duration in seconds for smooth voltage drop from absorption to float - # depending on the number of cells - FLOAT_MODE_TRANSITION_DURATION = self.cell_count * 12 - t = min(1, elapsed_time / FLOAT_MODE_TRANSITION_DURATION) + # Voltage drop per second + VOLTAGE_DROP_PER_SECOND = 0.01 / 10 + voltage_drop = min( + VOLTAGE_DROP_PER_SECOND * elapsed_time, + self.initial_control_voltage - floatVoltage, + ) self.control_voltage = ( - 1 - t - ) * self.initial_control_voltage + t * floatVoltage - if t == 1: + self.initial_control_voltage - voltage_drop + ) + if self.control_voltage <= floatVoltage: + self.control_voltage = floatVoltage chargeMode = "Float" else: chargeMode = "Float Transition" From 605801a758405e1139f782ffeb014a401c23b69e Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Fri, 16 Jun 2023 12:41:35 +0200 Subject: [PATCH 2/6] Validate setting of FLOAT_CELL_VOLTAGE and avoid misconfiguration --- etc/dbus-serialbattery/utils.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 0e49af52..7b9fc235 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -55,6 +55,16 @@ def _get_list_from_config( MAX_CELL_VOLTAGE = float(config["DEFAULT"]["MAX_CELL_VOLTAGE"]) # Max voltage can seen as absorption voltage FLOAT_CELL_VOLTAGE = float(config["DEFAULT"]["FLOAT_CELL_VOLTAGE"]) +if FLOAT_CELL_VOLTAGE > MAX_CELL_VOLTAGE: + FLOAT_CELL_VOLTAGE = MAX_CELL_VOLTAGE + logger.error( + ">>> ERROR: FLOAT_CELL_VOLTAGE is set to a value greater than MAX_CELL_VOLTAGE. Please check the configuration." + ) +if FLOAT_CELL_VOLTAGE < MIN_CELL_VOLTAGE: + FLOAT_CELL_VOLTAGE = MIN_CELL_VOLTAGE + logger.error( + ">>> ERROR: FLOAT_CELL_VOLTAGE is set to a value less than MAX_CELL_VOLTAGE. Please check the configuration." + ) # --------- BMS disconnect behaviour --------- # Description: Block charge and discharge when the communication to the BMS is lost. If you are removing the From abd69153a2445f8d6633dbad03a7c6308528a5b5 Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Fri, 16 Jun 2023 21:07:16 +0200 Subject: [PATCH 3/6] consider utils.LINEAR_RECALCULATION_EVERY to refresh CVL --- etc/dbus-serialbattery/battery.py | 32 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 01ef336c..14ab9b62 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -108,7 +108,6 @@ def init_values(self): self.min_battery_voltage = None self.allow_max_voltage = True self.max_voltage_start_time = None - self.transition_start_time = None self.control_voltage_at_transition_start = None self.charge_mode = None self.charge_limitation = None @@ -347,25 +346,28 @@ def manage_charge_voltage_linear(self) -> None: chargeMode = "Float" if self.control_voltage: if not self.charge_mode.startswith("Float"): - self.transition_start_time = int(time()) + self.linear_cvl_last_set = int(time()) self.initial_control_voltage = self.control_voltage chargeMode = "Float Transition" elif self.charge_mode.startswith("Float Transition"): - elapsed_time = int(time()) - self.transition_start_time + current_time = int(time()) + elapsed_time = current_time - self.linear_cvl_last_set # Voltage drop per second VOLTAGE_DROP_PER_SECOND = 0.01 / 10 - voltage_drop = min( - VOLTAGE_DROP_PER_SECOND * elapsed_time, - self.initial_control_voltage - floatVoltage, - ) - self.control_voltage = ( - self.initial_control_voltage - voltage_drop - ) - if self.control_voltage <= floatVoltage: - self.control_voltage = floatVoltage - chargeMode = "Float" - else: - chargeMode = "Float Transition" + if elapsed_time >= utils.LINEAR_RECALCULATION_EVERY: + voltage_drop = min( + VOLTAGE_DROP_PER_SECOND * elapsed_time, + self.initial_control_voltage - floatVoltage, + ) + self.control_voltage = ( + self.initial_control_voltage - voltage_drop + ) + self.linear_cvl_last_set = current_time + if self.control_voltage <= floatVoltage: + self.control_voltage = floatVoltage + chargeMode = "Float" + else: + chargeMode = "Float Transition" else: self.control_voltage = floatVoltage self.charge_mode = chargeMode From 5f9225b63d69f6ce459a3ab56edb3e4190d822e0 Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Sat, 17 Jun 2023 15:08:05 +0200 Subject: [PATCH 4/6] consider utils.LINEAR_RECALCULATION_EVERY to refresh CVL --- etc/dbus-serialbattery/battery.py | 37 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 14ab9b62..c0c22a11 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -108,6 +108,7 @@ def init_values(self): self.min_battery_voltage = None self.allow_max_voltage = True self.max_voltage_start_time = None + self.transition_start_time = None self.control_voltage_at_transition_start = None self.charge_mode = None self.charge_limitation = None @@ -346,28 +347,24 @@ def manage_charge_voltage_linear(self) -> None: chargeMode = "Float" if self.control_voltage: if not self.charge_mode.startswith("Float"): - self.linear_cvl_last_set = int(time()) + self.transition_start_time = int(time()) self.initial_control_voltage = self.control_voltage chargeMode = "Float Transition" elif self.charge_mode.startswith("Float Transition"): current_time = int(time()) - elapsed_time = current_time - self.linear_cvl_last_set + elapsed_time = current_time - self.transition_start_time # Voltage drop per second VOLTAGE_DROP_PER_SECOND = 0.01 / 10 - if elapsed_time >= utils.LINEAR_RECALCULATION_EVERY: - voltage_drop = min( - VOLTAGE_DROP_PER_SECOND * elapsed_time, - self.initial_control_voltage - floatVoltage, - ) - self.control_voltage = ( - self.initial_control_voltage - voltage_drop - ) - self.linear_cvl_last_set = current_time - if self.control_voltage <= floatVoltage: - self.control_voltage = floatVoltage - chargeMode = "Float" - else: - chargeMode = "Float Transition" + voltage_drop = min( + VOLTAGE_DROP_PER_SECOND * elapsed_time, + self.initial_control_voltage - floatVoltage, + ) + self.set_cvl_linear(self.initial_control_voltage - voltage_drop) + if self.control_voltage <= floatVoltage: + self.control_voltage = floatVoltage + chargeMode = "Float" + else: + chargeMode = "Float Transition" else: self.control_voltage = floatVoltage self.charge_mode = chargeMode @@ -385,6 +382,14 @@ def manage_charge_voltage_linear(self) -> None: self.control_voltage = None self.charge_mode = "--" + def set_cvl_linear(self, control_voltage) -> bool: + current_time = int(time()) + if utils.LINEAR_RECALCULATION_EVERY <= current_time - self.linear_cvl_last_set: + self.control_voltage = control_voltage + self.linear_cvl_last_set = current_time + return True + return False + def manage_charge_voltage_step(self) -> None: """ manages the charge voltage using a step function by setting self.control_voltage From 5a5743b8e3c904fd92c611aeaa398a99d578bbe4 Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Sat, 17 Jun 2023 15:43:45 +0200 Subject: [PATCH 5/6] small refactor, introduced set_cvl_linear function to set CVL only once every LINEAR_RECALCULATION_EVERY seconds --- etc/dbus-serialbattery/battery.py | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index c0c22a11..aaedb5d0 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -296,24 +296,18 @@ def manage_charge_voltage_linear(self) -> None: # INFO: battery will only switch to Absorption, if all cells are balanced. # Reach MAX_CELL_VOLTAGE * cell count if they are all balanced. if foundHighCellVoltage and self.allow_max_voltage: - # set CVL only once every LINEAR_RECALCULATION_EVERY seconds - if ( - int(time()) - self.linear_cvl_last_set - >= utils.LINEAR_RECALCULATION_EVERY - ): - self.linear_cvl_last_set = int(time()) - - # Keep penalty above min battery voltage and below max battery voltage - self.control_voltage = round( - min( - max( - voltageSum - penaltySum, - self.min_battery_voltage, - ), - self.max_battery_voltage, + # Keep penalty above min battery voltage and below max battery voltage + control_voltage = round( + min( + max( + voltageSum - penaltySum, + self.min_battery_voltage, ), - 3, - ) + self.max_battery_voltage, + ), + 3, + ) + self.set_cvl_linear(control_voltage) self.charge_mode = ( "Bulk dynamic" @@ -383,6 +377,10 @@ def manage_charge_voltage_linear(self) -> None: self.charge_mode = "--" def set_cvl_linear(self, control_voltage) -> bool: + """ + et CVL only once every LINEAR_RECALCULATION_EVERY seconds + :return: bool + """ current_time = int(time()) if utils.LINEAR_RECALCULATION_EVERY <= current_time - self.linear_cvl_last_set: self.control_voltage = control_voltage From f45fb41f5c71fd7ecab3679b1e61112f88178638 Mon Sep 17 00:00:00 2001 From: Oleg Gurevich Date: Sat, 17 Jun 2023 15:47:46 +0200 Subject: [PATCH 6/6] fix typo --- etc/dbus-serialbattery/battery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index aaedb5d0..c43b8360 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -378,7 +378,7 @@ def manage_charge_voltage_linear(self) -> None: def set_cvl_linear(self, control_voltage) -> bool: """ - et CVL only once every LINEAR_RECALCULATION_EVERY seconds + set CVL only once every LINEAR_RECALCULATION_EVERY seconds :return: bool """ current_time = int(time())