LoginSignup
6
3

More than 5 years have passed since last update.

BluezをD-busから使う LEデバイスをスキャンする

Last updated at Posted at 2016-06-15

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には、アドレス解決した後のアドレスが格納されているみたいです。

参考

6
3
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
6
3