【蓝牙】一文入门Bluez的BLE基础开发 - BLE广播

接下来关于基于Python的Bluez-BLE基础开发,主要由3篇文章构成,包含以下三点,循序渐进的完成本系列内容的讲解.

  1. 基于Python创建一个BLE设备,能够通过nRF Connect发现其设备和广播包数据
  2. 基于Python创建一个BLE设备,并完成一个自定义BLE Service的注册,实现数据的简单收发
  3. 基于Python创建一个BLE设备,在实现数据收发的基础上,增加BLE 连接等状态的上报
背景知识的掌握
Bluez的了解
dbus-python
开发环境准备
软件版本
操作系统VM虚拟机+Ubuntu 20.04
系统已安装的bluez5.50+
Bluez源码5.50+

我这里使用的版本,

test bluetoothctl --version
bluetoothctl: 5.53
test uname -a
Linux t 5.8.0-50-generic #56~20.04.1-Ubuntu SMP Mon Apr 12 21:46:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

bluez 源码: bluez-5.50

建议是和我这边保持一样的版本.

创建一个BLE设备-仅支持BLE广播
获取dbus

在对dbus和bluez有了一定了解后,就能知道我们首先获取与dbus-ddaemon的通信入口.

# 获取系统的dbus
bus = dbus.SystemBus()

在获取到System的dbus后,我们就可以通过dbus 对bluez进行一些操作.
在进行具体的coding之前我们先通过gdbus命令来看下bluez支持的相关interface(object):

## 我这里只是截取了部分的输出,详细请在自己的机器进行测试查看
➜  bluez-5.50 gdbus introspect -y -d "org.bluez" -o "/org/bluez/hci0"
node /org/bluez/hci0 {
  interface org.freedesktop.DBus.Introspectable {
    methods:
      Introspect(out s xml);
    signals:
    properties:
  };
  interface org.bluez.Adapter1 {
    methods:
      StartDiscovery();
      SetDiscoveryFilter(in  a{sv} properties);
      StopDiscovery();
      RemoveDevice(in  o device);
      GetDiscoveryFilters(out as filters);
    signals:
    properties:
      readonly s Address = '00:1A:7D:DA:71:13';
      readonly s AddressType = 'public';
      readonly s Name = 't';
      readwrite s Alias = 't';

通过gdbus相关命令可以看到bluez(BLE)主要实现了如下interface:

  1. interface org.bluez.Adapter1
  2. org.freedesktop.DBus.Properties
  3. org.bluez.GattManager1
  4. org.bluez.LEAdvertisingManager1
查找Bluez BLE adapter
def find_adapter(bus):
    remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
                               DBUS_OM_IFACE)
    objects = remote_om.GetManagedObjects()

    for o, props in objects.items():
        if LE_ADVERTISING_MANAGER_IFACE in props:
            return o

    return None
    
def main():
    global mainloop

    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()

    adapter = find_adapter(bus)
    if not adapter:
        print('LEAdvertisingManager1 interface not found')
        return


如上面贴出的Python代码,定义的find_adapter函数,主要是获取到Bluez BLE的adapter, 用于接下来对于以下interface的操作

  1. interface org.bluez.Adapter1
  2. org.freedesktop.DBus.Properties
  3. org.bluez.LEAdvertisingManager1

find_adapter在main中被调用,需要传递bus参数.

在获取到adapter后,需要打开该adapter, 做如下操作:

  1. 获取interface org.freedesktop.DBus.Properties ,调用其提供的Set 方法
  2. 调用Set方法,将org.bluez.Adapter1 interface 中的properties:Powered 设置为true.

相关代码如下:

adapter_props = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
                                   "org.freedesktop.DBus.Properties");

adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(1))

初始化广播包数据并使能

初始化广播包数据:

class TestAdvertisement(Advertisement):

    def __init__(self, bus, index):
        Advertisement.__init__(self, bus, index, 'peripheral')
        self.add_service_uuid('180D')
        self.add_service_uuid('180F')
        self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 0x04])
        self.add_service_data('9999', [0x00, 0x01, 0x02, 0x03, 0x04])
        self.add_local_name('Tracy')
        self.include_tx_power = True
        self.add_data(0x26, [0x06])

具体请参考bluez源码提供的提供的官方文档关于广播包数据的描述, bluez-5.50/doc/advertising-api.txt

主要是对org.bluez.LEAdvertisement1 中Properties的操作.

广播包数据注册并使能

ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
                                LE_ADVERTISING_MANAGER_IFACE)

    test_advertisement = TestAdvertisement(bus, 0)

mainloop = GObject.MainLoop()

ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
                                     reply_handler=register_ad_cb,
                                     error_handler=register_ad_error_cb)
  1. 在main函数下,调用dbus.Interface获取LE_ADVERTISING_MANAGER_IFACE的interface.

  2. 在main函数下,调用TestAdvertisement完成BLE广播包数据的设置

  3. 最后调用interface org.bluez.LEAdvertisingManager1下的RegisterAdvertisement进行广播包的注册和使能

具体请参考bluez源码提供的提供的官方文档关于广播包数据的描述, bluez-5.50/doc/advertising-api.txt

GLib Loop

在完成Bluez相关的操作后,不要忽略:

mainloop = GObject.MainLoop()
mainloop.run()

Mainloop起到了系统调度的作用,这一点在后续的文章中会详细说明.

运行example-advertisement
➜  test python3.8 example-advertisement 
example-advertisement:201: PyGIDeprecationWarning: GObject.MainLoop is deprecated; use GLib.MainLoop instead
  mainloop = GObject.MainLoop()
GetAll
returning props
Advertisement registered


在完成Python代码的编写后,通过python解析器运行该python脚本,运行结果如上.

然后通过nRF Connect 在Android手机上进行BLE设备的搜索、发现,如下图在nRF Connect发现了名称为"Tracy"设备,并确认广播包数据和我们代码中定义的是一致的.
在这里插入图片描述

总结

对于Bluez的开发,一个重要的点是需要掌握dbus中相关interface的操作!!
另外需要详细的阅读Bluez源码下面doc目录的相关doc.

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值