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:
123
ComConfigCopy.py
123
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:
|
||||
|
||||
Reference in New Issue
Block a user