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
This commit is contained in:
2025-02-19 21:39:58 +03:00
parent 99e9163760
commit 0ebcf9cb6a

View File

@@ -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: