我目前正在开发一个Python程序,通过使用btmon来监控蓝牙设备。但是,我遇到了一个问题,蓝牙设备上的按键(在 btmon 中即时注册)和 Python 程序中的输出之间似乎存在延迟。
本质上,我正在尝试从我的 BT 设备读取原始数据,并在按向左或向右时触发事件。这是我的电子阅读器的 BT 戒指;)
我有 2 个终端,用我的程序打开其中一个,该程序在其故障排除表单中仅用于打印来自 BTmon 的数据。 BTmon 显示按键的即时反馈,而我的程序仅在我按下至少两次后才显示按键。
当最终打印时,它会立即显示所有按键以及最新按键的时间戳。
例如,我在 1300 按一次,它永远不会在我的程序中打印
我在 1305 处再次按下,它将显示为两次按键。
如果我彼此按一秒钟,我将需要第三次按键。
这种行为表明某种缓冲区 - 或者有什么我完全错过的?
我尝试过的:
案例 1:使用 subprocess.Popen 运行 btmon 并逐行打印其输出。
案例2:与案例1类似,但使用函数连续打印btmon输出。
案例 3:尝试使用 iter 尽快处理 btmon 输出中的行。
案例 4:使用 subprocess.Popen 与 PIPE 和 universal_newlines=True 逐行打印输出。
案例 5:利用带有 subprocess.Popen 的循环来连续打印 btmon 输出,直到完成。
所有结果都完全相同。
请求协助:
我正在寻求帮助以了解为什么蓝牙设备按键和 Python 程序中的输出之间存在延迟。我的方法中是否缺少某些内容,或者是否有更好的方法在 Python 中从 btmon 捕获实时数据?
Case 1:
import subprocess
def run_btmon():
btmon_process = subprocess.Popen(["sudo", "btmon"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)
for line in btmon_process.stdout:
print(line.strip())
def main():
run_btmon()
if __name__ == "__main__":
main()
Case 2:
import subprocess
def capture_bluetooth_data():
btmon_process = subprocess.Popen(["sudo", "btmon"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
for line in btmon_process.stdout:
print(line.strip())
def main():
capture_bluetooth_data()
if __name__ == "__main__":
main()
Case 3:
import subprocess
def capture_bluetooth_data():
btmon_process = subprocess.Popen(["sudo", "btmon"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
for line in iter(btmon_process.stdout.readline, ""):
print(line.strip())
def main():
capture_bluetooth_data()
if __name__ == "__main__":
main()
Case 4:
from subprocess import Popen, PIPE, CalledProcessError
def capture_bluetooth_data():
with Popen(["sudo", "btmon"], stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line.strip())
if p.returncode != 0:
raise CalledProcessError(p.returncode, p.args)
def main():
capture_bluetooth_data()
if __name__ == "__main__":
main()
Case 5:
import subprocess
import sys
def capture_bluetooth_data():
process = subprocess.Popen(["sudo", "btmon"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
while True:
nextline = process.stdout.readline()
if nextline == '' and process.poll() is not None:
break
print(nextline.strip())
sys.stdout.flush()
output, _ = process.communicate()
exit_code = process.returncode
if exit_code != 0:
raise subprocess.CalledProcessError(exit_code, ["sudo", "btmon"])
def main():
capture_bluetooth_data()
if __name__ == "__main__":
main()
您在蓝牙设备上的按键与 Python 程序中的输出之间遇到的延迟问题可能源于 btmon 与您的程序之间的通信缓冲。 作为解决方案,您可以将非阻塞 I/O 与
select
一起使用:
使用select模块实现非阻塞I/O。这允许您的程序检查来自 btmon 的可用数据,而无需等待缓冲区已满。
您还可以使用 sys.stdout.buffer.write(data)
而不是 print(data)
以更细粒度的方式将数据写入标准输出,从而可能减少缓冲延迟。