I used to connect a generic Bluetooth dongle (ORICO-BTA-508) for connection to a device under development. The device under development is a SPP profile device, so it just provides a simple serial interface. The bluepy script in use (developed with help of http://ianharvey.github.io/bluepy-doc/index.html) is straight and simple:
`
!/usr/bin/env python3
"""
\file io.py
Communication helper
opens bluetooth connection to already bonded FL500C
prior connection can succeed a blescan has to be performed (needs sudo)
prints "DATA" when ready for communication
reads from STDIN in Format x01x03xFF..
waits for response
prints out response in format 01 03 FF
on timeout prints out nothing
(This behaviour is made as similar to spp_client as possible to reduce adaption works)
"""
import bluepy.btle as btle
import fileinput
import re
import sys
import time
from binascii import hexlify
DEFAULT_BLE_CHUNK = 247
BLE_NOTIFICATION_TIMEOUT = 1.0
class BLEDongleDelegate(btle.DefaultDelegate):
def __init__(self, dongle):
btle.DefaultDelegate.__init__(self)
self.dongle = dongle
self.dongle.result = bytearray( [] )
self.dongle.timeout = BLE_NOTIFICATION_TIMEOUT
print("init dongle: %f" % self.dongle.timeout)
def handleNotification(self, cHandle, data):
#print "notification got"
#self.dongle.result += bytearray(data)
for x in bytearray(data):
print("0x%02x" % x, end = " ")
if len(data) == 244: # this means the MTU (including 3 Bytes Overhead) is complete and
self.dongle.device.waitForNotifications(self.dongle.timeout) # there might be more data
else:
print("") # end with line break
try:
print("starting Stdin-Thread")
print("DATA")
for fileinput_line in fileinput.input():
if 'quit' == fileinput_line.rstrip():
break
if 'timeout' == fileinput_line[:7]:
cols=re.split("=", fileinput_line)
dongle.timeout = float(cols[1])
continue
byte_array = fileinput_line.rstrip()
cols=re.split("x", byte_array)
if len(cols) > 1:
cols=cols[1:]
myBytes = bytearray()
for n in cols:
myBytes += bytearray.fromhex(n)
dongle.exchange( myBytes )
except KeyboardInterrupt:
User interrupt the program with ctrl+c
print("Done")
sys.exit()
finally:
dongle.close()
`
I run that script on Raspberry Pi 3 after I have verified the device is advertising using blescan.
But since i have upgraded to Python 3.7 (and after I've adapted that scripts syntax), the connection comes up in 1 of 5 tries, only.
Before the upgrade bluepy was run with Python 2.7 and it failed only rarely to establish a connection, which was workarounded by at most 1 retry.
I found no reason yet (comparing logs of btmon, comparing a working with a failing attempt), except that it seems to struggle for timeouts and disconnects before the connection is secured.
Expected (and rarely seen outputs) of SPP_Client.py :
./SPP_Client 11:11:11:11:11:11
connecting 11:11:11:11:11:11
Characteristic: "Device Name" = b'FL5C-10000006\x00\x01\x00\x02\x01\x06', len:19
Characteristic: "Firmware Revision String" = b'1.0.1\x00\x00\x00\x00\x00\x00\x00\x00\x00', len:14
Characteristic: "Manufacturer Name String" = b'SICK ', len:12
init dongle: 1.000000
init Fl500C :1.000000
starting Stdin-Thread
DATA
x01x03x0CxB7x00x01x37x7C (user input, some telegram to send to the device)
0x01 0x03 0x02 0x03 0x41 0x78 0x84 (returned response from that device)
Usual error outputs of SPP_Client.py :
./SPP_Client 11:11:11:11:11:11
connecting 11:11:11:11:11:11
Traceback (most recent call last):
File "./SPP_Client", line 105, in
dongle = myFL500C(MAC)
File "./SPP_Client", line 60, in init
self.getChar(DeviceName)
File "./SPP_Client", line 53, in getChar
value = self.device.getCharacteristics(uuid=concreteuuid)[0].read()
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 508, in getCharacteristics
rsp = self._getResp('find')
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 407, in _getResp
resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 362, in _waitResp
raise BTLEDisconnectError("Device disconnected", resp)
bluepy.btle.BTLEDisconnectError: Device disconnected
Sometimes it generates a bit more of output:
./SPP_Client 11:11:11:11:11:11
connecting 11:11:11:11:11:11
Traceback (most recent call last):
File "./SPP_Client", line 105, in
dongle = myFL500C(MAC)
File "./SPP_Client", line 60, in init
self.getChar(DeviceName)
File "./SPP_Client", line 53, in getChar
value = self.device.getCharacteristics(uuid=concreteuuid)[0].read()
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 508, in getCharacteristics
rsp = self._getResp('find')
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 407, in _getResp
resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 361, in _waitResp
self._stopHelper()
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 293, in _stopHelper
self._helper.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe
Exception ignored in: <function Peripheral.del at 0x76620780>
Traceback (most recent call last):
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 630, in del
self.disconnect()
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 453, in disconnect
self._writeCmd("disc\n")
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 305, in _writeCmd
self._helper.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe
Version infos:
pip list
bluepy 1.3.0
pip 20.3.4
RPi.GPIO 0.7.0
Bonding was accomplished using the interactive bluetoothctl. Some other information you might be interested in:
Hi there,
I used to connect a generic Bluetooth dongle (ORICO-BTA-508) for connection to a device under development. The device under development is a SPP profile device, so it just provides a simple serial interface. The bluepy script in use (developed with help of http://ianharvey.github.io/bluepy-doc/index.html) is straight and simple:
`
!/usr/bin/env python3
""" \file io.py Communication helper
SPP_SERVICE = "4880c12cfdcb40778920a450d7f9b907" SPP_DATA = "fec26ec46d7144429f8155bc21d658d6" DeviceName = btle.UUID(0x2A00) FirmwareRev = btle.UUID(0x2A26) Manufacturer = btle.UUID(0x2A29)
DEFAULT_BLE_CHUNK = 247 BLE_NOTIFICATION_TIMEOUT = 1.0 class BLEDongleDelegate(btle.DefaultDelegate):
class myFL500C:
if len(sys.argv) != 2: print("syntax: %s" % sys.argv[0])
sys.exit()
else:
MAC = sys.argv[1]
print("connecting %s" % MAC)
sys.argv = [sys.argv[0]]
dongle = myFL500C(MAC)
try: print("starting Stdin-Thread") print("DATA") for fileinput_line in fileinput.input(): if 'quit' == fileinput_line.rstrip(): break if 'timeout' == fileinput_line[:7]: cols=re.split("=", fileinput_line) dongle.timeout = float(cols[1]) continue byte_array = fileinput_line.rstrip() cols=re.split("x", byte_array) if len(cols) > 1: cols=cols[1:] myBytes = bytearray() for n in cols: myBytes += bytearray.fromhex(n)
except KeyboardInterrupt:
User interrupt the program with ctrl+c
finally: dongle.close() ` I run that script on Raspberry Pi 3 after I have verified the device is advertising using blescan.
But since i have upgraded to Python 3.7 (and after I've adapted that scripts syntax), the connection comes up in 1 of 5 tries, only. Before the upgrade bluepy was run with Python 2.7 and it failed only rarely to establish a connection, which was workarounded by at most 1 retry.
I found no reason yet (comparing logs of btmon, comparing a working with a failing attempt), except that it seems to struggle for timeouts and disconnects before the connection is secured.
Expected (and rarely seen outputs) of SPP_Client.py :
Usual error outputs of SPP_Client.py :
Sometimes it generates a bit more of output:
Version infos:
Bonding was accomplished using the interactive bluetoothctl. Some other information you might be interested in:
The device under development is stable meanwhile, connections using a mobile phone or an android tablet do work very well.
Any help or hint with this would be appreciated.