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

时间:2016-08-15 10:11:18

标签: python dbus bluez gatt

我想连接蓝牙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中做同样的事情?

2 个答案:

答案 0 :(得分:2)

使用pydbus库可能最容易将BlueZ DBus API用作gatt客户端。 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

要入门的一些有用的事情:

  1. bluez的Dbus服务称为“ org.bluez”
  2. Raspberry Pi上的Bluetooth适配器通常将'/ org / bluez / hci0'作为DBus对象路径。
  3. 设备的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()

答案 1 :(得分:0)

请参阅bluez package中的'test / example-gatt-client'