检测并从"挂起"蓝牙 python 连接中恢复



我使用RPi内置模块和Arduino上的HC-05模块在Raspberry Pi 3b+和Arduino-Mega之间建立了蓝牙连接。双向交流就像一种魅力,有时几分钟,有时几小时。

然后,在看似随机的时间,python代码挂起,在sock.recv()函数上被阻塞。我可以通过ctrl-c杀死它,然后重新启动它,它通常会毫无问题地重新连接。

我知道蓝牙有点挑剔,所以虽然任何关于如何使通信更健壮并延长运行时间直到挂起的建议都会受到赞赏,但我更感兴趣的是如何检测这种"挂起"并从中恢复。即:我只想终止连接,并尝试从Python程序中重新连接,而不是我自己看到并对此做出反应。

这就是我目前在python中所拥有的:

#!/usr/bin/python3
import datetime
import socket
import sys
import time
import bluetooth
COMMAND_START_CHAR = '<'
COMMAND_END_CHAR = '>'
LOGFILE = 'bt.log'

def SearchForFullCommand(buffer):
"""Puts fully formed commands from buffer into a list, returning the remaining buffer.
We expect commands to be demarcated by COMMAND_START_CHAR and COMMAND_END_CHAR.  The
buffer may have zero or more such commands. This function finds all demarcated commands,
strips off those demarcations, and returns the remaining buffer.  Any text that arrives
before a COMMAND_START_CHAR is discarded.
Args:
buffer: string representing the text received so far.
Returns:
A 2-tuple, where the first element is the remaining buffer, and the second element
is a potentially empty list of identified commands.
"""
commands = []
while COMMAND_END_CHAR in buffer:
end_pos = buffer.find(COMMAND_END_CHAR)
if COMMAND_START_CHAR in buffer[:end_pos]:
start_pos = buffer.find(COMMAND_START_CHAR) + len(COMMAND_START_CHAR)
commands.append(buffer[start_pos:end_pos])
buffer = buffer[end_pos+len(COMMAND_END_CHAR):]
return (buffer, commands)  # no command found

def Log(s):
"""Appends message s to the logfile."""
with open(LOGFILE, 'a') as f:
f.write('%sn' % s)

def ConnectBluetooth(address, port):
"""Attempts to make one connection to the given address and port."""
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sock.connect((address, port))
except (bluetooth.btcommon.BluetoothError) as e:
Log('Failed to connect: %s' % e)
return None
return sock

def ConnectBluetoothRetry(address, port, seconds):
"""Attempts to make connections for a number of seconds, exiting program on fail."""
second = 0
while second < seconds:
sock = ConnectBluetooth(address, port)
if sock:
Log('Connected after %d seconds' % second)
return sock
time.sleep(1)
second += 1
Log('Failed to connect after %d seconds' % second)
sys.exit()

def main():
"""Sends sequential numbers over bluetooth, and receives & parses anything sent."""
sys.stderr = open(LOGFILE, 'a')
start = time.time()
timestring = datetime.datetime.fromtimestamp(start).strftime('%Y-%m-%d %H:%M:%S')
Log('Started at %s' % timestring)
bd_addr = '98:D3:11:FC:42:16'
port = 1
sock = ConnectBluetoothRetry(bd_addr, port, 10)
buffer = ''
x = 0
while True:
try:
recv = sock.recv(1024)
except (bluetooth.btcommon.BluetoothError) as e:
Log('Failed to receive: %s' % e)
sock.close()
sock = ConnectBluetoothRetry(bd_addr, port, 10)
Log('.. %s (len=%d) after running for %.3f hours' % (
recv, len(recv), (time.time() - start) / 60**2))
buffer += recv.decode()
buffer, commands = SearchForFullCommand(buffer)
if commands:
for n, command in enumerate(commands):
Log('Received full command #%d: %s' % (n, command))
send = COMMAND_START_CHAR+str(x)+COMMAND_END_CHAR
try:
sock.send(send)
except (bluetooth.btcommon.BluetoothError) as e:
Log('Failed to send %s: %s' % (send, e))
sock.close()
sock = ConnectBluetoothRetry(bd_addr, port, 10)
Log('Sent %s' % send)
x += 1
time.sleep(1)

main()

工作正常时,python日志文件如下所示:

.. b'646>' (len=4) after running for 0.843 hours
Received full command #0: 646
Sent <2526>
.. b'<647>' (len=5) after running for 0.843 hours
Received full command #0: 647
Sent <2527>
.. b'<' (len=1) after running for 0.844 hours
Sent <2528>
.. b'648>' (len=4) after running for 0.844 hours

然后,注意到它已经停止工作,我杀死了它,然后重新启动它:

KeyboardInterrupt
Started at 2020-05-03 11:15:07
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect: [Errno 16] Device or resource busy
Failed to connect after 10 seconds

我再试一次:

Started at 2020-05-03 11:15:42
Failed to connect: [Errno 112] Host is down
Failed to connect: [Errno 112] Host is down
Failed to connect: [Errno 112] Host is down
Connected after 3 seconds
.. b'1146><1147><1148><1149><1150><1151><1152><1153><1154><1155><1156><1157><1158><1159><1160><1161><1162><1163><1164><1165><1166><1' (len=127) after running for 0.005 hours
Received full command #0: 1147
Received full command #1: 1148
Received full command #2: 1149

它又运行了一两个小时,然后再次挂起。我没有移动发送器或接收器——它们相距不到一英尺——所以这不是范围。尽管我已经尝试断开Arduino的连接,并重新为其供电,但在仍在运行的Python进程中,它们确实重新连接了,没有出现任何问题。

Arduino代码,尽管我认为它不相关,但在这里:

long n = 1;
void setup() 
{
Serial.begin(9600);
// HC-05 default serial speed for communcation mode is 9600
Serial1.begin(9600);  
}
void loop() 
{
Serial1.print("<");
Serial1.print(n);
Serial1.print(">");
if(Serial1.available() > 0){ // Checks whether data is comming from the serial port
Serial.println(Serial1.readString());} // Reads the data from the serial port
delay(1000);
n++;
}

感谢您的帮助或建议!

尽管有几天的不同方法,我还是无法让套接字连接持续几个小时以上;努力;我之所以陷入插座兔子洞,是因为我不知道如何通过蓝牙使用pySerialTransfer,甚至只是串行传输。

因此,回到串行方法,经过更多的努力和调查,我最终能够在Raspberry Pi&Arduino上的HC-05。

代码在这里。

最新更新