From 044f06667f89018e7a535935006ae34eaa254051 Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 5 Sep 2023 16:41:06 +0200 Subject: [PATCH] LLT/JBD BMS - Improved error handling and automatical driver restart in case of error. Should fix: - https://github.com/Louisvdw/dbus-serialbattery/issues/730 - https://github.com/Louisvdw/dbus-serialbattery/issues/769 - https://github.com/Louisvdw/dbus-serialbattery/issues/777 --- CHANGELOG.md | 8 +- etc/dbus-serialbattery/bms/lltjbd_ble.py | 126 ++++++++++++++++++---- etc/dbus-serialbattery/reinstall-local.sh | 13 ++- requirements.txt | 3 +- 4 files changed, 126 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb9ac501..e56b37c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * Added: Temperature names to dbus and mqtt by @mr-manuel * Added: Use current average of the last 300 cycles for time to go and time to SoC calculation by @mr-manuel * Added: Validate current, voltage, capacity and SoC for all BMS. This prevents that a device, which is no BMS, is detected as BMS. Fixes also https://github.com/Louisvdw/dbus-serialbattery/issues/479 by @mr-manuel +* Changed: Daly BMS - Fix readsentence by @transistorgit * Changed: Enable BMS that are disabled by default by specifying it in the config file. No more need to edit scripts by @mr-manuel * Changed: Fix daly readsentence by @transistorgit * Changed: Fix Sinowealth not loading https://github.com/Louisvdw/dbus-serialbattery/issues/702 by @mr-manuel @@ -26,11 +27,14 @@ * Changed: Improved battery voltage handling in linear absorption mode by @ogurevich * Changed: Improved driver disable script by @md-manuel * Changed: Improved driver reinstall when multiple Bluetooth BMS are enabled by @mr-manuel -* Changed: Improved Jkbms_Ble driver by @seidler2547 & @mr-manuel -* Changed: LLT/JBD - Fix cycle capacity with https://github.com/Louisvdw/dbus-serialbattery/pull/762 by @idstein +* Changed: JKBMS_BLE BMS - Improved driver by @seidler2547 & @mr-manuel +* Changed: LLT/JBD BMS - Fix cycle capacity with https://github.com/Louisvdw/dbus-serialbattery/pull/762 by @idstein +* Changed: LLT/JBD BMS - Fixed https://github.com/Louisvdw/dbus-serialbattery/issues/778 with https://github.com/Louisvdw/dbus-serialbattery/pull/798 by @idstein +* Changed: LLT/JBD BMS - Improved error handling and automatical driver restart in case of error. Should fix https://github.com/Louisvdw/dbus-serialbattery/issues/730, https://github.com/Louisvdw/dbus-serialbattery/issues/769 and https://github.com/Louisvdw/dbus-serialbattery/issues/777 by @mr-manuel * Changed: LLT/JBD BMS - SOC different in Xiaoxiang app and dbus-serialbattery with https://github.com/Louisvdw/dbus-serialbattery/pull/760 by @idstein * Changed: Make CCL and DCL limiting messages more clear by @mr-manuel * Changed: Reduce the big inrush current if the CVL jumps from Bulk/Absorbtion to Float https://github.com/Louisvdw/dbus-serialbattery/issues/659 by @Rikkert-RS & @ogurevich +* Changed: Sinowealth BMS - Fix not loading https://github.com/Louisvdw/dbus-serialbattery/issues/702 by @mr-manuel * Changed: Time-to-Go and Time-to-SoC use the current average of the last 5 minutes for calculation by @mr-manuel * Changed: Time-to-SoC calculate only positive points by @mr-manuel * Removed: Cronjob to restart Bluetooth service every 12 hours by @mr-manuel diff --git a/etc/dbus-serialbattery/bms/lltjbd_ble.py b/etc/dbus-serialbattery/bms/lltjbd_ble.py index 65e1d4b7..449e7d0b 100644 --- a/etc/dbus-serialbattery/bms/lltjbd_ble.py +++ b/etc/dbus-serialbattery/bms/lltjbd_ble.py @@ -2,12 +2,15 @@ import asyncio import atexit import functools +import os import threading import sys from asyncio import CancelledError +from time import sleep from typing import Union, Optional from utils import logger from bleak import BleakClient, BleakScanner, BLEDevice +from bleak.exc import BleakDBusError from bms.lltjbd import LltJbdProtection, LltJbd BLE_SERVICE_UUID = "0000ff00-0000-1000-8000-00805f9b34fb" @@ -62,25 +65,66 @@ async def bt_main_loop(self): file = exception_traceback.tb_frame.f_code.co_filename line = exception_traceback.tb_lineno logger.error( - f"Exception occurred: {repr(exception_object)} of type {exception_type} in {file} line #{line}" + f"BleakScanner(): Exception occurred: {repr(exception_object)} of type {exception_type} " + f"in {file} line #{line}" ) self.device = None await asyncio.sleep(0.5) + # allow the bluetooth connection to recover + sleep(5) if not self.device: self.run = False return - async with BleakClient( - self.device, disconnected_callback=self.on_disconnect - ) as client: - self.bt_client = client - self.bt_loop = asyncio.get_event_loop() - self.response_queue = asyncio.Queue() - self.ready_event.set() - while self.run and client.is_connected and self.main_thread.is_alive(): - await asyncio.sleep(0.1) - self.bt_loop = None + try: + async with BleakClient( + self.device, disconnected_callback=self.on_disconnect + ) as client: + self.bt_client = client + self.bt_loop = asyncio.get_event_loop() + self.response_queue = asyncio.Queue() + self.ready_event.set() + while self.run and client.is_connected and self.main_thread.is_alive(): + await asyncio.sleep(0.1) + self.bt_loop = None + + # Exception occurred: TimeoutError() of type + except asyncio.exceptions.TimeoutError: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"BleakClient(): asyncio.exceptions.TimeoutError: {repr(exception_object)} of type {exception_type} " + f"in {file} line #{line}" + ) + # needed? + self.run = False + return + + except TimeoutError: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"BleakClient(): TimeoutError: {repr(exception_object)} of type {exception_type} " + f"in {file} line #{line}" + ) + # needed? + self.run = False + return + + except Exception: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"BleakClient(): Exception occurred: {repr(exception_object)} of type {exception_type} " + f"in {file} line #{line}" + ) + # needed? + self.run = False + return def background_loop(self): while self.run and self.main_thread.is_alive(): @@ -117,8 +161,13 @@ def test_connection(self): result = super().test_connection() if not result: logger.error("No BMS found at " + self.address) - except Exception as err: - logger.error(f"Unexpected {err=}, {type(err)=}") + except Exception: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"Exception occurred: {repr(exception_object)} of type {exception_type} in {file} line #{line}" + ) result = False return result @@ -161,8 +210,23 @@ async def async_read_serial_data_llt(self, command): except asyncio.TimeoutError: logger.error(">>> ERROR: No reply - returning") return False - except Exception as e: - logger.error(">>> ERROR: No reply - returning", e) + except BleakDBusError: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"BleakDBusError: {repr(exception_object)} of type {exception_type} in {file} line #{line}" + ) + self.reset_bluetooth() + return False + except Exception: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"Exception occurred: {repr(exception_object)} of type {exception_type} in {file} line #{line}" + ) + self.reset_bluetooth() return False def read_serial_data_llt(self, command): @@ -172,12 +236,38 @@ def read_serial_data_llt(self, command): data = asyncio.run(self.async_read_serial_data_llt(command)) return self.validate_packet(data) except CancelledError as e: - logger.error(">>> ERROR: No reply - canceled - returning", e) + logger.error(">>> ERROR: No reply - canceled - returning") + logger.error(e) return False - except Exception as e: - logger.error(">>> ERROR: No reply - returning", e) + # except Exception as e: + # logger.error(">>> ERROR: No reply - returning") + # logger.error(e) + # return False + except Exception: + exception_type, exception_object, exception_traceback = sys.exc_info() + file = exception_traceback.tb_frame.f_code.co_filename + line = exception_traceback.tb_lineno + logger.error( + f"Exception occurred: {repr(exception_object)} of type {exception_type} in {file} line #{line}" + ) return False + def reset_bluetooth(self): + logger.error("Reset of system Bluetooth daemon triggered") + self.bt_loop = False + + # 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") + sleep(2) + os.system("rfkill block bluetooth") + os.system("rfkill unblock bluetooth") + os.system("/etc/init.d/bluetooth start") + logger.error("System Bluetooth daemon should have been restarted") + sleep(5) + sys.exit(1) + if __name__ == "__main__": bat = LltJbd_Ble("Foo", -1, sys.argv[1]) diff --git a/etc/dbus-serialbattery/reinstall-local.sh b/etc/dbus-serialbattery/reinstall-local.sh index f1e98645..9e109e8a 100755 --- a/etc/dbus-serialbattery/reinstall-local.sh +++ b/etc/dbus-serialbattery/reinstall-local.sh @@ -181,9 +181,16 @@ if [ "$length" -gt 0 ]; then opkg install python3-misc python3-pip echo - pip3 install bleak==0.20.2 - # pip3 install bleak==0.21.0 - + pip3 install bleak + + # # ONLY FOR TESTING if there are version issues + # echo + # echo "Available bleak versions:" + # curl --silent https://api.github.com/repos/hbldh/bleak/releases | grep '"name": "v' | sed "s/ \"name\": \"v//g" | sed "s/\",//g" + # echo + # read -r -p "Specify the bleak version to install: " bleak_version + # pip3 install bleak=="$bleak_version" + # echo echo pip3 install dbus-fast==1.87.0 # pip3 install dbus-fast==1.87.3 diff --git a/requirements.txt b/requirements.txt index f5c4cddd..7a984a6f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ pyserial==3.5 minimalmodbus==2.0.1 -bleak==0.20.2 \ No newline at end of file +bleak==0.21.0 +dbus-fast==1.94.1