You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:05:01