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
参考
- Bluez の example-advertisement https://git.kernel.org/cgit/bluetooth/bluez.git/tree/test/example-advertisement
- Bluez の advertising-api.txt https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/advertising-api.txt