LoginSignup
2
4

More than 5 years have passed since last update.

BluezをD-busから使う LE advertise

Posted at

BlueZをD-Busから使う方法について

LEのAdvertiseする方法を調べました。

Bluezのバージョンについて

  • D-Bus から LE advertisetをするには5.30以降が必要です。下記は5.40で確認しました。

leadv.py

  • Bluezのexample-advertisementを参考にしました。
leadv.py
#!/usr/bin/python

import dbus
import dbus.mainloop.glib
import dbus.service
import gobject as GObject

mainloop = None

BLUEZ_SERVICE_NAME = 'org.bluez'
LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'

LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1'

class FixedAdvertisement(dbus.service.Object):
    PATH_BASE = '/org/bluez/example/fixedadvertisement'

    def __init__(self, bus, index, advertising_type):
        self.path = self.PATH_BASE + str(index)
        self.bus = bus
        self.ad_type = advertising_type
        dbus.service.Object.__init__(self, bus, self.path)

    def get_path(self):
        return dbus.ObjectPath(self.path)

    @dbus.service.method(DBUS_PROP_IFACE,
                         in_signature='s',
                         out_signature='a{sv}')
    def GetAll(self, interface):
        if interface != LE_ADVERTISEMENT_IFACE:
            raise InvalidArgsException()

        properties = dict()
        properties['Type'] = self.ad_type
        return properties

    @dbus.service.method(LE_ADVERTISEMENT_IFACE,
                         in_signature='',
                         out_signature='')
    def Release(self):
        print '%s: Released!' % self.path

def register_ad_cb():
    print 'Advertisement registered'

def register_ad_error_cb(error):
    print 'Failed to register advertisement: ' + str(error)
    mainloop.quit()

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.iteritems():
        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

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

    ad_manager.RegisterAdvertisement(FixedAdvertisement(bus, 0, 'broadcast').get_path(), {},
                                     reply_handler=register_ad_cb,
                                     error_handler=register_ad_error_cb)

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

if __name__ == '__main__':
    main()
  • FixedAdvertisementクラスはアドバタイズデータのクラスです。
    • サービスデーモンから呼ばれるので、GetAll()とRemove()のメソッドをクラスに用意する必要があります。
    • GetAll()では、アドバタイズデータをpropertisとして返します。
    • Remove()はアドバタイズを停止するときに呼ばれれます。
    • GetAll()とRemove()は定義する際に@dbus.service.methodのおまじないが必要です。
  • register_ad_cb()とregister_ad_error_cb()はRegisterAdvertisement()で登録するコールバック関数です。
  • find_adapter()はAdapterを探して、LE_ADVERTISING_MANAGER_IFACEの有無からLE advertiseが使えるか判定します。
  • メイン
    • mainloopのおまじない
    • busとadapterの取得
    • アドバタイズマネージャの取得
    • FixedAdvertisementを生成して、RegisterAdvertisement()に登録する
    • メインループ

動作例

  • アドバタイズはスマートフォン等のアプリで確認してください。
pi@raspberrypi: $ ./leadv.py
Advertisement registered

アドバタイズで指定できるパラメータ

  • Type : broadcast or peripheral
  • ServiceUUIDs
  • ManufacturerData
  • SolicitUUIDs
  • ServiceData
  • IncludeTxPower

参考

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4