From 0ebcf9cb6acfa241552070075077198266b135e4 Mon Sep 17 00:00:00 2001 From: LowaSC Date: Wed, 19 Feb 2025 21:39:58 +0300 Subject: [PATCH] Enhance command execution with robust error handling and connection monitoring - Add consecutive error tracking and connection state checks - Implement automatic pause and user notification for persistent connection issues - Improve block and line mode execution with enhanced error detection - Modify logging and status reporting for better visibility of execution problems - Add connection verification before and during command execution --- ComConfigCopy.py | 123 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 6 deletions(-) diff --git a/ComConfigCopy.py b/ComConfigCopy.py index aded353..9a9a0a3 100644 --- a/ComConfigCopy.py +++ b/ComConfigCopy.py @@ -633,11 +633,11 @@ def send_command_and_process_response( ): attempt = 0 while attempt < max_attempts: - msg = f"\nОтправка команды: {cmd} (Попытка {attempt+1} из {max_attempts})\n" + msg = f"\nОтправка команды: {cmd}\n" if log_callback: log_callback(msg) serial_connection.write((cmd + "\n").encode()) - logging.info(f"Отправлена команда: {cmd} (Попытка {attempt+1})") + logging.info(f"Отправлена команда: {cmd}") response = read_response(serial_connection, timeout, login=login, password=password, is_gui=is_gui) if response: if '^' in response: @@ -665,7 +665,7 @@ def send_command_and_process_response( logging.warning(f"Нет ответа для команды: {cmd}") return False, None - msg = f"[ERROR] Команда не выполнена корректно после {max_attempts} попыток: {cmd}\n" + msg = f"[ERROR] Команда не выполнена корректно: {cmd}\n" if log_callback: log_callback(msg) logging.error(msg) @@ -1191,6 +1191,57 @@ class SerialAppGUI(tk.Tk): copy_mode = self.settings.get("copy_mode", "line") block_size = self.settings.get("block_size", 15) + # Счетчик последовательных ошибок + consecutive_errors = 0 + MAX_CONSECUTIVE_ERRORS = 3 # Максимальное количество последовательных ошибок + + def check_connection(): + """Проверка состояния соединения""" + if not self.connection or not self.connection.is_open: + self.append_file_exec_text("[ERROR] Соединение потеряно!\n") + # Автоматически ставим на паузу + self.execution_paused = True + self.after(0, lambda: self.pause_button.config(text="▶ Продолжить")) + # Показываем сообщение пользователю + self.after(0, lambda: messagebox.showerror( + "Ошибка соединения", + "Соединение с устройством потеряно!\nВыполнение команд приостановлено.\n\n" + "Пожалуйста:\n" + "1. Проверьте подключение\n" + "2. Нажмите 'Продолжить' после восстановления соединения\n" + " или 'Остановить' для прекращения выполнения" + )) + return False + return True + + def handle_no_response(cmd_or_block, is_block=False): + """Обработка отсутствия ответа от устройства""" + nonlocal consecutive_errors + consecutive_errors += 1 + + if consecutive_errors >= MAX_CONSECUTIVE_ERRORS: + self.append_file_exec_text( + f"[ERROR] Обнаружено {consecutive_errors} последовательных ошибок!\n" + "Возможно, устройство не отвечает или проблемы с соединением.\n" + ) + # Автоматически ставим на паузу + self.execution_paused = True + self.after(0, lambda: self.pause_button.config(text="▶ Продолжить")) + # Показываем сообщение пользователю + self.after(0, lambda: messagebox.showerror( + "Устройство не отвечает", + f"Обнаружено {consecutive_errors} последовательных ошибок!\n\n" + "Возможные причины:\n" + "1. Устройство не отвечает на команды\n" + "2. Проблемы с соединением\n" + "3. Неверный формат команд\n\n" + "Выполнение приостановлено.\n" + "Проверьте подключение и состояние устройства,\n" + "затем нажмите 'Продолжить' или 'Остановить'." + )) + return False + return True + if copy_mode == "line": # Построчный режим while self.current_command_index < len(self.commands): @@ -1201,6 +1252,10 @@ class SerialAppGUI(tk.Tk): time.sleep(0.1) continue + # Проверяем соединение перед каждой командой + if not check_connection(): + continue + cmd = self.commands[self.current_command_index] try: success, response = send_command_and_process_response( @@ -1216,6 +1271,15 @@ class SerialAppGUI(tk.Tk): if not success: self.append_file_exec_text(f"[ERROR] Не удалось выполнить команду: {cmd}\n") + # Проверяем соединение после неудачной попытки + if not check_connection(): + continue + # Обрабатываем отсутствие ответа + if not handle_no_response(cmd): + continue + else: + # Сбрасываем счетчик ошибок при успешном выполнении + consecutive_errors = 0 self.current_command_index += 1 self.after(0, self.update_progress) @@ -1223,6 +1287,8 @@ class SerialAppGUI(tk.Tk): except Exception as e: self.append_file_exec_text(f"[ERROR] Ошибка при выполнении команды: {str(e)}\n") + if not check_connection(): + continue break else: # Блочный режим @@ -1238,15 +1304,20 @@ class SerialAppGUI(tk.Tk): time.sleep(0.1) continue + # Проверяем соединение перед каждым блоком + if not check_connection(): + continue + block = blocks[current_block] try: - self.append_file_exec_text(f"[CMD] Отправка блока команд:\n{block}\n") + # Выводим блок команд без [CMD] префикса + self.append_file_exec_text(f"Выполнение блока команд:\n{block}\n") success, response = send_command_and_process_response( self.connection, block, self.settings.get("timeout", 10), max_attempts=3, - log_callback=self.append_file_exec_text, + log_callback=None, # Отключаем вывод для первой попытки login=self.settings.get("login"), password=self.settings.get("password"), is_gui=True @@ -1254,11 +1325,21 @@ class SerialAppGUI(tk.Tk): if not success or (response and '^' in response): self.append_file_exec_text("[WARNING] Ошибка при выполнении блока команд. Отправляю команды по отдельности...\n") + # Проверяем соединение перед отправкой отдельных команд + if not check_connection(): + continue + + # Обрабатываем отсутствие ответа для блока + if not success and not handle_no_response(block, True): + continue + # Отправляем команды блока по отдельности for cmd in block.splitlines(): if self.execution_stop: break if cmd.strip(): + if not check_connection(): + break success, resp = send_command_and_process_response( self.connection, cmd, @@ -1271,15 +1352,30 @@ class SerialAppGUI(tk.Tk): ) if not success: self.append_file_exec_text(f"[ERROR] Не удалось выполнить команду: {cmd}\n") + if not check_connection(): + break + # Обрабатываем отсутствие ответа для отдельной команды + if not handle_no_response(cmd): + break + else: + # Сбрасываем счетчик ошибок при успешном выполнении + consecutive_errors = 0 + else: + # Если блок выполнился успешно, выводим ответ и сбрасываем счетчик ошибок + consecutive_errors = 0 + if response: + self.append_file_exec_text(f"Ответ устройства:\n{response}\n") # Обновляем прогресс на основе количества выполненных блоков current_block += 1 self.current_command_index = (current_block * 100) // total_blocks self.after(0, self.update_progress) - time.sleep(1) # Задержка между блоками + time.sleep(1) except Exception as e: self.append_file_exec_text(f"[ERROR] Ошибка при выполнении блока команд: {str(e)}\n") + if not check_connection(): + continue break # Завершение выполнения @@ -1294,6 +1390,16 @@ class SerialAppGUI(tk.Tk): self.reset_execution_buttons() def start_execution(self): + # Проверяем подключение перед стартом + if not self.connection or not self.connection.is_open: + self.connection = create_connection(self.settings) + if self.connection: + # Запускаем мониторинг при новом подключении + self.start_port_monitoring() + else: + self.append_file_exec_text("[ERROR] Не удалось установить соединение.\n") + return + if not hasattr(self, 'commands') or not self.commands: self.execution_thread = threading.Thread(target=self.execute_file_commands, daemon=True) self.execution_thread.start() @@ -1307,6 +1413,7 @@ class SerialAppGUI(tk.Tk): self.start_button.config(state="disabled") self.pause_button.config(state="normal") self.stop_button.config(state="normal") + self.update_status_bar() # Обновляем статус бар после подключения def pause_execution(self): if not self.execution_paused: @@ -1348,6 +1455,10 @@ class SerialAppGUI(tk.Tk): self.execution_stop = False self.timer_running = False + # Очищаем список команд, чтобы при следующем старте они загрузились заново + if hasattr(self, 'commands'): + delattr(self, 'commands') + def update_timer(self): """Обновление таймера в главном потоке""" if self.timer_running: