无法通过 BLE Python 连接到 Arduino:[org.bluez.Error.Failed] 软件导致连接中止

Posted

技术标签:

【中文标题】无法通过 BLE Python 连接到 Arduino:[org.bluez.Error.Failed] 软件导致连接中止【英文标题】:Cannot connect to Arduino over BLE Python: [org.bluez.Error.Failed] Software caused connection abort 【发布时间】:2021-11-16 07:58:38 【问题描述】:

我正在尝试通过 BLE 将数据从我的 Arduino 发送到我的 Raspberry Pi。但是,当我运行以下脚本时,有时会出现以下两个错误之一:

[org.bluez.Error.Failed] Software caused connection abortThis service is already present in this BleakGATTServiceCollection!

当我退出程序时,最后一行出现以下错误:bleak.exc.BleakError: Characteristic 00001143-0000-1000-8000-00805f9b34fb not found!bleak.exc.BleakError: Not connected

我已尝试重启 Raspberry Pi 和 Arduino 以及使用 sudo systemctl restart bluetoothsudo systemctl daemon-reload 重启蓝牙服务,但无济于事。

奇怪的是,如果我在以类似方式设置的不同 Pi 上运行脚本,脚本会按预期运行。

什么可能导致这个问题?

这是脚本(删除了一些不相关的部分):

# Adapted from: https://github.com/Ladvien/arduino_ble_sense

import os
import sys
import asyncio
import pyrebase
import platform
import bluetooth
from datetime import datetime
from typing import Callable, Any, List
from time import sleep

from aioconsole import ainput
from bleak import BleakClient, discover

class Connection:

    client: BleakClient = None

    def __init__(
        self,
        loop: asyncio.AbstractEventLoop,
        read_characteristic: str,
        write_characteristic: str,
        data_dump_handler: Callable[[str, str], None]
    ):
        self.loop = loop
        self.read_characteristic = read_characteristic
        self.write_characteristic = write_characteristic
        self.data_dump_handler = data_dump_handler

        self.connected = False
        self.connected_device = None

    def on_disconnect(self, client: BleakClient):
        self.connected = False
        # Put code here to handle what happens on disconnect.
        print(f"Disconnected from self.connected_device.name!")

    async def cleanup(self):
        if self.client:
            await self.client.stop_notify(read_characteristic)
            await self.client.disconnect()

    async def manager(self):
        print("Starting connection manager.")
        while True:
            if self.client:
                await self.connect()
            else:
                await self.select_device()
                await asyncio.sleep(15.0)

    async def connect(self):
        if self.connected:
            return
        try:
            await self.client.connect()
            self.connected = self.client.is_connected
            if self.connected:
                print(F"Connected to self.connected_device.name")
                self.client.set_disconnected_callback(self.on_disconnect)
                await self.client.start_notify(
                    self.read_characteristic, self.notification_handler,
                )
                while True:
                    if not self.connected:
                        break
                    await asyncio.sleep(3.0)
            else:
                print(f"Failed to connect to self.connected_device.name")
        except Exception as e:
            print(e)

    async def select_device(self):
        print("Bluetooh LE hardware warming up...")
        await asyncio.sleep(2.0)  # Wait for BLE to initialize.
        devices = await discover()

        print("Please select device: ")
        for i, device in enumerate(devices):
            print(f"i: device.name")

        response = -1
        while True:
            response = await ainput("Select device: ")
            try:
                response = int(response.strip())
            except:
                print("Please make valid selection.")

            if response > -1 and response < len(devices):
                break
            else:
                print("Please make valid selection.")

        print(f"Connecting to devices[response].name")
        self.connected_device = devices[response]
        self.client = BleakClient(devices[response].address, loop=self.loop)


#############
# Loops
#############
async def user_console_manager(connection: Connection):
    if connection.client and connection.connected:
        input_str = await ainput("Enter command: ")
            
        bytes_to_send = bytearray(map(ord, input_str))
        await connection.client.write_gatt_char(write_characteristic, bytes_to_send)
    else:
        await asyncio.sleep(2.0)


async def main():
    while True:
        await asyncio.sleep(5)


#############
# App Main
#############
read_characteristic = "00001143-0000-1000-8000-00805f9b34fb"
write_characteristic = "00001142-0000-1000-8000-00805f9b34fb"

if __name__ == "__main__":

    # Create the event loop.
    loop = asyncio.get_event_loop()

    db = Database()
    connection = Connection(
        loop, read_characteristic, write_characteristic, db.writeToDB
    )
    try:
        asyncio.ensure_future(connection.manager())
        asyncio.ensure_future(user_console_manager(connection))
        asyncio.ensure_future(main())
        loop.run_forever()
    except KeyboardInterrupt:
        print()
        print("User stopped program.")
    finally:
        print("Disconnecting...")
        loop.run_until_complete(connection.cleanup())
        exit()

编辑:

根据@ukBaz 的建议,我将脚本提炼成以下内容:

import asyncio
from bleak import discover
from bleak import BleakClient

address = "ARDUINO_ADDRESS"

async def connect(address, loop):
    async with BleakClient(address, loop=loop) as client:
        services = await client.get_services()
        for ser in services:
            print(ser.uuid)

loop = asyncio.get_event_loop()
loop.run_until_complete(connect(address, loop))

但是,我还是遇到了错误:

Traceback (most recent call last):
  File "/home/pi/smart-home-pi/test2.py", line 15, in <module>
    loop.run_until_complete(connect(address, loop))
  File "/home/pi/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/pi/smart-home-pi/test2.py", line 9, in connect
    async with BleakClient(address, loop=loop) as client:
  File "/home/pi/.pyenv/versions/3.9.7/lib/python3.9/site-packages/bleak/backends/client.py", line 61, in __aenter__
    await self.connect()
  File "/home/pi/.pyenv/versions/3.9.7/lib/python3.9/site-packages/bleak/backends/bluezdbus/client.py", line 298, in connect
    assert_reply(reply)
  File "/home/pi/.pyenv/versions/3.9.7/lib/python3.9/site-packages/bleak/backends/bluezdbus/utils.py", line 23, in assert_reply
    raise BleakDBusError(reply.error_name, reply.body)
bleak.exc.BleakDBusError: [org.bluez.Error.Failed] Software caused connection abort

会不会是我使用的 Python 版本?

【问题讨论】:

我能够重现您的错误,我认为您的问题与 asyncio 以及您在其中的所有 while 循环有关。一个更好的例子可能是github.com/hbldh/bleak/blob/develop/examples/uart_service.py @ukBaz 我已经编辑了我原来的问题,如果您能再看一下,我将不胜感激。 【参考方案1】:

我已经运行了你的第二个脚本,虽然我没有使用 RPi 或 Arduino,但它对我有用。我也在 Linux 上使用 Python 3.8.10。

在 Linux 上获取蓝牙调试信息:

您可以使用 bluetoothctl 连接到设备吗? service bluetooth status 是否显示错误?

运行脚本时,打开单独的终端并运行以下命令以获取更多调试信息:

bluetootctl journalctl -f -u 蓝牙 sudo busctl monitor org.bluez sudo btmon

我还查看了您的原始脚本以简化它。我想出了以下几点:

import asyncio

from aioconsole import ainput
from bleak import BleakClient, discover


async def data_client(device):

    def handle_rx(_: int, data: bytearray):
        print("received:", data)

    async with BleakClient(device) as client:
        await client.start_notify(read_characteristic, handle_rx)
        while client.is_connected:
            await asyncio.sleep(1)
            input_str = await ainput("Enter command: ")
            bytes_to_send = input_str.encode()
            if input_str == 'exit':
                await client.stop_notify(read_characteristic)
                await client.disconnect()
            else:
                await client.write_gatt_char(write_characteristic, bytes_to_send)


async def select_device():
    print("Scanning for Bluetooh LE hardware...")
    await asyncio.sleep(2.0)  # Wait for BLE to initialize.
    devices = await discover()

    print("Please select device: ")
    for i, device in enumerate(devices):
        print(f"i: device.name")
    print("99: Exit program")
    print("-1: Re-scan for BLE devices")
    response = await ainput("Select device: ")
    try:
        response = int(response.strip())
    except ValueError:
        print("Please make valid selection.")
        response = -1
    print('response', type(response), response)
    if -1 < response < len(devices):
        return devices[response].address
    elif response == 99:
        return 99
    print("Please make valid selection.")


async def main():
    device = None
    keep_alive = True
    while keep_alive:
        print('Device:', device)
        if device is None:
            device = await select_device()
            if device == 99:
                keep_alive = False
        elif device:
            await data_client(device)
            device = None
            print('Device disconnected.\n')


# read_characteristic = "00001143-0000-1000-8000-00805f9b34fb"
read_characteristic = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
# write_characteristic = "00001142-0000-1000-8000-00805f9b34fb"
write_characteristic = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

【讨论】:

非常感谢您提供详细的调试步骤!在没有任何错误的情况下完成它们之后,我决定再次将代码重新刷新到 Arduino 上,从而解决了它。我不知道为什么会这样,因为两个版本的 Arduino 代码之间没有任何变化。你的步骤帮助我找到了问题。再次感谢!

以上是关于无法通过 BLE Python 连接到 Arduino:[org.bluez.Error.Failed] 软件导致连接中止的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 BLE 将 Android 应用程序连接到 Raspberry Pi 3

无法使用 react-native-ble-manager 通过蓝牙连接到设备

无法将 ESP8266 连接到 Arduino IDE

Android 手机从蓝牙更改为 BLE 后无法连接到树莓派

无法连接到 Raspberry Pi 上的 BLE 设备

仅在华硕选项卡中无法发现并连接到 ble 设备