BlueZをD-Busから使う方法について
LEデバイスをスキャンする方法を調べました。
lescan.py
- lescan と同等の表示をする。
- Bluezのtest-discovery を元に作成
lescan.py
#!/usr/bin/python
import dbus
import dbus.mainloop.glib
import gobject as GObject
import bluezutils
devices = {}
def print_compact(properties):
name = "unknown"
address = "<unknown>"
for key, value in properties.iteritems():
if type(value) is dbus.String:
value = unicode(value).encode('ascii', 'replace')
if (key == "Name"):
name = value
if (key == "Address"):
address = value
print("%s (%s)" % (address, name))
def interfaces_added(path, interfaces):
properties = interfaces["org.bluez.Device1"]
if not properties:
return
if path in devices:
devices[path] = dict(devices[path].items() + properties.items())
else:
devices[path] = properties
print_compact(devices[path])
def properties_changed(interface, changed, invalidated, path):
if interface != "org.bluez.Device1":
return
if path in devices:
devices[path] = dict(devices[path].items() + changed.items())
else:
devices[path] = changed
print_compact(devices[path])
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
adapter = bluezutils.find_adapter()
bus.add_signal_receiver(interfaces_added,
dbus_interface = "org.freedesktop.DBus.ObjectManager",
signal_name = "InterfacesAdded")
bus.add_signal_receiver(properties_changed,
dbus_interface = "org.freedesktop.DBus.Properties",
signal_name = "PropertiesChanged",
arg0 = "org.bluez.Device1",
path_keyword = "path")
om = dbus.Interface(bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager")
objects = om.GetManagedObjects()
for path, interfaces in objects.iteritems():
if "org.bluez.Device1" in interfaces:
devices[path] = interfaces["org.bluez.Device1"]
scan_filter = dict()
scan_filter.update({ "Transport": "le" })
adapter.SetDiscoveryFilter(scan_filter)
adapter.StartDiscovery()
mainloop = GObject.MainLoop()
mainloop.run()
- print_compact()はLEデバイスのBDアドレスとBDネームを表示
- interfaces_add()はデバイスが最初に見つかった時の処理
- properties_changed()はデバイスのプロパティに変更があった時の処理
- メイン
- dbusメインループのおまじない
- busとadapterを取得
- イベント受信処理 interfaces_add()とpropoeties_changed()を登録
- bluetoothdが保持しているデバイス情報を取得して 変数devicesに保存する
- leのみ通知するように受信フィルタに設定
- StartDiscovery()でディスカバリを開始
- メインループを開始
実行例
pi@raspberrypi: $ ./lescan.py
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
52:0C:20:EA:75:14 (unknown)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
52:0C:20:EA:75:14 (unknown)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
52:0C:20:EA:75:14 (unknown)
B0:B4:48:C0:C7:13 (CC2650 SensorTag)
-
lescanと違ってsudoしなくても使えるのが良いです。
-
イベントの実際の挙動
-
デバイスが初めて見つかった時にInterfacesAddedが飛んでくる。
-
それ以外は定期的に、RSSIのPropertiesChangedが飛んでくる。たまにUUIDのPropertiesChangedが飛んでくる。
-
このスクリプトだと、RPA(resolvable private address)なランダムアドレスは、アドレス解決した後のアドレスが表示されるようです。
-
bluetoothdには、アドレス解決した後のアドレスが格納されているみたいです。
参考
- Bluez の test/test-discovery http://git.kernel.org/cgit/bluetooth/bluez.git/tree/test/test-discovery
- Bluez の doc/adapter-api.txt https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/adapter-api.txt