From 9b3d1060098b36f88e90848794d20923086acaa2 Mon Sep 17 00:00:00 2001 From: Anton <79713657+axectly@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:41:43 +0300 Subject: [PATCH] Retry opening the display COM port instead of exiting on first failure openSerial() gave up and stopped the whole program as soon as the port could not be opened. The program resets the screen at startup, which disconnects and reconnects the device: its COM port is gone for a few seconds and can come back under a different name, so an autostart at boot can lose that race and leave the screen frozen until the user starts the program again: [DEBUG] Detected screen turned ON [DEBUG] Auto detected COM port: COM4 [ERROR] Cannot open COM port COM4: could not open port 'COM4': FileNotFoundError(2, ...) Retry for a few seconds before giving up. Also keep self.com_port as configured instead of overwriting it with the detected port, so that with COM_PORT: AUTO the port is detected again at every attempt: the screen may come back on another port than the one found before. This applies to the reconnection in WriteLine() too, which reopens the port through the same function. Co-Authored-By: Claude Opus 5 --- library/lcd/lcd_comm.py | 52 ++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/library/lcd/lcd_comm.py b/library/lcd/lcd_comm.py index f12f07f95..197ac3c6d 100644 --- a/library/lcd/lcd_comm.py +++ b/library/lcd/lcd_comm.py @@ -44,6 +44,12 @@ class Orientation(IntEnum): REVERSE_LANDSCAPE = 3 +# The screen resets itself when the program starts, so its COM port can disappear or change for a +# few seconds: opening it is retried instead of giving up (and exiting) on the first failure. +SERIAL_OPEN_ATTEMPTS = 10 +SERIAL_OPEN_RETRY_DELAY = 1 # seconds + + class LcdComm(ABC): def __init__(self, com_port: str = "AUTO", display_width: int = 320, display_height: int = 480, update_queue: Optional[queue.Queue] = None): @@ -90,28 +96,36 @@ def get_height(self) -> int: return self.display_width def openSerial(self): - if self.com_port == 'AUTO': - self.com_port = self.auto_detect_com_port() - if not self.com_port: - logger.error( - "Cannot find COM port automatically, please run Configuration again and select COM port manually") - try: - sys.exit(0) - except: - os._exit(0) + # self.com_port is kept as configured ("AUTO" or a port name): on AUTO the port is + # detected again at every attempt, since it can change while the screen resets. + for attempt in range(1, SERIAL_OPEN_ATTEMPTS + 1): + com_port = self.com_port + if com_port == 'AUTO': + com_port = self.auto_detect_com_port() + if not com_port: + logger.warning( + f"Cannot find COM port automatically, retrying ({attempt}/{SERIAL_OPEN_ATTEMPTS})") + time.sleep(SERIAL_OPEN_RETRY_DELAY) + continue + logger.debug(f"Auto detected COM port: {com_port}") else: - logger.debug(f"Auto detected COM port: {self.com_port}") - else: - logger.debug(f"Static COM port: {self.com_port}") + logger.debug(f"Static COM port: {com_port}") - try: - self.lcd_serial = serial.Serial(self.com_port, 115200, timeout=1, rtscts=True) - except Exception as e: - logger.error(f"Cannot open COM port {self.com_port}: {e}") try: - sys.exit(0) - except: - os._exit(0) + self.lcd_serial = serial.Serial(com_port, 115200, timeout=1, rtscts=True) + return + except Exception as e: + logger.warning( + f"Cannot open COM port {com_port}: {e} - retrying ({attempt}/{SERIAL_OPEN_ATTEMPTS})") + time.sleep(SERIAL_OPEN_RETRY_DELAY) + + logger.error( + f"Cannot open COM port after {SERIAL_OPEN_ATTEMPTS} attempts. If the screen is connected, run " + f"Configuration again and select the COM port manually") + try: + sys.exit(0) + except: + os._exit(0) def closeSerial(self): if self.lcd_serial is not None: