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
|
attempt = 0
|
||||||
while attempt < max_attempts:
|
while attempt < max_attempts:
|
||||||
msg = f"\nОтправка команды: {cmd} (Попытка {attempt+1} из {max_attempts})\n"
|
msg = f"\nОтправка команды: {cmd}\n"
|
||||||
if log_callback:
|
if log_callback:
|
||||||
log_callback(msg)
|
log_callback(msg)
|
||||||
serial_connection.write((cmd + "\n").encode())
|
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)
|
response = read_response(serial_connection, timeout, login=login, password=password, is_gui=is_gui)
|
||||||
if response:
|
if response:
|
||||||
if '^' in response:
|
if '^' in response:
|
||||||
@@ -665,7 +665,7 @@ def send_command_and_process_response(
|
|||||||
logging.warning(f"Нет ответа для команды: {cmd}")
|
logging.warning(f"Нет ответа для команды: {cmd}")
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
msg = f"[ERROR] Команда не выполнена корректно после {max_attempts} попыток: {cmd}\n"
|
msg = f"[ERROR] Команда не выполнена корректно: {cmd}\n"
|
||||||
if log_callback:
|
if log_callback:
|
||||||
log_callback(msg)
|
log_callback(msg)
|
||||||
logging.error(msg)
|
logging.error(msg)
|
||||||
@@ -1191,6 +1191,57 @@ class SerialAppGUI(tk.Tk):
|
|||||||
copy_mode = self.settings.get("copy_mode", "line")
|
copy_mode = self.settings.get("copy_mode", "line")
|
||||||
block_size = self.settings.get("block_size", 15)
|
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":
|
if copy_mode == "line":
|
||||||
# Построчный режим
|
# Построчный режим
|
||||||
while self.current_command_index < len(self.commands):
|
while self.current_command_index < len(self.commands):
|
||||||
@@ -1201,6 +1252,10 @@ class SerialAppGUI(tk.Tk):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Проверяем соединение перед каждой командой
|
||||||
|
if not check_connection():
|
||||||
|
continue
|
||||||
|
|
||||||
cmd = self.commands[self.current_command_index]
|
cmd = self.commands[self.current_command_index]
|
||||||
try:
|
try:
|
||||||
success, response = send_command_and_process_response(
|
success, response = send_command_and_process_response(
|
||||||
@@ -1216,6 +1271,15 @@ class SerialAppGUI(tk.Tk):
|
|||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
self.append_file_exec_text(f"[ERROR] Не удалось выполнить команду: {cmd}\n")
|
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.current_command_index += 1
|
||||||
self.after(0, self.update_progress)
|
self.after(0, self.update_progress)
|
||||||
@@ -1223,6 +1287,8 @@ class SerialAppGUI(tk.Tk):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.append_file_exec_text(f"[ERROR] Ошибка при выполнении команды: {str(e)}\n")
|
self.append_file_exec_text(f"[ERROR] Ошибка при выполнении команды: {str(e)}\n")
|
||||||
|
if not check_connection():
|
||||||
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# Блочный режим
|
# Блочный режим
|
||||||
@@ -1238,15 +1304,20 @@ class SerialAppGUI(tk.Tk):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Проверяем соединение перед каждым блоком
|
||||||
|
if not check_connection():
|
||||||
|
continue
|
||||||
|
|
||||||
block = blocks[current_block]
|
block = blocks[current_block]
|
||||||
try:
|
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(
|
success, response = send_command_and_process_response(
|
||||||
self.connection,
|
self.connection,
|
||||||
block,
|
block,
|
||||||
self.settings.get("timeout", 10),
|
self.settings.get("timeout", 10),
|
||||||
max_attempts=3,
|
max_attempts=3,
|
||||||
log_callback=self.append_file_exec_text,
|
log_callback=None, # Отключаем вывод для первой попытки
|
||||||
login=self.settings.get("login"),
|
login=self.settings.get("login"),
|
||||||
password=self.settings.get("password"),
|
password=self.settings.get("password"),
|
||||||
is_gui=True
|
is_gui=True
|
||||||
@@ -1254,11 +1325,21 @@ class SerialAppGUI(tk.Tk):
|
|||||||
|
|
||||||
if not success or (response and '^' in response):
|
if not success or (response and '^' in response):
|
||||||
self.append_file_exec_text("[WARNING] Ошибка при выполнении блока команд. Отправляю команды по отдельности...\n")
|
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():
|
for cmd in block.splitlines():
|
||||||
if self.execution_stop:
|
if self.execution_stop:
|
||||||
break
|
break
|
||||||
if cmd.strip():
|
if cmd.strip():
|
||||||
|
if not check_connection():
|
||||||
|
break
|
||||||
success, resp = send_command_and_process_response(
|
success, resp = send_command_and_process_response(
|
||||||
self.connection,
|
self.connection,
|
||||||
cmd,
|
cmd,
|
||||||
@@ -1271,15 +1352,30 @@ class SerialAppGUI(tk.Tk):
|
|||||||
)
|
)
|
||||||
if not success:
|
if not success:
|
||||||
self.append_file_exec_text(f"[ERROR] Не удалось выполнить команду: {cmd}\n")
|
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
|
current_block += 1
|
||||||
self.current_command_index = (current_block * 100) // total_blocks
|
self.current_command_index = (current_block * 100) // total_blocks
|
||||||
self.after(0, self.update_progress)
|
self.after(0, self.update_progress)
|
||||||
time.sleep(1) # Задержка между блоками
|
time.sleep(1)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.append_file_exec_text(f"[ERROR] Ошибка при выполнении блока команд: {str(e)}\n")
|
self.append_file_exec_text(f"[ERROR] Ошибка при выполнении блока команд: {str(e)}\n")
|
||||||
|
if not check_connection():
|
||||||
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
# Завершение выполнения
|
# Завершение выполнения
|
||||||
@@ -1294,6 +1390,16 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.reset_execution_buttons()
|
self.reset_execution_buttons()
|
||||||
|
|
||||||
def start_execution(self):
|
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:
|
if not hasattr(self, 'commands') or not self.commands:
|
||||||
self.execution_thread = threading.Thread(target=self.execute_file_commands, daemon=True)
|
self.execution_thread = threading.Thread(target=self.execute_file_commands, daemon=True)
|
||||||
self.execution_thread.start()
|
self.execution_thread.start()
|
||||||
@@ -1307,6 +1413,7 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.start_button.config(state="disabled")
|
self.start_button.config(state="disabled")
|
||||||
self.pause_button.config(state="normal")
|
self.pause_button.config(state="normal")
|
||||||
self.stop_button.config(state="normal")
|
self.stop_button.config(state="normal")
|
||||||
|
self.update_status_bar() # Обновляем статус бар после подключения
|
||||||
|
|
||||||
def pause_execution(self):
|
def pause_execution(self):
|
||||||
if not self.execution_paused:
|
if not self.execution_paused:
|
||||||
@@ -1348,6 +1455,10 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.execution_stop = False
|
self.execution_stop = False
|
||||||
self.timer_running = False
|
self.timer_running = False
|
||||||
|
|
||||||
|
# Очищаем список команд, чтобы при следующем старте они загрузились заново
|
||||||
|
if hasattr(self, 'commands'):
|
||||||
|
delattr(self, 'commands')
|
||||||
|
|
||||||
def update_timer(self):
|
def update_timer(self):
|
||||||
"""Обновление таймера в главном потоке"""
|
"""Обновление таймера в главном потоке"""
|
||||||
if self.timer_running:
|
if self.timer_running:
|
||||||
|
|||||||
Reference in New Issue
Block a user