Posted at

BluezをD-busから使う LE advertise

More than 3 years have passed since last update.

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


参考