从“悬挂”中检测并恢复。蓝牙python连接 [英] Detecting and recovering from "hanging" bluetooth python connection

查看:106
本文介绍了从“悬挂”中检测并恢复。蓝牙python连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用RPi内置模块和Arduino上的HC-05模块在Raspberry Pi 3b +和Arduino Mega之间建立了蓝牙连接。双向通信就像一次魅力一样工作,一次几分钟,有时甚至几个小时。

I have a bluetooth connection between a Raspberry Pi 3b+ and an Arduino Mega, using the RPi built-in module, and an HC-05 module on the Arduino. Bi-directional communication works like a charm, for minutes to sometimes, hours at a time.

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

Then, at seemingly random times, the python code hangs, blocked on the sock.recv() function. I can kill it via ctrl-c, and restart it, and it usually reconnects without a problem.

我知道蓝牙有点挑剔,因此尽管有人建议如何为了使通信更加健壮并扩展运行时-直到挂起,我当然更感兴趣,我更感兴趣的是如何检测到这种挂起并从中恢复。即:我只是想终止连接并尝试从Python程序中重新连接,而不是我自己看看这个并对此做出反应。

I know Bluetooth is a little finicky and so while any suggestions of how to make the communication more robust and extend the runtime-until-hanging are definitely appreciated, what I'm more interested in is how to detect this "hanging" and recover from it. i.e.: I want to just kill the connection and try to reconnect from within the Python program, rather than me having to see this myself and react to it.

这就是我到目前为止在python中已经使用了

This is what I have so far in 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('%s\n' % 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日志文件如下所示:

When working well, the python log file looks like this:

.. 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

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

Then, noticing it had stopped working, I killed it, and then restarted it:

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进程中进行了重新连接而没有问题。

... and it runs for another hour or two, before hanging again. I'm not physically moving either sender or receiver - they're within a foot of each other - so it's not range. Though I have tried disconnecting the Arduino, and repowering it, and they do reconnect without a problem within the still-running Python process.

Arduino代码,尽管我没有t认为与之相关:

The Arduino code, though I don't think its as relevant, is here:

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或什至只是串行。

I could not get the socket connection to last more than a few hours despite a few days of different approaches & efforts; I only went down the socket rabbit hole because I was unable to figure out how to use pySerialTransfer, or even just serial, over bluetooth.

所以,回到串行经过更多的努力和研究,我最终得以使该方法在Raspberry Pi& amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp;#39 HC-05 on Arduino。

So, going back to the serial approach, after a bit more effort and investigation, I was ultimately able to get that approach working for a stable (over 1 day at this point) bluetooth connection between Raspberry Pi & HC-05 on Arduino.

代码为这里

这篇关于从“悬挂”中检测并恢复。蓝牙python连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆