PySerial网络传感器串口配置:确认交互异常问题排查
串口脚本处理设备确认提示的异常问题
问题描述
我正在整理通过控制台端口配置网络传感器的常见步骤,大部分操作正常,但执行需要用户确认的命令时,脚本写入逻辑不符合预期。
正常PuTTY操作示例
# 登录流程已省略 hostname# show uptime uptime "51 days, 20 hours, 36 mins and 2 seconds" hostname# config terminal Entering configuration mode terminal hostname(config)# system contact "John Doe" hostname(config)# copy running-config startup-config Are you sure? [no,yes] yes OK. Saved running-config to startup-config. hostname(config)# exit hostname#
脚本执行异常情况
hostname(config)# copy running-config startup-config Are you sure? Aborted: by user hostname(config)# yes -----------------------^ syntax error: unknown command
看起来像是发送yes前触发了中止命令(如\r或ctrl+c),请问串口设备的这类确认提示是否需要特殊处理?以下是我的Python代码:
import serial import time def read_until_prompt(prompt, timeout=10, user_input=None): buffer = "" end_time = time.time() + timeout while time.time() < end_time: if ser.in_waiting: buffer += ser.read(ser.in_waiting).decode("utf-8") if prompt in buffer: if user_input is not None: command = user_input.encode("utf-8") + b"\r\n" ser.write(command) print("\n--Current buffer--\n" + buffer) return buffer time.sleep(0.1) raise TimeoutError(f"Did not find prompt: {prompt}") ser = serial.Serial( port=com_interface, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1, xonxoff=False, # No flow control rtscts=False, # No flow control dsrdtr=False, # No flow control ) try: STANDARD_PROMT = "#" CONFIG_PROMT = "(config)#" # Initial connection sequence time.sleep(2) # Initial delay, to allow for initialization ser.write(b"\x03") # reset any activity read_until_prompt("login:") ser.write(b"john\r\n") # Username read_until_prompt("Password:") ser.write(f"{password}\r\n".encode("utf-8")) # Workes just fine read_until_prompt(STANDARD_PROMT, user_input="show uptime") read_until_prompt(STANDARD_PROMT, user_input="config terminal") read_until_prompt(CONFIG_PROMT, user_input=f'system contact "John Doe"') # Save config to startup read_until_prompt(CONFIG_PROMT, user_input=f'copy running-config startup-config') # a confirmation promped is shown 'Are you sure? [yes/no]', buffer shows 'Are you sure?' read_until_prompt("Are you sure?", user_input='yes') # Additional attempt ser.write(b'copy running-config startup-config\r\n') time.sleep(0.2) ser.write(b'yes\r\n') time.sleep(15) read_until_prompt(CONFIG_PROMT, user_input="exit") finally: ser.close()
问题原因与解决方法
1. 确认提示匹配不完整
设备实际输出的确认提示是Are you sure? [no,yes],但脚本仅匹配Are you sure?,导致提前触发输入逻辑。此时设备还在等待完整交互,脚本发送yes后,设备因超时或未正确识别输入自动中止操作,后续的yes变成独立命令,引发语法错误。
2. 命令发送逻辑不匹配确认场景
原read_until_prompt函数是基于提示符(如#)设计的,但确认提示并非标准命令提示符,不需要等待提示符出现再输入,而是在提示出现后直接发送确认指令。
修正后的代码示例
import serial import time def read_until_prompt(prompt, timeout=10): buffer = "" end_time = time.time() + timeout while time.time() < end_time: if ser.in_waiting: buffer += ser.read(ser.in_waiting).decode("utf-8") if prompt in buffer: print("\n--Current buffer--\n" + buffer) return buffer time.sleep(0.1) raise TimeoutError(f"Did not find prompt: {prompt}") def send_command(cmd, wait_for_prompt=None): ser.write(f"{cmd}\r\n".encode("utf-8")) if wait_for_prompt: return read_until_prompt(wait_for_prompt) ser = serial.Serial( port=com_interface, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False, ) try: STANDARD_PROMPT = "#" CONFIG_PROMPT = "(config)#" time.sleep(2) ser.write(b"\x03") read_until_prompt("login:") send_command("john") read_until_prompt("Password:") send_command(password) send_command("show uptime", wait_for_prompt=STANDARD_PROMPT) send_command("config terminal", wait_for_prompt=CONFIG_PROMPT) send_command('system contact "John Doe"', wait_for_prompt=CONFIG_PROMPT) # 单独处理配置保存的确认流程 send_command("copy running-config startup-config") # 等待完整的确认提示出现 read_until_prompt("Are you sure? [no,yes]") # 直接发送确认指令 ser.write(b"yes\r\n") # 等待保存完成并回到配置提示符 read_until_prompt(CONFIG_PROMPT) send_command("exit", wait_for_prompt=STANDARD_PROMPT) finally: ser.close()
额外注意事项
- 不同设备的确认提示格式可能不同(如
[Y/N]),需根据设备实际输出调整匹配字符串; - 尽量避免固定时长的
time.sleep(),通过读取输出内容判断设备状态,提升脚本稳定性; - 调试时可打印完整缓冲区内容,确认设备实际输出与预期是否一致。
内容的提问来源于stack exchange,提问作者Petter Östergren
相关产品推荐
相关产品推荐

