From 1383b291ef43b966dce3e889b398cecd045449c9 Mon Sep 17 00:00:00 2001 From: Marvo2011 Date: Tue, 3 Oct 2023 15:47:20 +0200 Subject: [PATCH] Some changes for lost bluetooth connection / hci_uart stack restart --- etc/dbus-serialbattery/bms/lltjbd_ble.py | 130 +++++++++++++++-------- 1 file changed, 85 insertions(+), 45 deletions(-) diff --git a/etc/dbus-serialbattery/bms/lltjbd_ble.py b/etc/dbus-serialbattery/bms/lltjbd_ble.py index 449e7d0b..c7fb94fa 100644 --- a/etc/dbus-serialbattery/bms/lltjbd_ble.py +++ b/etc/dbus-serialbattery/bms/lltjbd_ble.py @@ -5,6 +5,7 @@ import os import threading import sys +import re from asyncio import CancelledError from time import sleep from typing import Union, Optional @@ -43,6 +44,21 @@ def __init__(self, port: Optional[str], baud: Optional[int], address: str): self.response_queue: Optional[asyncio.Queue] = None self.ready_event: Optional[asyncio.Event] = None + self.hci_uart_ok = True + if not os.path.isfile("/tmp/dbus-blebattery-hciattach"): + execfile = open("/tmp/dbus-blebattery-hciattach", "w") + execpath = os.popen('ps -ww | grep hciattach | grep -v grep').read() + execpath = re.search("/usr/bin/hciattach.+", execpath) + execfile.write(execpath.group()) + execfile.close() + else: + execpath = os.popen('ps -ww | grep hciattach | grep -v grep').read() + if not execpath: + execfile = open("/tmp/dbus-blebattery-hciattach", "r") + os.system(execfile.readline()) + execfile.close() + + logger.info("Init of LltJbd_Ble at " + address) def connection_name(self) -> str: @@ -64,10 +80,14 @@ async def bt_main_loop(self): 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"BleakScanner(): Exception occurred: {repr(exception_object)} of type {exception_type} " - f"in {file} line #{line}" - ) + if "Bluetooth adapters" in repr(exception_object): + self.reset_hci_uart() + else: + logger.error( + 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 @@ -131,20 +151,21 @@ def background_loop(self): asyncio.run(self.bt_main_loop()) async def async_test_connection(self): - self.ready_event = asyncio.Event() - if not self.bt_thread.is_alive(): - self.bt_thread.start() - - def shutdown_ble_atexit(thread): - self.run = False - thread.join() - - atexit.register(shutdown_ble_atexit, self.bt_thread) - try: - return await asyncio.wait_for(self.ready_event.wait(), timeout=5) - except asyncio.TimeoutError: - logger.error(">>> ERROR: Unable to connect with BLE device") - return False + if self.hci_uart_ok: + self.ready_event = asyncio.Event() + if not self.bt_thread.is_alive(): + self.bt_thread.start() + + def shutdown_ble_atexit(thread): + self.run = False + thread.join() + + atexit.register(shutdown_ble_atexit, self.bt_thread) + try: + return await asyncio.wait_for(self.ready_event.wait(), timeout=5) + except asyncio.TimeoutError: + logger.error(">>> ERROR: Unable to connect with BLE device") + return False def test_connection(self): # call a function that will connect to the battery, send a command and retrieve the result. @@ -201,33 +222,34 @@ def rx_callback(future: asyncio.Future, data: bytearray, sender, rx: bytearray): return result async def async_read_serial_data_llt(self, command): - try: - bt_task = asyncio.run_coroutine_threadsafe( - self.send_command(command), self.bt_loop - ) - result = await asyncio.wait_for(asyncio.wrap_future(bt_task), 20) - return result - except asyncio.TimeoutError: - logger.error(">>> ERROR: No reply - returning") - return False - 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 + if self.hci_uart_ok: + try: + bt_task = asyncio.run_coroutine_threadsafe( + self.send_command(command), self.bt_loop + ) + result = await asyncio.wait_for(asyncio.wrap_future(bt_task), 20) + return result + except asyncio.TimeoutError: + logger.error(">>> ERROR: No reply - returning") + return False + 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): if not self.bt_loop: @@ -268,6 +290,24 @@ def reset_bluetooth(self): sleep(5) sys.exit(1) + def reset_hci_uart(self): + logger.error("Reset of hci_uart stack... Reconnecting to: " + self.address) + self.run = False + os.system("pkill -f 'hciattach'") + sleep(0.5) + os.system("rmmod hci_uart") + os.system("rmmod btbcm") + os.system("modprobe hci_uart") + os.system("modprobe btbcm") + sys.exit(1) + # execfile = open("/tmp/dbus-blebattery-hciattach", "r") + # sleep(5) + # os.system(execfile.readline()) + # os.system(execfile.readline()) + # execfile.close() + # sleep(0.5) + # os.system("bluetoothctl connect " + self.address) + # self.run = True if __name__ == "__main__": bat = LltJbd_Ble("Foo", -1, sys.argv[1])