简体   繁体   English

使用 bluez python dbus 接口连接到蓝牙 LE 设备

[英]Connect to a Bluetooth LE device using bluez python dbus interface

I would like to connect to a Bluetooth LE device and receive notifications from it in python.我想连接到蓝牙 LE 设备并在 python 中接收来自它的通知。 I would like to use the Bluez dbus API, but can't find an example I can understand.我想使用 Bluez dbus API,但找不到我能理解的示例。 :-) :-)

With gatttool, I can use the following command:使用 gatttool,我可以使用以下命令:

gatttool -b C4:8D:EE:C8:D2:D8 --char-write-req -a 0x001d -n 0100 –listen gatttool -b C4:8D:EE:C8:D2:D8 --char-write-req -a 0x001d -n 0100 –listen

How can I do the same in python, using the dbus API of Bluez?如何使用 Bluez 的 dbus API 在 python 中做同样的事情?

To use the BlueZ DBus API's to be a gatt client is probably easiest with the pydbus library.使用 pydbus 库可能最容易使用 BlueZ DBus API 作为 gatt 客户端。 https://pypi.org/project/pydbus/ https://pypi.org/project/pydbus/

The BlueZ DBus API documents are available at: BlueZ DBus API 文档位于:

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

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

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

Some useful things to know to get you started:一些有用的信息可以帮助您入门:

  1. The Dbus service for bluez is called 'org.bluez' bluez 的 Dbus 服务称为“org.bluez”
  2. The Bluetooth adapter on a Raspberry Pi normally has '/org/bluez/hci0' as DBus object path. Raspberry Pi 上的蓝牙适配器通常将“/org/bluez/hci0”作为 DBus 对象路径。
  3. The DBus Object path to a device is the adapter path plus the mac address prepended by 'dev_' and the semi-colons replaced with underscores.设备的 DBus 对象路径是适配器路径加上 'dev_' 前缀的 mac 地址和用下划线替换的分号。 ie 'DE:82:35:E7:43:BE' would be found at '/org/bluez/hci0/dev_DE_82_35_E7_43_BE'即“DE:82:35:E7:43:BE”可以在“/org/bluez/hci0/dev_DE_82_35_E7_43_BE”找到

I don't have your device so I have done an example using a BBC micro:bit to change the value of how often it updates the temperature value (period) and then get notifications of those temperature values.我没有你的设备,所以我做了一个例子,使用 BBC micro:bit 来改变它更新温度值(周期)的频率,然后获取这些温度值的通知。 Hopefully it will be easy to adapt this to your situation.希望它可以很容易地适应您的情况。

This code does assume that you have already used bluetoothctl to pair your device.此代码假定您已经使用bluetoothctl配对您的设备。 Type bluetoothctl devices on the command line and if you device is in the list, then this is a good sign.在命令行中键入bluetoothctl devices ,如果您的设备在列表中,那么这是一个好兆头。

import pydbus
from gi.repository import GLib

# Setup of device specific values
dev_id = 'DE:82:35:E7:43:BE'
adapter_path = '/org/bluez/hci0'
device_path = f"{adapter_path}/dev_{dev_id.replace(':', '_')}"
temp_reading_uuid = 'e95d9250-251d-470a-a062-fa1922dfa9a8'
temp_period_uuid = 'e95d1b25-251d-470a-a062-fa1922dfa9a8'

# Setup DBus informaton for adapter and remote device
bus = pydbus.SystemBus()
mngr = bus.get('org.bluez', '/')
adapter = bus.get('org.bluez', adapter_path)
device = bus.get('org.bluez', device_path)
# Connect to device (needs to have already been paired via bluetoothctl)
device.Connect()

# Some helper functions
def get_characteristic_path(device_path, uuid):
    """Find DBus path for UUID on a device"""
    mng_objs = mngr.GetManagedObjects()
    for path in mng_objs:
        chr_uuid = mng_objs[path].get('org.bluez.GattCharacteristic1', {}).get('UUID')
        if path.startswith(device_path) and chr_uuid == uuid:
           return path

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

# Get a couple of characteristics on the device we are connected to
temp_reading_path = get_characteristic_path(device._path, temp_reading_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, {})

# 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()

请参阅 bluez 包中的“test/example-gatt-client”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM