使用 bluez python dbus 接口连接到蓝牙 LE 设备
Connect to a Bluetooth LE device using bluez python dbus interface
我想连接到蓝牙 LE 设备并在 python 中接收来自它的通知。我想使用 Bluez dbus API,但找不到我能理解的示例。 :-)
借助 gatttool,我可以使用以下命令:
gatttool -b C4:8D:EE:C8:D2:D8 --char-write-req -a 0x001d -n 0100 –listen
如何使用 Bluez 的 dbus API 在 python 中执行相同的操作?
从 bluez 包中查看 'test/example-gatt-client'
使用 BlueZ DBus API 作为 gatt 客户端可能是使用 pydbus 库最简单的方法。 https://pypi.org/project/pydbus/
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/device-api.txt
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt
一些有助于您入门的知识:
- bluez 的 Dbus 服务被称为 'org.bluez'
- Raspberry Pi 上的蓝牙适配器通常将“/org/bluez/hci0”作为 DBus 对象路径。
- 设备的 DBus 对象路径是适配器路径加上前缀为 'dev_' 的 mac 地址,分号替换为
下划线。即 'DE:82:35:E7:43:BE' 会在
'/org/bluez/hci0/dev_DE_82_35_E7_43_BE'
我没有你的设备,所以我使用 BBC micro:bit 做了一个例子来更改它更新温度值(周期)的频率值,然后获取这些温度值的通知。希望它可以很容易地适应您的情况。
此代码假设您已经使用 bluetoothctl
配对您的设备。
在命令行中键入 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()
我想连接到蓝牙 LE 设备并在 python 中接收来自它的通知。我想使用 Bluez dbus API,但找不到我能理解的示例。 :-)
借助 gatttool,我可以使用以下命令:
gatttool -b C4:8D:EE:C8:D2:D8 --char-write-req -a 0x001d -n 0100 –listen
如何使用 Bluez 的 dbus API 在 python 中执行相同的操作?
从 bluez 包中查看 'test/example-gatt-client'
使用 BlueZ DBus API 作为 gatt 客户端可能是使用 pydbus 库最简单的方法。 https://pypi.org/project/pydbus/
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/device-api.txt
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt
一些有助于您入门的知识:
- bluez 的 Dbus 服务被称为 'org.bluez'
- Raspberry Pi 上的蓝牙适配器通常将“/org/bluez/hci0”作为 DBus 对象路径。
- 设备的 DBus 对象路径是适配器路径加上前缀为 'dev_' 的 mac 地址,分号替换为 下划线。即 'DE:82:35:E7:43:BE' 会在 '/org/bluez/hci0/dev_DE_82_35_E7_43_BE'
我没有你的设备,所以我使用 BBC micro:bit 做了一个例子来更改它更新温度值(周期)的频率值,然后获取这些温度值的通知。希望它可以很容易地适应您的情况。
此代码假设您已经使用 bluetoothctl
配对您的设备。
在命令行中键入 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()