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

Python ptyprocess读取缺失末尾两行数据问题求助

ptyprocess读取bluetoothctl响应丢失内容及异常字符问题

问题现象

真实终端中执行bluetoothctl操作能得到包含18个值和末尾“OK”的完整响应,但通过ptyprocess的read方法只能获取13个值,丢失末尾的“OK”行,同时还会返回一个ESC字符。

相关代码

@staticmethod
def communicate(write_uuid, read_uuid, data):
    
    # Requires a writable and a readable GATT uuid and data to be written
    # The method returns the data retrieved from the readable GATT uuid
    
    hex_string = ''
    for char in data:
        hex_string += hex(ord(char)) + ' '

    timeout = .1
    read_process = ptyprocess.PtyProcessUnicode.spawn(['/bin/bash'])
    commands = ['bluetoothctl', 'menu gatt', f'select-attribute {read_uuid}', 'notify on']
    for command in commands:
        read_process.write(command + '\n')
        time.sleep(timeout)
        read_process.read(1)

    write_process = ptyprocess.PtyProcessUnicode.spawn(['/bin/bash'])
    commands = f'bluetoothctl <<EOF\nmenu gatt\nselect-attribute {write_uuid}\nwrite "{hex_string}"\nEOF\n'
    write_process.write(commands)
    time.sleep(timeout)
    write_process.read(1)
    time.sleep(timeout)

    hex_values = []
    pattern = re.compile(r'\b[0-9a-fA-F]{2}\b')
    lines = read_process.read(size=10000).splitlines()
    for line in lines:
        print(line)

实际读取到的响应

[CHG] Attribute /org/bluez/hci0/dev_CE_EE_A8_9B_17_AC/service000b/char000e Value:
[Device:/service000b/char000e]#                                              
  30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30  0.0, 0.0, 0.0, 0
[Device:/service000b/char000e]#                                              
  2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e  .0, 0.0, 0.0, 0.
[Device:/service000b/char000e]#                                              
  30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30  0, 0.0, 0.0, 0.0
[Device:/service000b/char000e]#                                              
  2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c  , 0.0, 0.0, 0.0,
[Device:/service000b/char000e][

预期完整响应

[Device:/service000b/char000e]# [CHG] Attribute /org/bluez/hci0/dev_CE_EE_A8_9B_17_AC/service000b/char000e Value:
[Device:/service000b/char000e]#   30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30  0.0, 0.0, 0.0, 0
[Device:/service000b/char000e]#   2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e  .0, 0.0, 0.0, 0.
[Device:/service000b/char000e]#   30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30  0, 0.0, 0.0, 0.0
[Device:/service000b/char000e]#   2c 20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c  , 0.0, 0.0, 0.0,
[Device:/service000b/char000e]#   20 30 2e 30 2c 20 30 2e 30 2c 20 30 2e 30 2c 20   0.0, 0.0, 0.0, 
[Device:/service000b/char000e]#   30 2e 30 2c 20 30 2e 30 20 4f 4b 0a              0.0, 0.0 OK.   

解决方案

1. 调整等待逻辑与读取方式

问题核心是等待时间不足,导致bluetoothctl未输出完所有内容就开始读取;同时单次固定大小的read可能提前终止。修改方案如下:

@staticmethod
def communicate(write_uuid, read_uuid, data):
    hex_string = ' '.join(hex(ord(char)) for char in data)

    # 合并为单个进程处理,减少时序干扰
    process = ptyprocess.PtyProcessUnicode.spawn(['bluetoothctl'])
    time.sleep(0.2)
    
    # 执行GATT相关命令
    commands = [
        'menu gatt',
        f'select-attribute {read_uuid}',
        'notify on',
        f'select-attribute {write_uuid}',
        f'write "{hex_string}"'
    ]
    
    for cmd in commands:
        process.write(cmd + '\n')
        time.sleep(0.2)
        # 清空当前命令的输出缓冲区,避免残留数据干扰后续读取
        while process.readable():
            try:
                process.read_nonblocking(size=1024, timeout=0.1)
            except ptyprocess.PtyProcessTimeout:
                break
    
    # 循环读取直到捕获到"OK"标记,确保获取完整响应
    full_output = ""
    while True:
        try:
            chunk = process.read_nonblocking(size=1024, timeout=0.5)
            full_output += chunk
            if "OK" in full_output:
                break
        except ptyprocess.PtyProcessTimeout:
            break
    
    # 过滤ESC字符(ASCII码27)并输出
    cleaned_output = full_output.replace('\x1b', '')
    lines = cleaned_output.splitlines()
    for line in lines:
        print(line)
    
    process.close()

2. 关键优化点

  • 合并进程:避免多进程同步问题,用单个进程处理所有bluetoothctl操作
  • 延长等待时间:根据蓝牙设备响应速度调整sleep时长,确保命令执行完成
  • 非阻塞读取:配合超时机制循环读取,确保捕获所有输出直到目标标记出现
  • 清理异常字符:直接替换ESC字符(\x1b),净化输出内容

内容的提问来源于stack exchange,提问作者sonus89

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:07:11