【发布时间】:2021-11-16 07:58:38
【问题描述】:
我正在尝试通过 BLE 将数据从我的 Arduino 发送到我的 Raspberry Pi。但是,当我运行以下脚本时,有时会出现以下两个错误之一:
[org.bluez.Error.Failed] Software caused connection abort 或 This 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 bluetooth 和 sudo 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 我已经编辑了我原来的问题,如果您能再看一下,我将不胜感激。
标签: python arduino bluetooth raspberry-pi python-asyncio