python写的window小工具-一键设置ip自动获取ip

最近有个需求,笔记本在公司上网需要设置固定ip,拿回家之后又要设置自动获取ip,有些美女同事根本就不知道怎么设置,所以我打算开发一个一键设置的小软件供大家使用。

但是不会c++,也不会c#,更加不会vb,不可能使用Java开发桌面吧,思来想去,只能使用python了,因为python无所不能嘛,但是打包之后,这个小软件的体积居然达到了40M,实在是不忍心啊。

闲言少叙,开始编码。

先看结果

总体来说,python写代码真的非常简单,基本上一个小时就可以完成编码和测试。

下面把源码发布,大家自行复制下载。


import subprocess
import sys
from PySide6.QtWidgets import 
请解析我的代码 import json import os import threading import PySimpleGUI as sg import telnetlib import time import queue import logging from datetime import datetime import re # ============== 全局配置 ============== DATA_FILE = 'pyremote_config.json' PROJECTS_FILE = 'projects_config.json' END_STR = "ROUTER_MPU /home\x1b[m # " LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' ENCODING = 'utf-8' BUFFER_SIZE = 4096 CHUNK_SIZE = 10 CHUNK_DELAY = 0.15 COMMAND_DELAY = 0.5 MAX_PORTS = 2 # 支持的最大端口数 AUTO_OPERATION_SUCCESS_STR = "Close watchdog" # 自动操作成功标志 BOOT_STRING = r"Press\s*'Ctrl\+T'\s*to\s*skip\s*boot" # 引导字符串正则表达式 # ============== 日志配置 ============== def setup_logger(): """配置日志系统""" logger = logging.getLogger('RemoteControl') logger.setLevel(logging.DEBUG) # 文件处理器 file_handler = logging.FileHandler('remote_control.log') file_handler.setFormatter(logging.Formatter(LOG_FORMAT)) # 控制台处理器 console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter(LOG_FORMAT)) logger.addHandler(file_handler) logger.addHandler(console_handler) return logger logger = setup_logger() # ============== 项目管理类 ============== class ProjectManager: def __init__(self): self.projects = self.load_projects() def load_projects(self): """加载项目配置""" if os.path.exists(PROJECTS_FILE): try: with open(PROJECTS_FILE, 'r') as f: return json.load(f) except Exception as e: logger.error(f"加载项目配置失败: {e}") return {"projects": []} return {"projects": []} def save_projects(self): """保存项目配置""" try: with open(PROJECTS_FILE, 'w') as f: json.dump(self.projects, f, indent=4) return True except Exception as e: logger.error(f"保存项目配置失败: {e}") return False def add_project(self, name, commands, auto_operation=False): """添加新项目""" project = { "name": name, "commands": commands, "auto_operation": auto_operation, # 新增:自动操作标志 "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } self.projects["projects"].append(project) if self.save_projects(): return project return None def update_project(self, index, name, commands, auto_operation=False): """更新项目""" if 0 <= index < len(self.projects["projects"]): self.projects["projects"][index]["name"] = name self.projects["projects"][index]["commands"] = commands self.projects["projects"][index]["auto_operation"] = auto_operation # 新增 if self.save_projects(): return True return False def delete_project(self, index): """删除项目""" if 极 <= index < len(self.projects["projects"]): del self.projects["projects"][index] return self.save_projects() return False def import_projects(self, file_path): """导入项目配置""" try: with open(file_path, 'r') as f: imported = json.load(f) if "projects" in imported and isinstance(imported["projects"], list): self.projects = imported return self.save_projects() except Exception as e: logger.error(f"导入项目失败: {e}") return False def export_projects(self, file极ath): """导出项目配置""" try: with open(file_path, 'w') as f: json.dump(self.projects, f, indent=4) return True except Exception as e: logger.error(f"导出项目失败: {e}") return False def get_project_commands(self, index): """获取项目的命令列表""" if 0 <= index < len(self.projects["projects"]): return self.projects["projects"][index]["commands"] return [] # ============== 指令执行类(多端口支持) ============== class CommandExecutor: def __init__(self, port_id): self.port_id = port_id # 端口标识符 (1, 2, ...) self.tn = None self.is_connected = False self.response = "" self.prev_cmd = "" self.log_queue = queue.Queue() self.lock = threading.Lock() self.stop_event = threading.Event() self.pause_event = threading.Event() self.last_response = "" self.expected_prompt = END_STR self.current_command_index = -1 self.current_command = "" self.total_commands = 0 self.log_file = None # 日志文件对象 self.log_file_path = "" # 日志文件路径 self.auto_mode = False self.boot_string_detected = False # 引导字符串检测标志 self.auto_completed = False # 自动操作完成标志 self.auto_operation_callback = None # 新增:自动操作成功回调 def set_log_file(self, file_path): """设置日志文件路径""" self.log_file_path = file_path try: if self.log_file: self.log_file.close() self.log_file = open(file_path, 'a', encoding=ENCODING) return True except Exception as e: self.log_queue.put(f"打开日志文件失败: {str(e)}") return False def log_to_file(self, message): """记录日志到文件""" if self.log_file: try: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] self.log_file.write(f"[{timestamp}] [Port {self.port_id}] {message}\n") self.log_file.flush() except Exception as e: self.log_queue.put(f"日志入失败: {str(e)}") def connect(self, host, port): """连接设备""" try: with self.lock: self.tn = telnetlib.Telnet(host, port, timeout=10) self.is_connected = True self.log_queue.put(f"端口 {self.port_id} 已连接到 {host}:{port}") self.log_to_file(f"Connected to {host}:{port}") # 初始读取以清除欢迎信息 self.read_until_prompt(timeout=3) # 重置自动操作状态 self.boot_string_detected = False self.auto_completed = False return True except Exception as e: self.log_queue.put(f"端口 {self.port_id} 连接失败: {str(e)}") return False def disconnect(self): """断开连接""" with self.lock: if self.tn: try: self.tn.close() except: pass self.is_connected = False self.log_queue.put(f"端口 {self.port_id} 连接已断开") self.log_to_file("Disconnected") if self.log_file: try: self.log_file.close() except: pass self.log_file = None def send(self, content): """发送命令(分块发送)""" if not self.is_connected: self.log_queue.put(f"端口 {self.port_id} 错误:未连接到设备") return False try: with self.lock: # 保存当前命令 self.current_command = content # 使用正确的编码发送 encoded_content = content.encode(ENCODING) # 分块发送 chunks = [encoded_content[i:i+CHUNK_SIZE] for i in range(0, len(encoded_content), CHUNK_SIZE)] for chunk in chunks: if self.stop_event.is_set(): self.log_queue.put(f"端口 {self.port_id} 发送已中止") return False while self.pause_event.is_set(): time.sleep(0.1) if self.stop_event.is_set(): return False self.tn.write(chunk) log_msg = f"发送分块: {chunk.decode(ENCODING, errors='replace')}" self.log_queue.put(log_msg) self.log_to_file(log_msg) time.sleep(CHUNK_DELAY) # 发送回车符 self.tn.write(b"\r\n") self.log_queue.put(f"端口 {self.port_id} 发送回车符") self.log_to_file("Sent ENTER") self.log_queue.put(f"端口 {self.port_id} 完整发送: {content.strip()}") self.log_to_file(f"Sent: {content.strip()}") self.prev_cmd = content return True except Exception as e: self.log_queue.put(f"端口 {self.port_id} 发送命令失败: {str(e)}") self.log_to_file(f"Send error: {str(e)}") return False def read_until_prompt(self, timeout=5): """读取直到遇到提示符""" if not self.is_connected: return "" try: response = self.tn.read_until(self.expected_prompt.encode(ENCODING), timeout=timeout) decoded_response = response.decode(ENCODING, errors='replace') # 移除命令回显 if self.prev_cmd and decoded_response.startswith(self.prev_cmd.strip()): decoded_response = decoded_response[len(self.prev_cmd.strip()):].lstrip() # 移除尾部的提示符 if decoded_response.endswith(self.expected_prompt): decoded_response = decoded_response[:-len(self.expected_prompt)].rstrip() self.last_response = decoded_response # 记录到日志 if decoded_response.strip(): self.log_queue.put(f"端口 {self.port_id} 响应: {decoded_response}") self.log_to_file(f"Response: {decoded_response}") return decoded_response except Exception as e: error_msg = f"端口 {self.port_id} 接收响应失败: {str(e)}" self.log_queue.put(error_msg) self.log_to_file(error_msg) return "" def execute_commands(self, commands): """执行命令序列(增强版)""" if not self.is_connected: self.log_queue.put(f"端口 {self.port_id} 错误:未连接到设备") return False self.stop_event.clear() self.pause_event.clear() self.total_commands = len(commands) self.log_queue.put(f"端口 {self.port_id} 开始执行 {self.total_commands} 条命令") self.log_to_file(f"Starting execution of {self.total_commands} commands") try: for idx, cmd in enumerate(commands): if self.stop_event.is_set(): self.log_queue.put(f"端口 {self.port_id} 命令执行已中止") self.log_to_file("Execution aborted") return False # 设置当前命令索引 self.current_command_index = idx # 检查暂停状态 while self.pause_event.is_set(): time.sleep(0.1) if self.stop_event.is_set(): return False if cmd.strip(): # 跳过空行 # 发送命令 if not self.send(cmd): return False # 等待命令完成 self.read_until_prompt(timeout=10) # 命令间延迟 delay_remaining = COMMAND_DELAY while delay_remaining > 0: if self.stop_event.is_set(): return False if self.pause_event.is_set(): time.sleep(0.1) continue time.sleep(0.1) delay_remaining -= 0.1 self.log_queue.put(f"端口 {self.port_id} 命令执行完成") self.log_to_file("Execution completed") self.current_command_index = -1 return True except Exception as e: error_msg = f"端口 {self.port_id} 命令执行失败: {str(e)}" self.log_queue.put(error_msg) self.log_to_file(error_msg) return False def stop_execution(self): """停止当前执行""" self.stop_event.set() self.log_queue.put(f"端口 {self.port_id} 正在停止执行...") self.log_to_file("Stopping execution") def pause_execution(self): """暂停当前执行""" if not self.pause_event.is_set(): self.pause_event.set() self.log_queue.put(f"端口 {self.port_id} 执行已暂停") self.log_to_file("Execution paused") return True return False def resume_execution(self): """继续执行""" if self.pause_event.is_set(): self.pause_event.clear() self.log_queue.put(f"端口 {self.port_id} 执行已继续") self.log_to_file("Execution resumed") return True return False def get_execution_status(self): """获取执行状态""" return { "port_id": self.port_id, "is_connected": self.is_connected, "is_running": not self.stop_event.is_set() and not self.pause_event.is_set(), "is_paused": self.pause_event.is_set(), "is_stopped": self.stop_event.is_set(), "current_command": self.current_command.strip(), "current_index": self.current_command_index, "total_commands": self.total_commands, "log_file_path": self.log_file_path, "boot_string_detected": self.boot_string_detected, "auto_completed": self.auto_completed } # ============== 增强自动操作功能 ============== def detect_boot_string_and_auto_operation(self): """检测引导字符串并执行自动操作""" if not self.is_connected or self.auto_completed: return False try: # 读取响应并检测引导字符串 response = self.read_until_prompt(timeout=1) if re.search(BOOT_STRING, response, re.IGNORECASE): self.boot_string_detected = True self.log_queue.put(f"端口 {self.port_id} 检测到引导字符串,执行自动操作") self.log_to_file("Detected boot string, performing auto operation") # 在1秒内发送Ctrl+T self.log_queue.put(f"端口 {self.port_id} 发送 Ctrl+T") self.log_to_file("Sending Ctrl+T") self.send_ctrl_t() # 等待5秒后发送watchdog命令 time.sleep(6) self.log_queue.put(f"端口 {self.port_id} 发送 watchdog -close") self.log_to_file("Sending watchdog -close") self.send("watchdog -close") # 等待命令完成并检查响应 watchdog_response = self.read_until_prompt(timeout=5) if AUTO_OPERATION_SUCCESS_STR in watchdog_response: self.log_queue.put(f"端口 {self.port_id} watchdog命令执行成功") self.auto_completed = True # 如果设置了回调,执行回调(触发升级) if self.auto_operation_callback: self.log_queue.put(f"端口 {self.port_id} 触发自动升级") self.auto_operation_callback() else: self.log_queue.put(f"端口 {self.port_id} watchdog命令执行失败") self.log_to_file(f"Watchdog命令失败,响应: {watchdog_response}") return self.auto_completed except Exception as e: self.log_queue.put(f"端口 {self.port_id} 自动操作失败: {str(e)}") self.log_to_file(f"Auto operation failed: {str(e)}") return False def perform_auto_operation(self, callback=None): """执行自动操作(带重试)""" # 设置回调函数 self.auto_operation_callback = callback # 尝试检测引导字符串 success = self.detect_boot_string_and_auto_operation() # 如果未检测到,尝试多次检测 if not self.boot_string_detected: for _ in range(10): # 最多尝试3次 time.sleep(1) success = self.detect_boot_string_and_auto_operation() if success: break return success def send_ctrl_t(self): """发送Ctrl+T组合键""" if not self.is_connected: return False try: with self.lock: # Ctrl+T 的ASCII码是20 self.tn.write(b"\x14") self.log_queue.put(f"端口 {self.port_id} 已发送 Ctrl+T") self.log_to_file("Sent Ctrl+T") return True except Exception as e: self.log_queue.put(f"端口 {self.port_id} 发送Ctrl+T失败: {str(e)}") self.log_to_file(f"Send Ctrl+T error: {str(e)}") return False # ============== GUI 界面类(多端口支持) ============== class RemoteControlApp: def __init__(self): self.project_manager = ProjectManager() self.default_data = self.load_default_data() self.executors = {} # 端口ID到执行器的映射 self.window = None self.setup_gui() self.running = True # 初始化端口执行器 for port_id in range(1, MAX_PORTS + 1): self.executors[port_id] = CommandExecutor(port_id) def load_default_data(self): """加载默认配置""" default_data = { "IP1": "71.19.0.120", "port1": "1001", "IP2": "71.19.0.120", "port2": "1002", "FTP_IP": "71.19.0.120", "芯片名称": "Hi1260SV100", '发送信息': "", "board_local_ip": "71.19.0.53", 'interval': "1", "start_addr": "", "end_addr": "", "文件FTP路径": "", "log_dir": os.getcwd() # 默认日志目录 } if os.path.exists(DATA_FILE): try: with open(DATA_FILE, 'r') as f: data = json.load(f) default_data.update({k: data[k] for k in default_data if k in data}) except Exception as e: logger.error(f"加载默认配置失败: {e}") with open(DATA_FILE, 'w') as f: json.dump(default_data, f) else: with open(DATA_FILE, 'w') as f: json.dump(default_data, f) return default_data def save_config(self): """保存配置""" try: values = self.window.read()[1] if self.window else {} config = { "IP1": values.get("IP1", self.default_data["极1"]), "port1": values.get("port1", self.default_data["port1"]), "IP2": values.get("IP2", self.default_data["IP2"]), "port2": values.get("port2", self.default_data["port2"]), "FTP_IP": values.get("FTP_IP", self.default_data["FTP_IP"]), "芯片名称": values.get("芯片名称", self.default_data["芯片名称"]), '发送信息': values.get("发送信息", self.default_data["发送信息"]), "board_local_ip": values.get("board_local_ip", self.default_data["board_local_ip"]), 'interval': values.get("interval", self.default_data["interval"]), "start_addr": values.get("start_addr", self.default_data["start_addr"]), "end_addr": values.get("end_addr", self.default_data["end_addr"]), "文件FTP路径": values.get("文件FTP路径", self.default_data["文件FTP路径"]), "log_dir": values.get("log_dir", self.default_data["log_dir"]) } with open(DATA_FILE, 'w') as f: json.dump(config, f) self.default_data = config return True except Exception as e: logger.error(f"保存配置失败: {e}") return False def create_project_buttons(self): """创建项目按钮区域(增加自动操作状态)""" layout = [] projects = self.project_manager.projects["projects"] if not projects: layout.append([sg.Text("没有项目,请添加新项目", text_color='red')]) for i, project in enumerate(projects): # 添加自动操作状态指示器 auto_status = '✓' if project.get("auto_operation", False) else '○' auto_color = 'green' if project.get("auto_operation", False) else 'gray' row = [ sg.Button(project["name"], key=f'-PROJECT-{i}-', size=(15,1), tooltip=f"创建于: {project['created_at']}\n命令数: {len(project['commands'])}"), sg.Text(auto_status, text_color=auto_color, font=('Arial', 12), tooltip="自动操作: ○禁用 ✓启用", size=(2,1)), sg.Button("一键升级", key=f'-UPGRADE-{i}-', button_color=('white', 'green')), sg.Button("自动", key=f'-AUTO-{i}-', button_color=('white', 'purple'), tooltip="执行自动操作并触发升级"), sg.Button("编辑", key=f'-EDIT-{i}-', button_color=('white', 'blue')), sg.Button("删除", key=f'-DELETE-{i}-', button_color=('white', 'red')) ] layout.append(row) # 添加项目管理按钮 layout.append([ sg.Button("添加新项目", key='-ADD-PROJECT-', button_color=('white', 'purple')), sg.Button("导入项目", key='-IMPORT-PROJECTS-'), sg.Button("导出项目", key='-EXPORT-PROJECTS-'), sg.Button("生成模板", key='-CREATE-TEMPLATE-') ]) return layout def edit_project_window(self, index=None): """项目编辑窗口(增加自动操作选项)""" project = None if index is not None and 0 <= index < len(self.project_manager.projects["projects"]): project = self.project_manager.projects["projects"][index] layout = [ [sg.Text("项目名称:"), sg.Input(key='-PROJECT-NAME-', default_text=project["name"] if project else "")], [sg.Checkbox("启用自动操作", key='-AUTO-OPERATION-', default=project.get("auto_operation", False) if project else False, tooltip="如果启用,将在执行升级命令前自动检测引导字符串并执行Ctrl+T和watchdog -close")], [sg.Text("升级指令:")], [sg.Multiline(key='-PROJECT-COMMANDS-', size=(60, 10), default_text='\n'.join(project["commands"]) if project else "", tooltip="每行一个命令,命令将按顺序执行")], [sg.Button("保存", key='-SAVE-PROJECT-'), sg.Button("取消", key='-CANCEL-PROJECT-')] ] window = sg.Window("项目编辑", layout, modal=True) while True: event, values = window.read() if event in (sg.WINDOW_CLOSED, '-CANCEL-PROJECT-'): break elif event == '-SAVE-PROJECT-': name = values['-PROJECT-NAME-'].strip() commands = [cmd.strip() for cmd in values['-PROJECT-COMMANDS-'].split('\n') if cmd.strip()] auto_operation = values['-AUTO-OPERATION-'] # 获取自动操作选项 if not name: sg.popup("项目名称不能为空") continue if index is None: new_project = self.project_manager.add_project(name, commands, auto_operation) if new_project: sg.popup(f"项目 '{name}' 添加成功") break else: if self.project_manager.update_project(index, name, commands, auto_operation): sg.popup(f"项目 '{name}' 更新成功") break sg.popup("操作失败,请查看日志") window.close() return True def setup_gui(self): """设置GUI界面(多端口支持)""" sg.theme('LightBlue1') # 输出区域 output = sg.Multiline( size=(80, 20), key='-OUTPUT-', autoscroll=True, background_color='#f0f0f0', text_color='black' ) # 状态信息区域 status_info = [ sg.Text("当前命令: ", size=(10,1)), sg.Text("无", key='-CURRENT-COMMAND-', size=(40,1), text_color='blue'), sg.Text("进度: ", size=(5,1)), sg.Text("0/0", key='-COMMAND-PROGRESS-', size=(10,1)) ] # 项目列表区域 projects_frame = sg.Frame("项目列表", [ [sg.Column( self.create_project_buttons(), scrollable=True, vertical_scroll_only=True, size=(700, 100), key='-PROJECTS-COLUMN-' )] ], key='-PROJECTS-FRAME-') # 执行控制区域 control_buttons = [ sg.Button('暂停执行', key='-PAUSE-EXECUTION-', button_color=('white', 'orange'), size=(10,1)), sg.Button('继续执行', key='-RESUME-EXECUTION-', button_color=('white', 'green'), size=(10,1)), sg.Button('停止执行', key='-STOP-EXECUTION-', button_color=('white', 'red'), size=(10,1)), ] # 端口连接区域 port_layouts = [] for port_id in range(1, MAX_PORTS + 1): port_layout = [ sg.Text(f'端口 {port_id} IP:', size=(8,1)), sg.Input(key=f"IP{port_id}", default_text=self.default_data[f"IP{port_id}"], size=(15,1)), sg.Text('端口:', size=(5,1)), sg.Input(key=f"port{port_id}", default_text=self.default_data[f"port{port_id}"], size=(8,1)), sg.Button(f'连接{port_id}', key=f'-CONNECT-{port_id}-', button_color=('white', 'green')), sg.Button(f'断开{port_id}', key=f'-DISCONNECT-{port_id}-', button_color=('white', 'red')), sg.Text('●', key=f'-STATUS-LIGHT-{port_id}-', text_color='red', font=('Arial', 12)), sg.Text("未连接", key=f'-CONNECTION-STATUS-{port_id}-'), # 自动操作状态指示器 sg.Text('○', key=f'-AUTO-STATUS-{port_id}-', text_color='gray', font=('Arial', 12), tooltip="自动操作状态: ○未执行 ●已检测到引导字符串 ✓已完成") ] port_layouts.append(port_layout) # 日志保存区域 log_layout = [ sg.Text('日志目录:', size=(8,1)), sg.Input(key='log_dir', default_text=self.default_data["log_dir"], size=(40,1)), sg.FolderBrowse('浏览', key='-LOG-BROWSE-'), sg.Button('设置日志目录', key='-SET-LOG-DIR-') ] # 主布局 layout = [ # 端口连接区域 *port_layouts, [projects_frame], status_info, # 执行控制按钮 [sg.Frame("执行控制", [control_buttons], key='-CONTROL-FRAME-')], [sg.Text("发送信息:", size=(8,1)), sg.Input(key='发送信息', size=(50, 1), default_text=self.default_data["发送信息"])], [sg.Button('ROUTER_MPU下发送'), sg.Button('Shell下发送'), sg.Text('每隔', size=(3,1)), sg.Input(key='interval', default_text=self.default_data["interval"], size=(5,1)), sg.Text("秒", size=(2,1)), sg.Button('定时发送'), sg.Button("停止定时发送")], [sg.Button('接收1s')], [sg.Button("使用说明", button_color=('white', 'blue'))], [sg.Text('起始地址:', size=(8,1)), sg.Input(key='start_addr', default_text=self.default_data["start_addr"], size=(12,1)), sg.Text('结束地址:', size=(8,1)), sg.Input(key='end_addr', default_text=self.default_data["end_addr"], size=(12,1)), sg.Button('dump寄存器')], # 日志保存区域 log_layout, [output], [sg.StatusBar("就绪", key='-STATUS-', size=(50, 1))] ] self.window = sg.Window('远程单板连接工具 (多端口)', layout, finalize=True, resizable=True) self.update_status_lights() self.update_auto_status() def update_status_lights(self): """更新所有端口的状态指示灯""" for port_id in self.executors: executor = self.executors[port_id] color = 'green' if executor.is_connected else 'red' status = "已连接" if executor.is_connected else "未连接" self.window[f'-STATUS-LIGHT-{port_id}-'].update(text_color=color) self.window[f'-CONNECTION-STATUS-{port_id}-'].update(status) def update_auto_status(self): """更新所有端口的自动操作状态指示器""" for port_id in self.executors: executor = self.executors[port_id] if executor.auto_completed: # 已完成:绿色勾号 self.window[f'-AUTO-STATUS-{port_id}-'].update('✓', text_color='green') elif executor.boot_string_detected: # 已检测到引导字符串:红色圆点 self.window[f'-AUTO-STATUS-{port_id}-'].update('●', text_color='red') else: # 未执行:灰色圆圈 self.window[f'-AUTO-STATUS-{port_id}-'].update('○', text_color='gray') def update_output(self): """更新输出区域""" output_text = self.window['-OUTPUT-'].get() updated = False # 遍历所有端口的日志队列 for port_id, executor in self.executors.items(): while not executor.log_queue.empty(): try: message = executor.log_queue.get_nowait() output_text += message + '\n' updated = True except queue.Empty: break if updated: self.window['-OUTPUT-'].update(output_text) def update_status(self): """更新状态信息""" # 更新执行状态 for port_id, executor in self.executors.items(): status = executor.get_execution_status() # 更新当前命令显示 if status["current_command"] and port_id == 1: # 只显示第一个端口的命令 self.window['-CURRENT-COMMAND-'].update(status["current_command"]) # 更新进度显示 if status["current_index"] >= 0 and status["total_commands"] > 0: progress_text = f"{status['current_index'] + 1}/{status['total_commands']}" self.window['-COMMAND-PROGRESS-'].update(progress_text) # 更新状态指示灯 color = 'green' if status["is_connected"] else 'red' self.window[f'-STATUS-LIGHT-{port_id}-'].update(text_color=color) self.window[f'-CONNECTION-STATUS-{port_id}-'].update("已连接" if status["is_connected"] else "未连接") # 更新自动操作状态 self.update_auto_status() # 更新按钮状态(基于第一个端口的状态) if self.executors[1].is_connected: status1 = self.executors[1].get_execution_status() if status1["is_running"]: self.window['-PAUSE-EXECUTION-'].update(disabled=False) self.window['-RESUME-EXECUTION-'].update(disabled=True) self.window['-STOP-EXECUTION-'].update(disabled=False) elif status1["is_paused"]: self.window['-PAUSE-EXECUTION-'].update(disabled=True) self.window['-RESUME-EXECUTION-'].update(disabled=False) self.window['-STOP-EXECUTION-'].update(disabled=False) else: self.window['-PAUSE-EXECUTION-'].update(disabled=True) self.window['-RESUME-EXECUTION-'].update(disabled=True) self.window['-STOP-EXECUTION-'].update(disabled=True) def refresh_project_list(self): """刷新项目列表""" self.window['-PROJECTS-COLUMN-'].update(visible=False) self.window['-PROJECTS-COLUMN-'].update(self.create_project_buttons()) self.window['-PROJECTS-COLUMN-'].update(visible=True) def run(self): """运行主循环(多端口支持)""" last_status_update = time.time() stop_loop = 0 interval = 10000 loop_msg = "" while True: event, values = self.window.read(timeout=100) # 100ms超时 if event == sg.WINDOW_CLOSED: break # 更新输出区域 self.update_output() # 定期更新状态(每0.5秒一次) current_time = time.time() if current_time - last_status_update > 0.5: self.update_status() last_status_update = current_time # 端口连接管理 if event.startswith('-CONNECT-'): port_id = int(event.split('-')[2]) ip_key = f"IP{port_id}" port_key = f"port{port_id}" if values[ip_key] and values[port_key]: if self.executors[port_id].connect(values[ip_key], int(values[port_key])): self.window['-STATUS-'].update(f"端口 {port_id} 已连接") self.update_status_lights() else: sg.popup(f"请输入端口 {port_id} 的IP和端口号") elif event.startswith('-DISCONNECT-'): port_id = int(event.split('-')[2]) self.executors[port_id].disconnect() self.window['-STATUS-'].update(f"端口 {port_id} 已断开") self.update_status_lights() # 日志目录设置 elif event == '-SET-LOG-DIR-': if 'log_dir' in values and values['log_dir']: self.default_data["log_dir"] = values['log_dir'] self.save_config() sg.popup(f"日志目录已设置为: {values['log_dir']}") # 项目管理 elif event == '-ADD-PROJECT-': self.edit_project_window() self.refresh_project_list() elif event.startswith('-EDIT-'): index = int(event.split('-')[2]) self.edit_project_window(index) self.refresh_project_list() elif event.startswith('-DELETE-'): index = int(event.split('-')[2]) if self.project_manager.delete_project(index): sg.popup("项目删除成功") self.refresh_project_list() else: sg.popup("项目删除失败") elif event == '-IMPORT-PROJECTS-': file_path = sg.popup_get_file("选择项目配置文件", file_types=(("JSON Files", "*.json"),)) if file_path and self.project_manager.import_projects(file_path): sg.popup("项目导入成功") self.refresh_project_list() else: sg.popup("项目导入失败") elif event == '-EXPORT-PROJECTS-': file_path = sg.popup_get_file("保存项目配置文件", save_as=True, file_types=(("JSON Files", "*.json"),)) if file_path and self.project_manager.export_projects(file_path): sg.popup("项目导出成功") else: sg.popup("项目导出失败") elif event == '-CREATE-TEMPLATE-': self.create_template_file() sg.popup("模板文件已生成: projects_template.json") # 一键升级(多端口支持) elif event.startswith('-UPGRADE-'): index = int(event.split('-')[2]) if index < len(self.project_manager.projects["projects"]): project = self.project_manager.projects["projects"][index] # 选择端口对话框 port_layout = [ [sg.Text(f"选择执行 {project['name']} 的端口:")], *[[sg.Checkbox(f"端口 {port_id}", key=f'-PORT-{port_id}-', default=True)] for port_id in self.executors], [sg.Button("确定"), sg.Button("取消")] ] port_window = sg.Window("选择端口", port_layout, modal=True) port_event, port_values = port_window.read() port_window.close() if port_event == "确定": selected_ports = [port_id for port_id in self.executors if port_values[f'-PORT-{port_id}-']] if not selected_ports: sg.popup("请至少选择一个端口") continue # 设置日志文件 log_dir = self.default_data["log_dir"] timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") project_name_safe = re.sub(r'[\\/*?:"<>|]', "", project["name"]) for port_id in selected_ports: log_file = os.path.join(log_dir, f"{project_name_safe}_port{port_id}_{timestamp}.log") self.executors[port_id].set_log_file(log_file) # 在新线程中执行升级 threading.Thread( target=self.execute_project_upgrade, args=(index, selected_ports), daemon=True ).start() # 自动操作按钮 elif event.startswith('-AUTO-'): index = int(event.split('-')[2]) if index < len(self.project_manager.projects["projects"]): project = self.project_manager.projects["projects"][index] # 选择端口对话框 port_layout = [ [sg.Text(f"选择执行 {project['name']} 自动操作的端口:")], *[[sg.Checkbox(f"端口 {port_id}", key=f'-PORT-{port_id}-', default=True)] for port_id in self.executors], [sg.Button("确定"), sg.Button("取消")] ] port_window = sg.Window("选择端口", port_layout, modal=True) port_event, port_values = port_window.read() port_window.close() if port_event == "确定": selected_ports = [port_id for port_id in self.executors if port_values[f'-PORT-{port_id}-']] if not selected_ports: sg.popup("请至少选择一个端口") continue # 设置日志文件 log_dir = self.default_data["log_dir"] timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") project_name_safe = re.sub(r'[\\/*?:"<>|]', "", project["name"]) for port_id in selected_ports: log_file = os.path.join(log_dir, f"{project_name_safe}_auto_port{port_id}_{timestamp}.log") self.executors[port_id].set_log_file(log_file) # 在新线程中执行自动操作 threading.Thread( target=self.execute_project_auto_operation, args=(index, selected_ports), daemon=True ).start() # 执行控制 elif event == '-PAUSE-EXECUTION-': for executor in self.executors.values(): if executor.get_execution_status()["is_running"]: executor.pause_execution() self.window['-STATUS-'].update("执行已暂停") elif event == '-RESUME-EXECUTION-': for executor in self.executors.values(): if executor.get_execution_status()["is_paused"]: executor.resume_execution() self.window['-STATUS-'].update("执行已继续") elif event == '-STOP-EXECUTION-': for executor in self.executors.values(): executor.stop_execution() self.window['-STATUS-'].update("执行已停止") # 其他功能 elif event == 'ROUTER_MPU下发送': if self.save_config() and values["发送信息"]: for port_id, executor in self.executors.items(): if executor.is_connected: executor.send(values["发送信息"]) executor.read_until_prompt() elif event == 'Shell下发送': if self.save_config() and values["发送信息"]: for port_id, executor in self.executors.items(): if executor.is_connected: executor.send(values["发送信息"]) executor.read_until_prompt() elif event == '定时发送': if self.save_config() and values["发送信息"] and values["interval"]: try: interval = float(values["interval"]) if interval <= 0: raise ValueError("间隔必须大于0") loop_msg = values["发送信息"] threading.Thread( target=self.periodic_send, args=(loop_msg, interval), daemon=True ).start() except Exception as e: sg.popup(f"无效的间隔: {str(e)}") else: sg.popup("请输入发送信息和有效间隔") elif event == "停止定时发送": for executor in self.executors.values(): executor.stop_execution() elif event == '接收1s': for executor in self.executors.values(): if executor.is_connected: executor.read_until_prompt(timeout=1) elif event == 'dump寄存器': if values["start_addr"] and values["end_addr"]: for executor in self.executors.values(): if executor.is_connected: executor.send(f"dump {values['start_addr']} {values['end_addr']}") executor.read_until_prompt() elif event == '重新获取sdk.out': for executor in self.executors.values(): if executor.is_connected: executor.send("get_sdk.out") executor.read_until_prompt() elif event == '一键升级MT1': for executor in self.executors.values(): if executor.is_connected: executor.send("upgrade_mt1") executor.read_until_prompt() elif event == '一键升级MT2': for executor in self.executors.values(): if executor.is_connected: executor.send("upgrade_mt2") executor.read_until_prompt() elif event == '使用说明': self.show_help() self.running = False for executor in self.executors.values(): executor.disconnect() self.window.close() def execute_project_auto_operation(self, index, port_ids): """执行项目自动操作并触发升级""" project = self.project_manager.projects["projects"][index] commands = project["commands"] # 为每个端口启动自动操作线程 threads = [] for port_id in port_ids: executor = self.executors[port_id] # 设置自动操作回调(触发升级) upgrade_callback = lambda e=executor, c=commands: self._execute_upgrade_commands(e, c) thread = threading.Thread( target=self._perform_auto_operation_on_port, args=(executor, upgrade_callback, port_id), daemon=True ) thread.start() threads.append(thread) # 等待所有线程完成 for thread in threads: thread.join(timeout=300) # 5分钟超时 self.window['-STATUS-'].update("自动操作完成") def _perform_auto_operation_on_port(self, executor, upgrade_callback, port_id): """在单个端口上执行自动操作""" self.window['-STATUS-'].update(f"端口 {port_id} 开始自动操作...") success = executor.perform_auto_operation(callback=upgrade_callback) self.window['-STATUS-'].update(f"端口 {port_id} 自动操作{'成功' if success else '失败'}") def _execute_upgrade_commands(self, executor, commands): """执行升级命令序列""" return executor.execute_commands(commands) def execute_project_upgrade(self, index, port_ids): """在指定端口上执行项目升级""" commands = self.project_manager.get_project_commands(index) if commands: # 重置进度显示 self.window['-CURRENT-COMMAND-'].update("") self.window['-COMMAND-PROGRESS-'].update("0/0") # 为每个端口启动升级线程 threads = [] for port_id in port_ids: executor = self.executors[port_id] thread = threading.Thread( target=self._execute_upgrade_on_port, args=(executor, commands, port_id), daemon=True ) thread.start() threads.append(thread) # 等待所有线程完成 for thread in threads: thread.join(timeout=300) # 5分钟超时 self.window['-STATUS-'].update("升级任务已完成") else: for port_id in port_ids: self.executors[port_id].log_queue.put("错误:项目没有配置命令") def _execute_upgrade_on_port(self, executor, commands, port_id): """在单个端口上执行升级命令""" self.window['-STATUS-'].update(f"端口 {port_id} 开始升级...") success = executor.execute_commands(commands) self.window['-STATUS-'].update(f"端口 {port_id} 升级{'成功' if success else '失败'}") def periodic_send(self, message, interval): """周期性发送消息(优化版)""" while not self.executors[1].stop_event.is_set(): for executor in self.executors.values(): if executor.is_connected: executor.send(message) executor.read_until_prompt() time.sleep(interval) def show_help(self): """显示使用说明(多端口版)""" help_text = f""" === 远程单板连接工具使用说明 (多端口) === 1. 多端口连接管理: - 支持同时连接 {MAX_PORTS} 个端口 - 每个端口独立显示连接状态(红:未连接, 绿:已连接) - 每个端口独立保存日志文件 2. 自动操作功能: - 点击"自动"按钮执行特殊引导操作 - 检测"Press 'Ctrl+T' to skip boot"字符串 - 自动发送Ctrl+T组合键 - 5秒后发送"watchdog -close"命令 - 成功执行后自动触发项目升级 - 状态指示器: ○未执行 ●已检测 ✓已完成 3. 项目升级: - 选择项目后,会弹出端口选择对话框 - 可以为每个选择的端口设置独立的日志文件 - 日志文件保存在指定目录,文件名格式:项目名_portX_时间戳.log 4. 日志管理: - 默认日志目录:{self.default_data.get('log_dir', os.getcwd())} - 可以随时修改日志保存目录 - 每个端口连接会记录详细的操作日志 5. 命令执行控制: - 暂停执行:暂停所有端口的命令执行 - 继续执行:继续所有端口的命令执行 - 停止执行:停止所有端口的命令执行 6. 发送机制: - 命令发送到所有已连接的端口 - 每个端口独立处理响应 - 支持定时发送到所有端口 """ sg.popup(help_text, title="使用说明", font=("Arial", 11)) def create_template_file(self): """创建项目配置模板""" try: template = { "projects": [ { "name": "项目A", "commands": [ "ifconfig eth0 192.168.0.100", "ftpget -u user -p pass 192.168.0.1 /home/firmware.bin firmware.bin", "flash -w 0 0x0000000 0xa000000 0x2000000" ], "auto_operation": True, # 新增:自动操作标志 "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") }, { "name": "项目B", "commands": [ "ifconfig eth0 192.168.0.101", "ping 192.168.0.1", "reboot" ], "auto_operation": False, # 新增:自动操作标志 "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } ] } with open("projects_template.json", 'w') as f: json.dump(template, f, indent=4) return True except Exception as e: logger.error(f"创建模板文件失败: {e}") return False # ============== 主程序入口 ============== if __name__ == "__main__": # 启动应用 try: app = RemoteControlApp() app.run() except Exception as e: logger.exception("应用程序崩溃") sg.popup_error(f"应用程序发生致命错误: {str(e)}")
07-08
<think>我们正在分析一个多端口远程控制工具,该工具使用Telnet连接设备,执行一系列命令,并支持自动操作(如检测引导字符串并发送Ctrl+T和watchdog命令)。代码结构包括项目管理、命令执行、GUI界面等部分。 首先,我们注意到代码中存在一些拼错误和变量名错误(例如“极”应该是“0”)。此外,代码中使用了PySimpleGUI库来构建图形用户界面。 我们将逐步分析代码,并指出可能的问题和改进点。 1. 全局配置部分: - 定义了一些常量,如配置文件路径、项目配置文件路径、结束字符串、日志格式等。 - 注意:`MAX_PORTS = 2` 表示支持的最大端口数为2。 2. 日志配置: - 配置了日志记录器,同时输出到文件和控制台。 3. 项目管理类(ProjectManager): - 负责加载、保存、添加、更新、删除项目配置。 - 每个项目包含名称、命令列表、自动操作标志(新增)和创建时间。 - 注意:在`delete_project`方法中,有一个明显的错误:`极 <= index` 应该是 `0 <= index`。 4. 指令执行类(CommandExecutor): - 每个端口对应一个CommandExecutor实例。 - 主要功能包括连接设备、断开连接、发送命令、读取响应、执行命令序列、暂停、继续、停止执行等。 - 新增了自动操作功能:检测引导字符串(BOOT_STRING),然后发送Ctrl+T,再发送watchdog命令,最后触发升级回调。 - 提供了设置日志文件的方法,将操作记录到文件。 5. GUI界面类(RemoteControlApp): - 使用PySimpleGUI构建多窗口界面。 - 支持多端口连接状态显示(指示灯和状态文本)。 - 项目列表显示,每个项目有名称、自动操作状态指示器(○表示禁用,✓表示启用)以及操作按钮(一键升级、自动、编辑、删除)。 - 主界面包括端口连接区域、项目列表、状态信息、执行控制按钮、发送命令区域、日志目录设置等。 - 自动操作状态指示器:○未执行 ●已检测到引导字符串 ✓已完成。 6. 主要功能: - 连接/断开端口。 - 添加、编辑、删除、导入、导出项目。 - 一键升级:选择项目后,可以选择多个端口同时执行该项目的命令序列。 - 自动操作:选择项目后,执行自动操作(检测引导字符串并执行Ctrl+T和watchdog命令),成功后再执行升级命令。 - 暂停、继续、停止执行命令序列。 - 定时发送消息。 - 寄存器dump等。 7. 代码中的问题: - 在`ProjectManager.delete_project`方法中,条件判断成了`极 <= index`,应该是`0 <= index`。 - 在`ProjectManager.export_projects`方法中,参数名成了`file极ath`,应该是`file_path`。 - 在`RemoteControlApp.load_default_data`方法中,更新默认数据时,键名错(例如"极1"应该是"IP1")。 - 在`CommandExecutor.execute_commands`方法中,命令索引从0开始,但在状态更新时,`current_command_index`设置为当前命令的索引(从0开始),而进度显示时使用`current_index+1`,这是合理的。 - 在`RemoteControlApp.setup_gui`方法中,创建项目按钮区域时,调用了`self.create_project_buttons`,但这个方法在初始化时可能还没有项目,因此会显示“没有项目”。 8. 改进建议: - 修复上述拼错误和变量名错误。 -自动操作中,重试机制(最多10次)可能过于频繁,可以考虑增加重试间隔。 -自动操作回调中,执行升级命令时,注意确保设备已经准备好(例如在发送watchdog命令后等待一段时间)。 - 多线程操作时,注意线程安全(例如使用锁)。 由于代码较长,我们只对关键部分进行注释和修正。 下面我们将修正代码中的明显错误: 修正1:ProjectManager.delete_project方法 原代码:`if 极 <= index < len(self.projects["projects"]):` 修正为:`if 0 <= index < len(self.projects["projects"]):` 修正2:ProjectManager.export_projects方法 参数名:`def export_projects(self, file极ath):` -> `def export_projects(self, file_path):` 修正3:RemoteControlApp.load_default_data方法 在更新配置时,键名错误: "IP1": values.get("IP1", self.default_data["极1"]), -> 应该是 self.default_data["IP1"] 类似的,其他键名也要检查。 由于代码量很大,我们无法在此处完整重,但会指出关键修正点。 另外,在`RemoteControlApp`的`load_default_data`方法中,从文件加载配置后更新默认数据时,应该使用正确的键。例如: 原代码: default_data.update({k: data[k] for k in default_data if k in data}) 这是正确的,但是注意在定义default_data时,有一个键错了: 'board_local_ip': "71.19.0.53", # 这个键在后续使用中是否一致? 但是,在定义default_data时,有一个键名是"board_local_ip",而在GUI布局中,对应的输入框key也是"board_local_ip",所以没有问题。 注意:在GUI布局中,端口1的IP输入框key是"IP1",端口2的是"IP2",所以在`load_default_data`中,我们应该确保这些键在default_data中存在。 由于时间关系,我们只分析到这里。下面给出修正后的部分代码片段(仅修正明显错误的地方): 由于整个代码文件很长,我们只修正三个地方: 1. ProjectManager.delete_project 方法: 将条件判断中的“极”改为0。 2. ProjectManager.export_projects 方法: 将参数名“file极ath”改为“file_path”。 3. RemoteControlApp.load_default_data 方法: 在更新配置时,键名错的地方,例如: "IP1": values.get("IP1", self.default_data["IP1"]), # 原来的是“极1” 但是,在`load_default_data`方法中,我们并没有看到直接使用“极1”的地方,而是从文件加载后更新default_data。在default_data的初始化中,我们定义的是“IP1”,所以可能是之前错了。实际上,在代码中,我们注意到: default_data = { "IP1": "71.19.0.120", "port1": "1001", ... # 其他键 } 所以,在更新时,我们使用正确的键名。 然而,在`RemoteControlApp`的`save_config`方法中,我们发现了问题: config = { "IP1": values.get("IP1", self.default_data["极1"]), # 这里应该是"IP1" 这里成了“极1”,应该是`self.default_data["IP1"]`。 因此,在`save_config`方法中,需要修正: "IP1": values.get("IP1", self.default_data["IP1"]), "port1": values.get("port1", self.default_data["port1"]), "IP2": values.get("IP2", self.default_data["IP2"]), "port2": values.get("port2", self.default_data["port2"]), ... # 其他类似 修正后的`save_config`方法片段: ```python def save_config(self): """保存配置""" try: values = self.window.read()[1] if self.window else {} config = { "IP1": values.get("IP1", self.default_data["IP1"]), "port1": values.get("port1", self.default_data["port1"]), "IP2": values.get("IP2", self.default_data["IP2"]), "port2": values.get("port2", self.default_data["port2"]), "FTP_IP": values.get("FTP_IP", self.default_data["FTP_IP"]), "芯片名称": values.get("芯片名称", self.default_data["芯片名称"]), '发送信息': values.get("发送信息", self.default_data["发送信息"]), "board_local_ip": values.get("board_local_ip", self.default_data["board_local_ip"]), 'interval': values.get("interval", self.default_data["interval"]), "start_addr": values.get("start_addr", self.default_data["start_addr"]), "end_addr": values.get("end_addr", self.default_data["end_addr"]), "文件FTP路径": values.get("文件FTP路径", self.default_data["文件FTP路径"]), "log_dir": values.get("log_dir", self.default_data["log_dir"]) } ... # 其余不变 ``` 由于无法提供完整的修正代码,我们建议根据上述分析逐一修正。 最后,运行主程序入口。 注意:由于代码依赖PySimpleGUI和telnetlib,确保已安装PySimpleGUI。 安装:pip install pysimplegui 由于代码较长且复杂,建议在测试环境中逐步调试。 相关问题: 1. 如何扩展支持更多端口? 2. 自动操作中的重试机制如何优化? 3. 在多线程执行命令时,如何避免资源竞争? 4. 如何增强日志记录,以便于问题追踪? 根据要求,我们提出以下相关问题: §§相关问题§§: 1. 如何修改代码以支持超过2个端口? 2. 在自动操作功能中,如果设备没有出现预期的引导字符串,程序会如何处理? 3. 在多线程环境下,如何确保日志记录(log_queue)的线程安全? 4. 如何增加一个功能:在自动操作失败时发送警报(例如邮件或消息通知)?</think>### 代码解析 这是一个使用Python实现的远程设备控制工具,支持多端口连接、命令执行、项目管理等功能。主要功能包括: 1. 通过Telnet连接多个设备 2. 执行预定义命令序列(项目) 3. 自动检测引导字符串并执行特殊操作 4. 项目管理(添加/编辑/删除/导入/导出) 5. 详细的日志记录 #### 主要组件分析 1. **项目管理类 (ProjectManager)** ```python class ProjectManager: def __init__(self): self.projects = self.load_projects() def load_projects(self): # 加载项目配置 def save_projects(self): # 保存项目配置 def add_project(self, name, commands, auto_operation=False): # 添加新项目 def update_project(self, index, name, commands, auto_operation=False): # 更新项目 def delete_project(self, index): # 删除项目 def import_projects(self, file_path): # 导入项目配置 def export_projects(self, file_path): # 导出项目配置 ``` - 管理项目配置(JSON格式) - 支持项目的新增、编辑、删除、导入导出 - 每个项目包含名称、命令列表和自动操作标志 2. **指令执行类 (CommandExecutor)** ```python class CommandExecutor: def __init__(self, port_id): # 初始化执行器 def connect(self, host, port): # 连接设备 def disconnect(self): # 断开连接 def send(self, content): # 发送命令(分块发送) def read_until_prompt(self, timeout=5): # 读取响应直到遇到提示符 def execute_commands(self, commands): # 执行命令序列 def detect_boot_string_and_auto_operation(self): # 检测引导字符串并执行自动操作 def perform_auto_operation(self, callback=None): # 执行自动操作(带重试) ``` - 每个端口对应一个执行器实例 - 支持分块发送命令(避免命令粘包) - 自动检测引导字符串并执行特殊操作(Ctrl+T + watchdog) - 提供暂停/继续/停止执行的控制功能 3. **GUI界面类 (RemoteControlApp)** ```python class RemoteControlApp: def __init__(self): # 初始化应用 def setup_gui(self): # 设置GUI界面 def run(self): # 运行主循环 ``` - 使用PySimpleGUI构建用户界面 - 多端口状态显示(连接状态、自动操作状态) - 项目管理界面 - 实时日志输出 - 执行控制按钮(暂停/继续/停止) #### 核心功能实现 1. **自动操作功能** ```python def detect_boot_string_and_auto_operation(self): # 检测引导字符串 if re.search(BOOT_STRING, response, re.IGNORECASE): # 发送Ctrl+T self.send_ctrl_t() # 发送watchdog命令 self.send("watchdog -close") # 检查响应并触发回调 ``` 2. **命令执行流程** ```python def execute_commands(self, commands): for idx, cmd in enumerate(commands): # 发送命令 self.send(cmd) # 等待响应 self.read_until_prompt() # 命令间延迟 time.sleep(COMMAND_DELAY) ``` 3. **多端口支持** ```python # 初始化端口执行器 for port_id in range(1, MAX_PORTS + 1): self.executors[port_id] = CommandExecutor(port_id) ``` 4. **状态指示器** - 连接状态:●红色(未连接)●绿色(已连接) - 自动操作状态: - ○灰色:未执行 - ●红色:检测到引导字符串 - ✓绿色:自动操作完成 #### 使用说明 1. 配置端口IP和端口号 2. 创建项目(包含命令序列) 3. 选择端口执行项目 4. 可启用"自动操作"功能处理特殊引导场景 5. 所有操作日志会保存到指定目录 #### 需要修复的问题 1. **变量名错误**: ```python # 原代码 if 极 <= index < len(self.projects["projects"]): # 应改为 if 0 <= index < len(self.projects["projects"]): ``` 2. **方法参数错误**: ```python # 原代码 def export_projects(self, file极ath): # 应改为 def export_projects(self, file_path): ``` 3. **键名错误**: ```python # 原代码 "IP1": values.get("IP1", self.default_data["极1"]), # 应改为 "IP1": values.get("IP1", self.default_data["IP1"]), ``` ### 总结 这是一个功能完善的远程设备控制工具,主要特点包括: 1. 多端口并行控制 2. 项目管理功能 3. 自动操作处理特殊引导场景 4. 详细的日志记录 5. 用户友好的GUI界面 修复上述拼错误后,代码可以正常运行。核心价值在于自动化处理设备连接和命令执行流程,特别适合需要批量操作多台设备的场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网时光机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值