From 3153962aaa924065ad24ef2992545c8c0b3c53b6 Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Mon, 1 May 2023 09:24:24 +0000 Subject: [PATCH 01/11] black reformatting --- etc/dbus-serialbattery/bms/daly.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/etc/dbus-serialbattery/bms/daly.py b/etc/dbus-serialbattery/bms/daly.py index 16fef5dd..917b1aa0 100644 --- a/etc/dbus-serialbattery/bms/daly.py +++ b/etc/dbus-serialbattery/bms/daly.py @@ -285,8 +285,8 @@ def read_cells_volts(self, ser): # logger.warning("data " + bytes(cells_volts_data).hex()) - while ( - bufIdx <= len(cells_volts_data) - (4 + 8 + 1) + while bufIdx <= len(cells_volts_data) - ( + 4 + 8 + 1 ): # we at least need 13 bytes to extract the identifiers + 8 bytes payload + checksum b1, b2, b3, b4 = unpack_from(">BBBB", cells_volts_data, bufIdx) if b1 == 0xA5 and b2 == 0x01 and b3 == 0x95 and b4 == 0x08: @@ -313,7 +313,7 @@ def read_cells_volts(self, ser): ) bufIdx += 13 # BBBBBhhhBB -> 13 byte else: - bufIdx += 1 # step through buffer to find valid start + bufIdx += 1 # step through buffer to find valid start logger.warning("bad cell voltages header") return True @@ -409,20 +409,22 @@ def read_serial_data_daly(self, ser, command): if len(data) <= 12: logger.debug("Too short reply to cmd " + bytes(command).hex()) - return False; + return False # search sentence start try: idx = data.index(0xA5) except ValueError: - logger.debug("No Sentence Start found for reply to cmd " + bytes(command).hex()) + logger.debug( + "No Sentence Start found for reply to cmd " + bytes(command).hex() + ) return False if len(data[idx:]) <= 12: logger.debug("Too short reply to cmd " + bytes(command).hex()) - return False; + return False - if data[12+idx] != sum(data[idx:12+idx]) & 0xFF: + if data[12 + idx] != sum(data[idx : 12 + idx]) & 0xFF: logger.debug("Bad checksum in reply to cmd " + bytes(command).hex()) return False @@ -431,7 +433,12 @@ def read_serial_data_daly(self, ser, command): if length == 8: return data[4 + idx : length + 4 + idx] else: - logger.debug(">>> ERROR: Incorrect Reply to CMD " + bytes(command).hex() + ": 0x" + bytes(data).hex()) + logger.debug( + ">>> ERROR: Incorrect Reply to CMD " + + bytes(command).hex() + + ": 0x" + + bytes(data).hex() + ) return False # Read data from previously openned serial port @@ -510,4 +517,4 @@ def read_serialport_data( except Exception as e: logger.error(e) - return False \ No newline at end of file + return False From 84556e8b2c756baac6bb655819e48f0ce63baf7c Mon Sep 17 00:00:00 2001 From: Manuel Date: Wed, 3 May 2023 10:44:50 +0200 Subject: [PATCH 02/11] updated changelog --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ea31c2..04d78dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,12 @@ ## v1.0.0-jkbms_ble +### ATTENTION: Breaking changes! The config is now done in the `config.ini`. All values from the `utils.py` gets lost. The changes in the `config.ini` will persists future updates. + +* Added: `self.unique_identifier` to the battery class. Used to identify a BMS when multiple BMS are connected - planned for future use by @mr-manuel * Added: Balancing status for JKBMS by @mr-manuel * Added: Balancing switch status for JKBMS by @mr-manuel * Added: Balancing switch status to the GUI -> SerialBattery -> IO by @mr-manuel -* Added: `self.unique_identifier` to the battery class. Used to identify a BMS when multiple BMS are connected - planned for future use by @mr-manuel * Added: Charge Mode display by @mr-manuel * Added: Choose how battery temperature is assembled (mean temp 1 & 2, only temp 1 or only temp 2) by @mr-manuel * Added: Config file by @ppuetsch @@ -25,8 +27,8 @@ * Added: JKBMS BLE - MOS temperature by @mr-manuel * Added: JKBMS BLE - Show if balancing is active and which cells are balancing by @mr-manuel * Added: Post install notes by @mr-manuel -* Added: Recalculation interval in linear mode for CVL, CCL and DCL by @mr-manuel * Added: Read charge/discharge limits from JKBMS by @mr-manuel +* Added: Recalculation interval in linear mode for CVL, CCL and DCL by @mr-manuel * Added: Script to install directly from repository by @mr-manuel * Added: Show charge mode (absorption, bulk, ...) in Parameters page by @mr-manuel * Added: Show charge/discharge limitation reason by @mr-manuel From 56fecf3125bd7bdec195bc6c7f3ce6c1ac24e2bb Mon Sep 17 00:00:00 2001 From: Manuel Date: Wed, 3 May 2023 15:25:43 +0200 Subject: [PATCH 03/11] Small fixes --- etc/dbus-serialbattery/bms/lltjbd.py | 2 +- etc/dbus-serialbattery/reinstall-local.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/dbus-serialbattery/bms/lltjbd.py b/etc/dbus-serialbattery/bms/lltjbd.py index 8b34c920..a74697cc 100644 --- a/etc/dbus-serialbattery/bms/lltjbd.py +++ b/etc/dbus-serialbattery/bms/lltjbd.py @@ -158,7 +158,7 @@ def read_gen_data(self): ) = unpack_from(">HhHHHHhHHBBBBB", gen_data) self.voltage = voltage / 100 self.current = current / 100 - self.soc = round(100 * capacity_remain / capacity, 0) + self.soc = round(100 * capacity_remain / capacity, 2) self.capacity_remain = capacity_remain / 100 self.capacity = capacity / 100 self.to_cell_bits(balance, balance2) diff --git a/etc/dbus-serialbattery/reinstall-local.sh b/etc/dbus-serialbattery/reinstall-local.sh index aba7436a..c9ee661d 100755 --- a/etc/dbus-serialbattery/reinstall-local.sh +++ b/etc/dbus-serialbattery/reinstall-local.sh @@ -63,7 +63,7 @@ fi ### BLUETOOTH PART | START ### # get BMS list from config file -bluetooth_bms=$(awk -F "=" '/BLUETOOTH_BMS/ {print $2}' /data/etc/dbus-serialbattery/config.ini) +bluetooth_bms=$(awk -F "=" '/^BLUETOOTH_BMS/ {print $2}' /data/etc/dbus-serialbattery/config.ini) #echo $bluetooth_bms # clear whitespaces From bbb7b1bfb26c9dc1afb17bb51ca085585b0cc586 Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Wed, 3 May 2023 20:23:32 +0000 Subject: [PATCH 04/11] fix disconnection behaviour: on disconnect, show '---' after 10s and 'not connected' after 60s --- etc/dbus-serialbattery/battery.py | 121 ++++++++++++++++++--------- etc/dbus-serialbattery/dbushelper.py | 25 ++++-- 2 files changed, 100 insertions(+), 46 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 6b40846a..68e6e77b 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -62,8 +62,15 @@ def __init__(self, port, baud, address): self.type = "Generic" self.poll_interval = 1000 self.online = True - self.hardware_version = None + self.cell_count = None + + self.init_values() + + # used to identify a BMS when multiple BMS are connected - planned for future use + self.unique_identifier = None + + def init_values(self): self.voltage = None self.current = None self.capacity_remain = None @@ -78,7 +85,6 @@ def __init__(self, port, baud, address): self.charge_fet = None self.discharge_fet = None self.balance_fet = None - self.cell_count = None self.temp_sensors = None self.temp1 = None self.temp2 = None @@ -103,9 +109,6 @@ def __init__(self, port, baud, address): self.max_battery_charge_current = None self.max_battery_discharge_current = None - # used to identify a BMS when multiple BMS are connected - planned for future use - self.unique_identifier = None - @abstractmethod def test_connection(self) -> bool: """ @@ -306,12 +309,20 @@ def manage_charge_current(self) -> None: # Manage Charge Current Limitations charge_limits = [ self.max_battery_charge_current + if self.max_battery_charge_current is not None + else 0 ] # gets removed after finished testing - charge_limits_new = {self.max_battery_charge_current: "None (Max Config Limit)"} + charge_limits_new = { + self.max_battery_charge_current + if self.max_battery_charge_current is not None + else 0: "None (Max Config Limit)" + } if utils.CCCM_CV_ENABLE: tmp = self.calcMaxChargeCurrentReferringToCellVoltage() - charge_limits.append(tmp) # gets removed after finished testing + charge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_charge_current: " # + str(self.max_battery_charge_current) @@ -327,7 +338,9 @@ def manage_charge_current(self) -> None: if utils.CCCM_T_ENABLE: tmp = self.calcMaxChargeCurrentReferringToTemperature() - charge_limits.append(tmp) # gets removed after finished testing + charge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_charge_current: " # + str(self.max_battery_charge_current) @@ -341,7 +354,9 @@ def manage_charge_current(self) -> None: if utils.CCCM_SOC_ENABLE: tmp = self.calcMaxChargeCurrentReferringToSoc() - charge_limits.append(tmp) # gets removed after finished testing + charge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_charge_current: " # + str(self.max_battery_charge_current) @@ -372,14 +387,20 @@ def manage_charge_current(self) -> None: # Manage Discharge Current Limitations discharge_limits = [ self.max_battery_discharge_current + if self.max_battery_discharge_current is not None + else 0 ] # gets removed after finished testing discharge_limits_new = { - self.max_battery_discharge_current: "None (Max Config Limit)" + self.max_battery_discharge_current + if self.max_battery_discharge_current is not None + else 0: "None (Max Config Limit)" } if utils.DCCM_CV_ENABLE: tmp = self.calcMaxDischargeCurrentReferringToCellVoltage() - discharge_limits.append(tmp) # gets removed after finished testing + discharge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_discharge_current: " # + str(self.max_battery_discharge_current) @@ -395,7 +416,9 @@ def manage_charge_current(self) -> None: if utils.DCCM_T_ENABLE: tmp = self.calcMaxDischargeCurrentReferringToTemperature() - discharge_limits.append(tmp) # gets removed after finished testing + discharge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_discharge_current: " # + str(self.max_battery_discharge_current) @@ -411,7 +434,9 @@ def manage_charge_current(self) -> None: if utils.DCCM_SOC_ENABLE: tmp = self.calcMaxDischargeCurrentReferringToSoc() - discharge_limits.append(tmp) # gets removed after finished testing + discharge_limits.append( + tmp if tmp is not None else 0 + ) # gets removed after finished testing # logging.error("self.max_battery_discharge_current: " # + str(self.max_battery_discharge_current) @@ -772,43 +797,61 @@ def extract_from_temp_values(self, extractor) -> Union[float, None]: return None def get_temp(self) -> Union[float, None]: - if utils.TEMP_BATTERY == 1: - return self.temp1 - elif utils.TEMP_BATTERY == 2: - return self.temp2 - else: - return self.extract_from_temp_values( - extractor=lambda temp1, temp2: round( - (float(temp1) + float(temp2)) / 2, 2 + try: + if utils.TEMP_BATTERY == 1: + return self.temp1 + elif utils.TEMP_BATTERY == 2: + return self.temp2 + else: + return self.extract_from_temp_values( + extractor=lambda temp1, temp2: round( + (float(temp1) + float(temp2)) / 2, 2 + ) ) - ) + except: + return None def get_min_temp(self) -> Union[float, None]: - return self.extract_from_temp_values( - extractor=lambda temp1, temp2: min(temp1, temp2) - ) + try: + return self.extract_from_temp_values( + extractor=lambda temp1, temp2: min(temp1, temp2) + ) + except: + return None def get_min_temp_id(self) -> Union[str, None]: - if self.temp1 < self.temp2: - return utils.TEMP_1_NAME - else: - return utils.TEMP_2_NAME + try: + if self.temp1 < self.temp2: + return utils.TEMP_1_NAME + else: + return utils.TEMP_2_NAME + except: + return None def get_max_temp(self) -> Union[float, None]: - return self.extract_from_temp_values( - extractor=lambda temp1, temp2: max(temp1, temp2) - ) + try: + return self.extract_from_temp_values( + extractor=lambda temp1, temp2: max(temp1, temp2) + ) + except: + return None def get_max_temp_id(self) -> Union[str, None]: - if self.temp1 > self.temp2: - return utils.TEMP_1_NAME - else: - return utils.TEMP_2_NAME + try: + if self.temp1 > self.temp2: + return utils.TEMP_1_NAME + else: + return utils.TEMP_2_NAME + except: + return None def get_mos_temp(self) -> Union[float, None]: - if self.temp_mos is not None: - return self.temp_mos - else: + try: + if self.temp_mos is not None: + return self.temp_mos + else: + return None + except: return None def log_cell_data(self) -> bool: diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index 246a1aad..578ab782 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -332,6 +332,8 @@ def publish_battery(self, loop): # If the battery is offline for more than 10 polls (polled every second for most batteries) if self.error_count >= 10: self.battery.online = False + self.battery.init_values() + # Has it completely failed if self.error_count >= 60: loop.quit() @@ -352,11 +354,19 @@ def publish_battery(self, loop): def publish_dbus(self): # Update SOC, DC and System items self._dbusservice["/System/NrOfCellsPerBattery"] = self.battery.cell_count - self._dbusservice["/Soc"] = round(self.battery.soc, 2) - self._dbusservice["/Dc/0/Voltage"] = round(self.battery.voltage, 2) - self._dbusservice["/Dc/0/Current"] = round(self.battery.current, 2) - self._dbusservice["/Dc/0/Power"] = round( - self.battery.voltage * self.battery.current, 2 + self._dbusservice["/Soc"] = ( + round(self.battery.soc, 2) if self.battery.soc is not None else None + ) + self._dbusservice["/Dc/0/Voltage"] = ( + round(self.battery.voltage, 2) if self.battery.voltage is not None else None + ) + self._dbusservice["/Dc/0/Current"] = ( + round(self.battery.current, 2) if self.battery.current is not None else None + ) + self._dbusservice["/Dc/0/Power"] = ( + round(self.battery.voltage * self.battery.current, 2) + if self.battery.current is not None and self.battery.current is not None + else None ) self._dbusservice["/Dc/0/Temperature"] = self.battery.get_temp() self._dbusservice["/Capacity"] = self.battery.get_capacity_remain() @@ -540,5 +550,6 @@ def publish_dbus(self): except: pass - logger.debug("logged to dbus [%s]" % str(round(self.battery.soc, 2))) - self.battery.log_cell_data() + if self.battery.soc is not None: + logger.debug("logged to dbus [%s]" % str(round(self.battery.soc, 2))) + self.battery.log_cell_data() From d647b1e62593da9145df1895897852b9217998ee Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Wed, 3 May 2023 21:13:35 +0000 Subject: [PATCH 05/11] fix flake errors --- etc/dbus-serialbattery/battery.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index cf269c96..44275371 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -798,7 +798,7 @@ def get_temp(self) -> Union[float, None]: (float(temp1) + float(temp2)) / 2, 2 ) ) - except: + except TypeError: return None def get_min_temp(self) -> Union[float, None]: @@ -806,7 +806,7 @@ def get_min_temp(self) -> Union[float, None]: return self.extract_from_temp_values( extractor=lambda temp1, temp2: min(temp1, temp2) ) - except: + except TypeError: return None def get_min_temp_id(self) -> Union[str, None]: @@ -815,7 +815,7 @@ def get_min_temp_id(self) -> Union[str, None]: return utils.TEMP_1_NAME else: return utils.TEMP_2_NAME - except: + except TypeError: return None def get_max_temp(self) -> Union[float, None]: @@ -823,7 +823,7 @@ def get_max_temp(self) -> Union[float, None]: return self.extract_from_temp_values( extractor=lambda temp1, temp2: max(temp1, temp2) ) - except: + except TypeError: return None def get_max_temp_id(self) -> Union[str, None]: @@ -832,16 +832,13 @@ def get_max_temp_id(self) -> Union[str, None]: return utils.TEMP_1_NAME else: return utils.TEMP_2_NAME - except: + except TypeError: return None def get_mos_temp(self) -> Union[float, None]: - try: - if self.temp_mos is not None: - return self.temp_mos - else: - return None - except: + if self.temp_mos is not None: + return self.temp_mos + else: return None def log_cell_data(self) -> bool: From 8ed42ae7d6726d09ec6f1f85d2434f3a7a52c967 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 08:31:51 +0200 Subject: [PATCH 06/11] small fix --- CHANGELOG.md | 1 + etc/dbus-serialbattery/restart-driver.sh | 2 +- etc/dbus-serialbattery/utils.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d78dac..f32c1dc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ * Added: Post install notes by @mr-manuel * Added: Read charge/discharge limits from JKBMS by @mr-manuel * Added: Recalculation interval in linear mode for CVL, CCL and DCL by @mr-manuel +* Added: Reset values to None, if battery goes offline (not reachable for 10s) by @transistorgit * Added: Script to install directly from repository by @mr-manuel * Added: Show charge mode (absorption, bulk, ...) in Parameters page by @mr-manuel * Added: Show charge/discharge limitation reason by @mr-manuel diff --git a/etc/dbus-serialbattery/restart-driver.sh b/etc/dbus-serialbattery/restart-driver.sh index 59b0b5cd..853a8b97 100755 --- a/etc/dbus-serialbattery/restart-driver.sh +++ b/etc/dbus-serialbattery/restart-driver.sh @@ -14,7 +14,7 @@ pkill -f "python .*/$DRIVERNAME.py" # get BMS list from config file -bluetooth_bms=$(awk -F "=" '/BLUETOOTH_BMS/ {print $2}' /data/etc/dbus-serialbattery/config.ini) +bluetooth_bms=$(awk -F "=" '/^BLUETOOTH_BMS/ {print $2}' /data/etc/dbus-serialbattery/config.ini) # clear whitespaces bluetooth_bms_clean="$(echo $bluetooth_bms | sed 's/\s*,\s*/,/g')" # split into array diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 74d6e58a..9a4e3fd0 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -36,7 +36,7 @@ def _get_list_from_config( # Constants - Need to dynamically get them in future DRIVER_VERSION = "1.0" -DRIVER_SUBVERSION = ".0-jkbms_ble (20230503)" +DRIVER_SUBVERSION = ".0-jkbms_ble (20230504)" zero_char = chr(48) degree_sign = "\N{DEGREE SIGN}" From 77fc2127f1272423394d54667ed6ee4b17fefe01 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 11:47:11 +0200 Subject: [PATCH 07/11] Added: apply max voltage if CVCM_ENABLE is False before float voltage was applied --- CHANGELOG.md | 7 ++--- etc/dbus-serialbattery/battery.py | 12 ++++++--- etc/dbus-serialbattery/config.default.ini | 33 ++++++++++++++--------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f32c1dc3..78d8f234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### ATTENTION: Breaking changes! The config is now done in the `config.ini`. All values from the `utils.py` gets lost. The changes in the `config.ini` will persists future updates. * Added: `self.unique_identifier` to the battery class. Used to identify a BMS when multiple BMS are connected - planned for future use by @mr-manuel +* Added: Apply max voltage, if `CVCM_ENABLE` is `False`. Before float voltage was applied by @mr-manuel * Added: Balancing status for JKBMS by @mr-manuel * Added: Balancing switch status for JKBMS by @mr-manuel * Added: Balancing switch status to the GUI -> SerialBattery -> IO by @mr-manuel @@ -17,8 +18,8 @@ * Added: Driver uninstall script by @mr-manuel * Added: Fix for Venus OS >= v3.00~14 showing unused items https://github.com/Louisvdw/dbus-serialbattery/issues/469 by @mr-manuel * Added: HighInternalTemperature alarm (MOSFET) for JKBMS by @mr-manuel -* Added: Install needed components automatically after a Venus OS upgrade by @mr-manuel -* Added: JKBMS - MOS temperature https://github.com/Louisvdw/dbus-serialbattery/pull/440 by @mr-manuel +* Added: Install needed Bluetooth components automatically after a Venus OS upgrade by @mr-manuel +* Added: JKBMS - MOS temperature https://github.com/Louisvdw/dbus-serialbattery/pull/440 by @baphomett * Added: JKBMS BLE - Balancing switch status by @mr-manuel * Added: JKBMS BLE - Capacity by @mr-manuel * Added: JKBMS BLE - Cell imbalance alert by @mr-manuel @@ -73,4 +74,4 @@ * Changed: Temperature alarm changed in order to not trigger all in the same condition for JKBMS by @mr-manuel * Changed: Time-To-Soc repetition from cycles to seconds. Minimum value is every 5 seconds. This prevents CPU overload and ensures system stability. Renamed `TIME_TO_SOC_LOOP_CYCLES` to `TIME_TO_SOC_RECALCULATE_EVERY` by @mr-manuel * Changed: Time-To-Soc string from `days, HR:MN:SC` to `d h m s` (same as Time-To-Go) by @mr-manuel -* Changed: Uninstall also installed Bluetooth modules on uninstall. by @mr-manuel +* Changed: Uninstall also installed Bluetooth modules on uninstall by @mr-manuel diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 44275371..c1f4686b 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -165,10 +165,15 @@ def manage_charge_voltage(self) -> None: manages the charge voltage by setting self.control_voltage :return: None """ - if utils.LINEAR_LIMITATION_ENABLE: - self.manage_charge_voltage_linear() + if utils.CVCM_ENABLE: + if utils.LINEAR_LIMITATION_ENABLE: + self.manage_charge_voltage_linear() + else: + self.manage_charge_voltage_step() + # on CVCM_ENABLE = False apply max voltage else: - self.manage_charge_voltage_step() + self.control_voltage = round((utils.MAX_CELL_VOLTAGE * self.cell_count), 3) + self.charge_mode = "Keep always max voltage" def manage_charge_voltage_linear(self) -> None: """ @@ -268,6 +273,7 @@ def manage_charge_voltage_linear(self) -> None: and voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT ): self.charge_mode += " + Balancing" + self.charge_mode += " (Linear Mode)" def manage_charge_voltage_step(self) -> None: diff --git a/etc/dbus-serialbattery/config.default.ini b/etc/dbus-serialbattery/config.default.ini index f2ac2ab4..c1a356e9 100644 --- a/etc/dbus-serialbattery/config.default.ini +++ b/etc/dbus-serialbattery/config.default.ini @@ -20,9 +20,10 @@ BLUETOOTH_BMS = ; --------- Charge mode --------- ; Choose the mode for voltage / current limitations (True / False) -; False is a step mode. This is the default with limitations on hard boundary steps -; True is a linear mode. For CCL and DCL the values between the steps are calculated for smoother values (by WaldemarFech) -; For CVL max battery voltage is calculated dynamically in order that the max cell voltage is not exceeded +; False is a step mode: This is the default with limitations on hard boundary steps +; True is a linear mode: +; For CCL and DCL the values between the steps are calculated for smoother values (by WaldemarFech) +; For CVL max battery voltage is calculated dynamically in order that the max cell voltage is not exceeded LINEAR_LIMITATION_ENABLE = True ; Specify in seconds how often the linear values should be recalculated @@ -33,17 +34,23 @@ LINEAR_RECALCULATION_ON_PERC_CHANGE = 5 ; --------- Charge Voltage limitation (affecting CVL) --------- -; Description: Limit max charging voltage (MAX_CELL_VOLTAGE * cell count), switch from max voltage to float voltage (FLOAT_CELL_VOLTAGE * cell count) and back -; Step mode: After max voltage is reached for MAX_VOLTAGE_TIME_SEC it switches to float voltage. After SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT it -; switches back to max voltage. -; Linear mode: After max voltage is reachend and cell voltage difference is smaller or equal to CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL it switches to -; float voltage after 300 (fixed) additional seconds. After cell voltage difference is greater or equal to CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT -; it switches back to max voltage. -; Example: The battery reached max voltage of 55.2V and hold it for 900 seconds, the the CVL is switched to float voltage of 53.6V to don't stress the batteries. -; Allow max voltage of 55.2V again, if SoC is once below 90% +; Description: Limit max charging voltage (MAX_CELL_VOLTAGE * cell count), switch from max voltage to float +; voltage (FLOAT_CELL_VOLTAGE * cell count) and back +; False: Max charging voltage is always kept +; True: Max charging voltage is reduced based on charge mode +; Step mode: After max voltage is reached for MAX_VOLTAGE_TIME_SEC it switches to float voltage. After +; SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT it switches back to max voltage. +; Linear mode: After max voltage is reachend and cell voltage difference is smaller or equal to +; CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL it switches to float voltage after 300 (fixed) +; additional seconds. After cell voltage difference is greater or equal to +; CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT it switches back to max voltage. +; Example: The battery reached max voltage of 55.2V and hold it for 900 seconds, the the CVL is switched to +; float voltage of 53.6V to don't stress the batteries. Allow max voltage of 55.2V again, if SoC is +; once below 90% ; OR -; The battery reached max voltage of 55.2V and the max cell difference is 0.010V, then switch to float voltage of 53.6V after 300 additional seconds -; to don't stress the batteries. Allow max voltage of 55.2V again if max cell difference is above 0.050V +; The battery reached max voltage of 55.2V and the max cell difference is 0.010V, then switch to float +; voltage of 53.6V after 300 additional seconds to don't stress the batteries. Allow max voltage of +; 55.2V again if max cell difference is above 0.050V ; Charge voltage control management enable (True/False). CVCM_ENABLE = True From 9acfb1543402aea43dd9c4d7bc92825f9c7e4a26 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 12:20:47 +0200 Subject: [PATCH 08/11] fixed type error --- etc/dbus-serialbattery/battery.py | 263 ++++++++++++++++-------------- 1 file changed, 139 insertions(+), 124 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index c1f4686b..f1afcb16 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -184,97 +184,106 @@ def manage_charge_voltage_linear(self) -> None: voltageSum = 0 penaltySum = 0 tDiff = 0 - if utils.CVCM_ENABLE: - # calculate battery sum - for i in range(self.cell_count): - voltage = self.get_cell_voltage(i) - if voltage: - voltageSum += voltage - - # calculate penalty sum to prevent single cell overcharge by using current cell voltage - if voltage > utils.MAX_CELL_VOLTAGE: - # foundHighCellVoltage: reset to False is not needed, since it is recalculated every second - foundHighCellVoltage = True - penaltySum += voltage - utils.MAX_CELL_VOLTAGE - 0.010 - - voltageDiff = self.get_max_cell_voltage() - self.get_min_cell_voltage() - if self.max_voltage_start_time is None: + try: + if utils.CVCM_ENABLE: + # calculate battery sum + for i in range(self.cell_count): + voltage = self.get_cell_voltage(i) + if voltage: + voltageSum += voltage + + # calculate penalty sum to prevent single cell overcharge by using current cell voltage + if voltage > utils.MAX_CELL_VOLTAGE: + # foundHighCellVoltage: reset to False is not needed, since it is recalculated every second + foundHighCellVoltage = True + penaltySum += voltage - utils.MAX_CELL_VOLTAGE - 0.010 + + voltageDiff = self.get_max_cell_voltage() - self.get_min_cell_voltage() + + if self.max_voltage_start_time is None: + if ( + utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum + and voltageDiff + <= utils.CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL + and self.allow_max_voltage + ): + self.max_voltage_start_time = time() + elif ( + # utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc + voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT + and not self.allow_max_voltage + ): + self.allow_max_voltage = True + else: + tDiff = time() - self.max_voltage_start_time + # if utils.MAX_VOLTAGE_TIME_SEC < tDiff: + # keep max voltage for 300 more seconds + if 300 < tDiff: + self.allow_max_voltage = False + self.max_voltage_start_time = 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 ( - utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum - and voltageDiff <= utils.CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL - and self.allow_max_voltage + int(time()) - self.linear_cvl_last_set + >= utils.LINEAR_RECALCULATION_EVERY ): - self.max_voltage_start_time = time() - elif ( - # utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc - voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT - and not self.allow_max_voltage - ): - self.allow_max_voltage = True - else: - tDiff = time() - self.max_voltage_start_time - # if utils.MAX_VOLTAGE_TIME_SEC < tDiff: - # keep max voltage for 300 more seconds - if 300 < tDiff: - self.allow_max_voltage = False - self.max_voltage_start_time = 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()) + self.linear_cvl_last_set = int(time()) + + # Keep penalty above min battery voltage + self.control_voltage = round( + max( + voltageSum - penaltySum, + utils.MIN_CELL_VOLTAGE * self.cell_count, + ), + 3, + ) - # Keep penalty above min battery voltage - self.control_voltage = round( - max( - voltageSum - penaltySum, - utils.MIN_CELL_VOLTAGE * self.cell_count, - ), - 3, + self.charge_mode = ( + "Bulk dynamic" + # + " (vS: " + # + str(round(voltageSum, 2)) + # + " - pS: " + # + str(round(penaltySum, 2)) + # + ")" + if self.max_voltage_start_time is None + else "Absorption dynamic" + # + "(vS: " + # + str(round(voltageSum, 2)) + # + " - pS: " + # + str(round(penaltySum, 2)) + # + ")" ) - self.charge_mode = ( - "Bulk dynamic" - # + " (vS: " - # + str(round(voltageSum, 2)) - # + " - pS: " - # + str(round(penaltySum, 2)) - # + ")" - if self.max_voltage_start_time is None - else "Absorption dynamic" - # + "(vS: " - # + str(round(voltageSum, 2)) - # + " - pS: " - # + str(round(penaltySum, 2)) - # + ")" - ) + elif self.allow_max_voltage: + self.control_voltage = round( + (utils.MAX_CELL_VOLTAGE * self.cell_count), 3 + ) + self.charge_mode = ( + "Bulk" if self.max_voltage_start_time is None else "Absorption" + ) - elif self.allow_max_voltage: - self.control_voltage = round((utils.MAX_CELL_VOLTAGE * self.cell_count), 3) - self.charge_mode = ( - "Bulk" if self.max_voltage_start_time is None else "Absorption" - ) + else: + self.control_voltage = round( + (utils.FLOAT_CELL_VOLTAGE * self.cell_count), 3 + ) + self.charge_mode = "Float" - else: - self.control_voltage = round( - (utils.FLOAT_CELL_VOLTAGE * self.cell_count), 3 - ) - self.charge_mode = "Float" + if ( + self.allow_max_voltage + and self.get_balancing() + and voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT + ): + self.charge_mode += " + Balancing" - if ( - self.allow_max_voltage - and self.get_balancing() - and voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT - ): - self.charge_mode += " + Balancing" + self.charge_mode += " (Linear Mode)" - self.charge_mode += " (Linear Mode)" + except TypeError: + self.control_voltage = None + self.charge_mode = "--" def manage_charge_voltage_step(self) -> None: """ @@ -283,55 +292,61 @@ def manage_charge_voltage_step(self) -> None: """ voltageSum = 0 tDiff = 0 - if utils.CVCM_ENABLE: - # calculate battery sum - for i in range(self.cell_count): - voltage = self.get_cell_voltage(i) - if voltage: - voltageSum += voltage - - if self.max_voltage_start_time is None: - # check if max voltage is reached and start timer to keep max voltage - if ( - utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum - and self.allow_max_voltage - ): - # example 2 - self.max_voltage_start_time = time() - - # check if reset soc is greater than battery soc - # this prevents flapping between max and float voltage - elif ( - utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc - and not self.allow_max_voltage - ): - self.allow_max_voltage = True - # do nothing + try: + if utils.CVCM_ENABLE: + # calculate battery sum + for i in range(self.cell_count): + voltage = self.get_cell_voltage(i) + if voltage: + voltageSum += voltage + + if self.max_voltage_start_time is None: + # check if max voltage is reached and start timer to keep max voltage + if ( + utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum + and self.allow_max_voltage + ): + # example 2 + self.max_voltage_start_time = time() + + # check if reset soc is greater than battery soc + # this prevents flapping between max and float voltage + elif ( + utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc + and not self.allow_max_voltage + ): + self.allow_max_voltage = True + + # do nothing + else: + pass + + # timer started else: - pass + tDiff = time() - self.max_voltage_start_time + if utils.MAX_VOLTAGE_TIME_SEC < tDiff: + self.allow_max_voltage = False + self.max_voltage_start_time = None + + else: + pass + + if self.allow_max_voltage: + self.control_voltage = utils.MAX_CELL_VOLTAGE * self.cell_count + self.charge_mode = ( + "Bulk" if self.max_voltage_start_time is None else "Absorption" + ) - # timer started else: - tDiff = time() - self.max_voltage_start_time - if utils.MAX_VOLTAGE_TIME_SEC < tDiff: - self.allow_max_voltage = False - self.max_voltage_start_time = None + self.control_voltage = utils.FLOAT_CELL_VOLTAGE * self.cell_count + self.charge_mode = "Float" - else: - pass + self.charge_mode += " (Step Mode)" - if self.allow_max_voltage: - self.control_voltage = utils.MAX_CELL_VOLTAGE * self.cell_count - self.charge_mode = ( - "Bulk" if self.max_voltage_start_time is None else "Absorption" - ) - - else: - self.control_voltage = utils.FLOAT_CELL_VOLTAGE * self.cell_count - self.charge_mode = "Float" - - self.charge_mode += " (Step Mode)" + except TypeError: + self.control_voltage = None + self.charge_mode = "--" def manage_charge_current(self) -> None: # Manage Charge Current Limitations From 7e1ada1e82c4eb4f9268f279561c2c48eba2ea9a Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 14:12:31 +0200 Subject: [PATCH 09/11] Added: BMS disconnect behaviour * Choose to block charge/discharge on disconnect * Trigger Venus OS alarm --- etc/dbus-serialbattery/config.default.ini | 8 +++++ etc/dbus-serialbattery/dbushelper.py | 36 +++++++++++++++++++---- etc/dbus-serialbattery/utils.py | 8 +++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/etc/dbus-serialbattery/config.default.ini b/etc/dbus-serialbattery/config.default.ini index c1a356e9..8018e3bd 100644 --- a/etc/dbus-serialbattery/config.default.ini +++ b/etc/dbus-serialbattery/config.default.ini @@ -18,6 +18,14 @@ FLOAT_CELL_VOLTAGE = 3.375 ; Example with 3 BMS: Jkbms_Ble C8:47:8C:00:00:00, Jkbms_Ble C8:47:8C:00:00:11, Jkbms_Ble C8:47:8C:00:00:22 BLUETOOTH_BMS = +; --------- BMS disconnect behaviour --------- +; Description: Block charge and discharge when the communication to the BMS is lost. If you are removing the +; BMS on purpose, then you have to restart the driver/system to reset the block. +; False: Charge and discharge is not blocked on BMS communication loss +; True: Charge and discharge is blocked on BMS communication loss, it's unblocked when connection is established +; again or the driver/system is restarted +BLOCK_ON_DISCONNECT = False + ; --------- Charge mode --------- ; Choose the mode for voltage / current limitations (True / False) ; False is a step mode: This is the default with limitations on hard boundary steps diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index 4f1b4a5f..77a48544 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -34,6 +34,7 @@ def __init__(self, battery): self.instance = 1 self.settings = None self.error_count = 0 + self.block_because_disconnect = False self._dbusservice = VeDbusService( "com.victronenergy.battery." + self.battery.port[self.battery.port.rfind("/") + 1 :], @@ -264,6 +265,7 @@ def setup_vedbus(self): self._dbusservice.add_path("/Alarms/LowChargeTemperature", None, writeable=True) self._dbusservice.add_path("/Alarms/HighTemperature", None, writeable=True) self._dbusservice.add_path("/Alarms/LowTemperature", None, writeable=True) + self._dbusservice.add_path("/Alarms/BmsCable", None, writeable=True) self._dbusservice.add_path( "/Alarms/HighInternalTemperature", None, writeable=True ) @@ -327,6 +329,11 @@ def publish_battery(self, loop): if success: self.error_count = 0 self.battery.online = True + + # unblock charge/discharge, if it was blocked when battery went offline + if utils.BLOCK_ON_DISCONNECT: + self.block_because_disconnect = False + else: self.error_count += 1 # If the battery is offline for more than 10 polls (polled every second for most batteries) @@ -334,6 +341,10 @@ def publish_battery(self, loop): self.battery.online = False self.battery.init_values() + # block charge/discharge + if utils.BLOCK_ON_DISCONNECT: + self.block_because_disconnect = True + # Has it completely failed if self.error_count >= 60: loop.quit() @@ -386,22 +397,34 @@ def publish_dbus(self): self._dbusservice["/History/ChargeCycles"] = self.battery.cycles self._dbusservice["/History/TotalAhDrawn"] = self.battery.total_ah_drawn self._dbusservice["/Io/AllowToCharge"] = ( - 1 if self.battery.charge_fet and self.battery.control_allow_charge else 0 + 1 + if self.battery.charge_fet + and self.battery.control_allow_charge + and self.block_because_disconnect is False + else 0 ) self._dbusservice["/Io/AllowToDischarge"] = ( 1 - if self.battery.discharge_fet and self.battery.control_allow_discharge + if self.battery.discharge_fet + and self.battery.control_allow_discharge + and self.block_because_disconnect is False else 0 ) self._dbusservice["/Io/AllowToBalance"] = 1 if self.battery.balance_fet else 0 self._dbusservice["/System/NrOfModulesBlockingCharge"] = ( 0 - if self.battery.charge_fet is None - or (self.battery.charge_fet and self.battery.control_allow_charge) + if ( + self.battery.charge_fet is None + or (self.battery.charge_fet and self.battery.control_allow_charge) + ) + and self.block_because_disconnect is False else 1 ) self._dbusservice["/System/NrOfModulesBlockingDischarge"] = ( - 0 if self.battery.discharge_fet is None or self.battery.discharge_fet else 1 + 0 + if (self.battery.discharge_fet is None or self.battery.discharge_fet) + and self.block_because_disconnect is False + else 1 ) self._dbusservice["/System/NrOfModulesOnline"] = 1 if self.battery.online else 0 self._dbusservice["/System/NrOfModulesOffline"] = ( @@ -477,6 +500,9 @@ def publish_dbus(self): self._dbusservice[ "/Alarms/LowTemperature" ] = self.battery.protection.temp_low_discharge + self._dbusservice["/Alarms/BmsCable"] = ( + 2 if self.block_because_disconnect else 0 + ) self._dbusservice[ "/Alarms/HighInternalTemperature" ] = self.battery.protection.temp_high_internal diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 9a4e3fd0..e5e8475f 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -54,6 +54,14 @@ def _get_list_from_config( # Max voltage can seen as absorption voltage FLOAT_CELL_VOLTAGE = float(config["DEFAULT"]["FLOAT_CELL_VOLTAGE"]) +# --------- BMS disconnect behaviour --------- +# Description: Block charge and discharge when the communication to the BMS is lost. If you are removing the +# BMS on purpose, then you have to restart the driver/system to reset the block. +# False: Charge and discharge is not blocked on BMS communication loss +# True: Charge and discharge is blocked on BMS communication loss, it's unblocked when connection is established +# again or the driver/system is restarted +BLOCK_ON_DISCONNECT = "True" == config["DEFAULT"]["BLOCK_ON_DISCONNECT"] + # --------- Charge mode --------- # Choose the mode for voltage / current limitations (True / False) # False is a step mode. This is the default with limitations on hard boundary steps From 2b32e11c11d4b524c36a38a35482c4360278a539 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 14:53:46 +0200 Subject: [PATCH 10/11] Changed: Remove wildcard import from dbushelper.py --- .flake8 | 2 +- etc/dbus-serialbattery/dbushelper.py | 56 ++++++++++++++-------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/.flake8 b/.flake8 index 0e731225..e7900ff1 100644 --- a/.flake8 +++ b/.flake8 @@ -8,7 +8,7 @@ exclude = ./etc/dbus-serialbattery/bms/mnb_utils_max17853.py, ./etc/dbus-serialbattery/bms/revov.py, #./etc/dbus-serialbattery/dbus-serialbattery.py, - ./etc/dbus-serialbattery/dbushelper.py, + #./etc/dbus-serialbattery/dbushelper.py, ./etc/dbus-serialbattery/minimalmodbus.py, ./velib_python venv diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index 77a48544..8c1c9d5f 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -14,10 +14,10 @@ "/opt/victronenergy/dbus-systemcalc-py/ext/velib_python", ), ) -from vedbus import VeDbusService -from settingsdevice import SettingsDevice -import battery -from utils import * +from vedbus import VeDbusService # noqa: E402 +from settingsdevice import SettingsDevice # noqa: E402 +from utils import logger, publish_config_variables # noqa: E402 +import utils # noqa: E402 def get_bus(): @@ -122,7 +122,7 @@ def setup_vedbus(self): "/ProductName", "SerialBattery(" + self.battery.type + ")" ) self._dbusservice.add_path( - "/FirmwareVersion", str(DRIVER_VERSION) + DRIVER_SUBVERSION + "/FirmwareVersion", str(utils.DRIVER_VERSION) + utils.DRIVER_SUBVERSION ) self._dbusservice.add_path("/HardwareVersion", self.battery.hardware_version) self._dbusservice.add_path("/Connected", 1) @@ -271,11 +271,11 @@ def setup_vedbus(self): ) # cell voltages - if BATTERY_CELL_DATA_FORMAT > 0: + if utils.BATTERY_CELL_DATA_FORMAT > 0: for i in range(1, self.battery.cell_count + 1): cellpath = ( "/Cell/%s/Volts" - if (BATTERY_CELL_DATA_FORMAT & 2) + if (utils.BATTERY_CELL_DATA_FORMAT & 2) else "/Voltages/Cell%s" ) self._dbusservice.add_path( @@ -284,11 +284,11 @@ def setup_vedbus(self): writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v), ) - if BATTERY_CELL_DATA_FORMAT & 1: + if utils.BATTERY_CELL_DATA_FORMAT & 1: self._dbusservice.add_path( "/Balances/Cell%s" % (str(i)), None, writeable=True ) - pathbase = "Cell" if (BATTERY_CELL_DATA_FORMAT & 2) else "Voltages" + pathbase = "Cell" if (utils.BATTERY_CELL_DATA_FORMAT & 2) else "Voltages" self._dbusservice.add_path( "/%s/Sum" % pathbase, None, @@ -305,18 +305,18 @@ def setup_vedbus(self): # Create TimeToSoC items only if enabled if self.battery.capacity is not None: # Create TimeToGo item - if TIME_TO_GO_ENABLE: + if utils.TIME_TO_GO_ENABLE: self._dbusservice.add_path("/TimeToGo", None, writeable=True) # Create TimeToSoc items - if len(TIME_TO_SOC_POINTS) > 0: - for num in TIME_TO_SOC_POINTS: + if len(utils.TIME_TO_SOC_POINTS) > 0: + for num in utils.TIME_TO_SOC_POINTS: self._dbusservice.add_path( "/TimeToSoC/" + str(num), None, writeable=True ) - logger.info(f"publish config values = {PUBLISH_CONFIG_VALUES}") - if PUBLISH_CONFIG_VALUES == 1: + logger.info(f"publish config values = {utils.PUBLISH_CONFIG_VALUES}") + if utils.PUBLISH_CONFIG_VALUES == 1: publish_config_variables(self._dbusservice) return True @@ -358,7 +358,7 @@ def publish_battery(self, loop): # publish all the data from the battery object to dbus self.publish_dbus() - except: + except Exception: traceback.print_exc() loop.quit() @@ -508,40 +508,42 @@ def publish_dbus(self): ] = self.battery.protection.temp_high_internal # cell voltages - if BATTERY_CELL_DATA_FORMAT > 0: + if utils.BATTERY_CELL_DATA_FORMAT > 0: try: voltageSum = 0 for i in range(self.battery.cell_count): voltage = self.battery.get_cell_voltage(i) cellpath = ( "/Cell/%s/Volts" - if (BATTERY_CELL_DATA_FORMAT & 2) + if (utils.BATTERY_CELL_DATA_FORMAT & 2) else "/Voltages/Cell%s" ) self._dbusservice[cellpath % (str(i + 1))] = voltage - if BATTERY_CELL_DATA_FORMAT & 1: + if utils.BATTERY_CELL_DATA_FORMAT & 1: self._dbusservice[ "/Balances/Cell%s" % (str(i + 1)) ] = self.battery.get_cell_balancing(i) if voltage: voltageSum += voltage - pathbase = "Cell" if (BATTERY_CELL_DATA_FORMAT & 2) else "Voltages" + pathbase = ( + "Cell" if (utils.BATTERY_CELL_DATA_FORMAT & 2) else "Voltages" + ) self._dbusservice["/%s/Sum" % pathbase] = voltageSum self._dbusservice["/%s/Diff" % pathbase] = ( self.battery.get_max_cell_voltage() - self.battery.get_min_cell_voltage() ) - except: + except Exception: pass # Update TimeToGo and/or TimeToSoC try: if ( self.battery.capacity is not None - and (TIME_TO_GO_ENABLE or len(TIME_TO_SOC_POINTS) > 0) + and (utils.TIME_TO_GO_ENABLE or len(utils.TIME_TO_SOC_POINTS) > 0) and ( int(time()) - self.battery.time_to_soc_update - >= TIME_TO_SOC_RECALCULATE_EVERY + >= utils.TIME_TO_SOC_RECALCULATE_EVERY ) ): self.battery.time_to_soc_update = int(time()) @@ -550,13 +552,13 @@ def publish_dbus(self): ) # Update TimeToGo item - if TIME_TO_GO_ENABLE: + if utils.TIME_TO_GO_ENABLE: # Update TimeToGo item, has to be a positive int since it's used from dbus-systemcalc-py self._dbusservice["/TimeToGo"] = ( abs( int( self.battery.get_timeToSoc( - SOC_LOW_WARNING, crntPrctPerSec, True + utils.SOC_LOW_WARNING, crntPrctPerSec, True ) ) ) @@ -565,15 +567,15 @@ def publish_dbus(self): ) # Update TimeToSoc items - if len(TIME_TO_SOC_POINTS) > 0: - for num in TIME_TO_SOC_POINTS: + if len(utils.TIME_TO_SOC_POINTS) > 0: + for num in utils.TIME_TO_SOC_POINTS: self._dbusservice["/TimeToSoC/" + str(num)] = ( self.battery.get_timeToSoc(num, crntPrctPerSec) if self.battery.current else None ) - except: + except Exception: pass if self.battery.soc is not None: From cd8c22a431d702710423302050f877c7e1601e3f Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 4 May 2023 15:48:14 +0200 Subject: [PATCH 11/11] small fixes --- CHANGELOG.md | 6 ++++-- etc/dbus-serialbattery/bms/jkbms_ble.py | 6 ++++-- etc/dbus-serialbattery/reinstall-local.sh | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d8f234..e6a84661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,18 @@ ### ATTENTION: Breaking changes! The config is now done in the `config.ini`. All values from the `utils.py` gets lost. The changes in the `config.ini` will persists future updates. * Added: `self.unique_identifier` to the battery class. Used to identify a BMS when multiple BMS are connected - planned for future use by @mr-manuel +* Added: Alert is triggered, when BMS communication is lost by @mr-manuel * Added: Apply max voltage, if `CVCM_ENABLE` is `False`. Before float voltage was applied by @mr-manuel * Added: Balancing status for JKBMS by @mr-manuel * Added: Balancing switch status for JKBMS by @mr-manuel * Added: Balancing switch status to the GUI -> SerialBattery -> IO by @mr-manuel +* Added: Block charge/discharge when BMS communication is lost. Can be enabled trough the config file by @mr-manuel * Added: Charge Mode display by @mr-manuel * Added: Choose how battery temperature is assembled (mean temp 1 & 2, only temp 1 or only temp 2) by @mr-manuel * Added: Config file by @ppuetsch * Added: Create empty `config.ini` for easier user usage by @mr-manuel * Added: Cronjob to restart Bluetooth service every 12 hours by @mr-manuel -* Added: Daly BMS read capacity https://github.com/Louisvdw/dbus-serialbattery/pull/594 by transistorgit +* Added: Daly BMS read capacity https://github.com/Louisvdw/dbus-serialbattery/pull/594 by @transistorgit * Added: Driver uninstall script by @mr-manuel * Added: Fix for Venus OS >= v3.00~14 showing unused items https://github.com/Louisvdw/dbus-serialbattery/issues/469 by @mr-manuel * Added: HighInternalTemperature alarm (MOSFET) for JKBMS by @mr-manuel @@ -66,7 +68,7 @@ * Changed: Moved Bluetooth part to `reinstall-local.sh` by @mr-manuel * Changed: Moved BMS scripts to subfolder by @mr-manuel * Changed: Removed cell voltage penalty. Replaced by automatic voltage calculation. Max voltage is kept until cells are balanced and reset when cells are inbalanced by @mr-manuel -* Changed: Removed wildcard imports from several BMS drivers and fixed black lint errors by @mr-manuel +* Changed: Removed all wildcard imports and fixed black lint errors by @mr-manuel * Changed: Renamed scripts for better reading #532 by @mr-manuel * Changed: Reworked and optimized installation scripts by @mr-manuel * Changed: Separate Time-To-Go and Time-To-SoC activation by @mr-manuel diff --git a/etc/dbus-serialbattery/bms/jkbms_ble.py b/etc/dbus-serialbattery/bms/jkbms_ble.py index b495aa8e..6ba2f631 100644 --- a/etc/dbus-serialbattery/bms/jkbms_ble.py +++ b/etc/dbus-serialbattery/bms/jkbms_ble.py @@ -225,8 +225,10 @@ def reset_bluetooth(self): # if self.jk.is_running(): # self.jk.stop_scraping() logger.info("scraping ended, issuing sys-commands") - os.system("kill -9 $(pidof bluetoothd)") - # os.system("/etc/init.d/bluetooth stop") is not enugh, kill -9 via pid is needed + # process kill is needed, since the service/bluetooth driver is probably freezed + os.system('pkill -f "bluetoothd"') + # stop will not work, if service/bluetooth driver is stuck + # os.system("/etc/init.d/bluetooth stop") time.sleep(2) os.system("rfkill block bluetooth") os.system("rfkill unblock bluetooth") diff --git a/etc/dbus-serialbattery/reinstall-local.sh b/etc/dbus-serialbattery/reinstall-local.sh index c9ee661d..5e9a5e18 100755 --- a/etc/dbus-serialbattery/reinstall-local.sh +++ b/etc/dbus-serialbattery/reinstall-local.sh @@ -81,6 +81,9 @@ length=${#bms_array[@]} # always remove existing blebattery services to cleanup rm -rf /service/dbus-blebattery.* +# kill all blebattery processes +pkill -f "blebattery" + if [ $length -gt 0 ]; then echo "Found $length Bluetooth BMS in the config file!"