Raspberry Pi的藍牙庫


0

根據bluepy https://github.com/IanHarvey/bluepy/issues/403作者的最新更新,它似乎需要一些時間才能被更新,否則如果沒有進一步的發展,它可能會被放棄

Pybluez是,但該項目https://github.com/pybluez/pybluez處於未處於積極開發狀態

有沒有好的藍牙低能耗庫可供使用?

1

There are many options for using Python for Bluetooth Low Energy on Raspberry Pi. Maybe too many options and that is why there is maybe no one winner for all situations.

BLE defines multiple roles that devices can play:

  • The Broadcaster (beacon) is a transmit only application.
  • The Observer (scanner) is for receive only applications.
  • Devices acting in the Peripheral role advertise and can accept connections.
  • Devices acting in the Central role can scan for and connect to Peripheral devices.

For brevity I shall focus this answer on the Central role and that is what I see that most people want to to do with a Raspberry Pi

BlueZ API

BlueZ is the Bluetooth stack for Linux and they have a few API's for people to use. A list of the possible API’s starting from lowest level and going to the highest. For most people, the higher the better.

HCI Socket

This bypasses the bluetoothd that is running on the Linux system that is used by the desktop tools. Using this is not a great idea unless you really, really know what you are doing.

All the information is available in the Bluetooth Core Specification which runs to about 3,256 pages for the 5.2 version of the spec.

MGMT Socket

The BlueZ Bluetooth Mamagement API is the next step up and the lowest level that the BlueZ developers recommend.

The problem for Python users is this bug makes it difficult to access the mgmt socket. There are other duplicate bugs on this in the system. Until they are fixed, this remains off bounds for many Python users.

DBus API

This should be the go to level for most people wanting to interact with the BlueZ API’s. However, it seems the number of people that have done things with DBus previously is a relatively small group and it is another level of indirection to learn.

There are a number of Python libraries that offer DBus bindings for Python.

https://wiki.python.org/moin/DbusExamples

However, there isn’t just one library that is correct for all cases. pydbus is one of the easier ones to get started with.

The BlueZ DBus API for interacting with the Bluetooth Adapter on your Raspberry Pi is documented at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt

And the device API is at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt

The BlueZ DBus Service is org.bluez. The Object Path is less obvious from the documentation but is /org/bluez/hci0 by default on most Linux machines. With this information we can quickly look to see properties from the adapter and device using the DBus API. The example below looks at name, if it is powered, and its mac adderess:

import pydbus
from time import sleep
from gi.repository import GObject

# Setup of device specific values
dev_id = 'DE:82:35:E7:43:BE'
btn_a_uuid = 'E95DDA90-251D-470A-A062-FA1922DFA9A8'
temp_period_uuid = 'E95D1B25-251D-470A-A062-FA1922DFA9A8'
temp_value_uuid = 'E95D9250-251D-470A-A062-FA1922DFA9A8'

# DBus object paths
bluez_service = 'org.bluez'
adapter_path = '/org/bluez/hci0'
device_path = f"{adapter_path}/dev_{dev_id.replace(':', '_')}"

# setup dbus
bus = pydbus.SystemBus()
mngr = bus.get(bluez_service, '/')
adapter = bus.get(bluez_service, adapter_path) 
device = bus.get(bluez_service, device_path)

# Access adapter properties
print(adapter.Name)
print(adapter.Powered)
print(adapter.Address)

# Commands and properties from the DBus API
print(dir(adapter))
print(dir(device))

# Assume device has been paired already so can use connect
device.Connect()

GATT

It is a little bit more work to do a GATT characteristics.

https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt

# Wait for GATT database
while not device.ServicesResolved:
    sleep(0.5)

def get_characteristic_path(dev_path, uuid):
    """Look up DBus path for characteristic UUID"""
    mng_objs = mngr.GetManagedObjects()
    for path in mng_objs:
        chr_uuid = mng_objs[path].get('org.bluez.GattCharacteristic1', {}).get('UUID')
        if path.startswith(dev_path) and chr_uuid == uuid.casefold():
           return path

def as_int(value):
    """Create integer from bytes"""
    return int.from_bytes(value, byteorder='little')

# Characteristic DBus information
temp_reading_path = get_characteristic_path(device._path, temp_value_uuid)
temp_period_path = get_characteristic_path(device._path, temp_period_uuid)
temp = bus.get('org.bluez', temp_reading_path)
period = bus.get('org.bluez', temp_period_path)
# Read value of characteristics
print(temp.ReadValue({}))
# [0]
print(period.ReadValue({}))
# [232, 3]
print(as_int(period.ReadValue({})))
# 1000

# Write a new value to one of the characteristics
new_value = int(1500).to_bytes(2, byteorder='little')
period.WriteValue(new_value, {})

Notifications

Notification need to be done asynchronously.

# Enable eventloop for notifications
def temp_handler(iface, prop_changed, prop_removed):
    """Notify event handler for temperature"""
    if 'Value' in prop_changed:
        print(f"Temp value: {as_int(prop_changed['Value'])} \u00B0C")

mainloop = GLib.MainLoop()
temp.onPropertiesChanged = temp_handler
temp.StartNotify()
try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()
    temp.StopNotify()
    device.Disconnect()

Libraries to help

There are plenty of them out there. I keep a list of many of them at: https://github.com/ukBaz/python-bluezero/wiki

Most of them are pretty niche in what they do. There are a number of them that are abondonware. This isn’t surprising given how big Bluetooth is and the many things can be done with it.

It is difficult to automate the testing of Python Bluetooth libraries and I think this is what ends up being the main reason why the libraries stay niche or abandoned.

Bluetooth Classic

I will make mention of Bluetooth Classic at the end here as this can be done with with the standard Bluetooth library

http://blog.kevindoran.co/bluetooth-programming-with-python-3/

And I have found the BlueDot Python library provides a more reliable RFCOMM/SPP client/server:

https://bluedot.readthedocs.io/en/latest/btcommapi.html

It contains an example server

https://github.com/martinohanlon/BlueDot/blob/master/examples/server_debug.py

And an example client:

https://github.com/martinohanlon/BlueDot/blob/master/examples/client_debug.py