はじめに
前回に引き続き、今回もBluetooth編です。
Bluetoothは、様々なプロトコルから構成される「プロトコルスタック」です。そのLinux版の実装といえるのが、BlueZになります。
今回は、BlueZをCLIとPythonで使う方法を紹介していきます。
BlueZとは?
BlueZでは主に次のようなことができます。
- Bluetoothデバイスとのペアリング・ボンディング(鍵の保管)
- Bluetoothの各種プロトコルを使用した通信 (以前紹介したBLEなども含みます)
BlueZはデーモンとして起動させて使用します。また、BlueZはD-Busでのプロセス間通信をサポートしているので、D-Bus経由でBlueZと会話することで、Bluetoothを使ったプログラミングをすることができます。
もちろん、Linuxのデスクトップ環境でBluetoothのペアリングをしたり、接続したりするのも、裏ではBlueZが動いています。
BlueZと会話するには、CLIも用意されています。代表的なものでは、bluetoothctlやbt-agentなどがあり、BlueZデーモンと会話することで、Bluetoothの機能を使用することができるようになっています。この記事では、BlueZを使用してデバイスとのペアリングをする方法について、bletoothctlとPythonでの実装方法を紹介していきます。
D-Busとは?
本題に入る前に、D-Busについて簡単に触れておきます。D-Busとは、プロセス間通信をするためのシステムです。D-Bus自体はデーモン起動していて表に出ることはありませんが、プロセス同士がD-Busを経由して通信することができます。
主に、次のようなD-Busの機能を経由することで、BlueZとやり取りすることができます。
- メソッド呼び出し
例: デバイスのスキャン開始・停止、ペアリングなど - シグナル
例: デバイスのスキャンが見つかった時に通知される時など - プロパティの読み書き
例: ペアリング済みのデバイス一覧を取得など
Pythonでは、dbus-pythonというパッケージを使用することで、D-Busとの通信ができるようになります。
ただ、D-Busの理解した上でないと使うのがむずかしいので、今回はBlueZが提供しているD-Busインターフェイスを、Pythonでラップした bluezeroというパッケージを使用します。
bluetoothctlでのペアリング
bluetoothctlはBlueZに付属するCLIです。対話型でBlueZとやり取りすることができます。まずは、bluetoothctlを立ち上げます。
1 2 3 | pi@raspberrypi:~ $ bluetoothctl Agent registered [bluetooth]# |
ペアリング
ペアリングをするために、周りのデバイスをスキャンします。スキャンをするには
scan on
コマンドです。(MACアドレスはマスクしています。)
1 2 3 4 5 | [bluetooth]# scan on Discovery started [NEW] Device 00:00:00:00:00:00 iPhone [NEW] Device 11:22:33:44:55:66 [NEW] Device AA:AA:AA:AA:AA:AA |
このように、付近で見つかったデバイスが出力されます。ここにはMACアドレスとデバイス名が表示されていています。スキャンを止めるには、
scan off
コマンドです。
目的のデバイスが見つかったら
pair MACアドレス
でペアリングを開始します。今回は先ほどん見つかったiPhoneとペアリングしてみます。
1 2 3 4 5 | [bluetooth]# pair 00:00:00:00:00:00 Attempting to pair with 00:00:00:00:00:00 [CHG] Device 00:00:00:00:00:00 Connected: yes Request confirmation [agent] Confirm passkey 876754 (yes/no): yes |
すると、iPhone側にはペアリング要求のアラートが表示されました。bluetoothctl側と同じpasskeyがiPhone側に表示されています。
iPhone側で「ペアリング」を押すと、ペアリング完了です。ペアリング済みのデバイスを確認する
paired-devices
コマンドを実行してみます。
1 2 | [bluetooth]# paired-devices Device 00:00:00:00:00:00 My iPhone |
先ほどペアリングしたデバイスが表示されています。前回の記事で触れましたが、この時にボンディングもされていて、BlueZ内に交換した鍵が格納されているので、以降BlueZ経由で相手のデバイスとセキュア通信をすることができます。
Pythonでの実装
今度は、ペアリングをPythonで実装してみます。冒頭で触れたとおり、bluezeroを使用して実装します。
https://github.com/ukBaz/python-bluezero
bluezeroでのペアリング実装
まず、bluezeroをpipでインストールします
1 | $ pip3 install bluezero |
次に、Pythonスクリプトを実装していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import logging from bluezero import adapter, device from bluezero import tools found_device: device.Device = None # デバイスが見つかったときのコールバック def on_device_found(device: device.Device): global found_device try: print(device.address) print(device.name) if (device.name == 'My iPhone'): found_device = device except: print('Error') def main(): # Bluetoothドングルの取得 dongles = adapter.list_adapters() print('dongles available: ', dongles) dongle = adapter.Adapter(dongles[0]) # Bluetoothドングルの電源が切れている場合は、電源を入れる if not dongle.powered: dongle.powered = True print('Now powered: ', dongle.powered) print('Start discovering') # デバイスが見つかったときのコールバック dongle.on_device_found = on_device_found # デバイスのスキャン開始 dongle.nearby_discovery(timeout=20) # デバイスが見つかったら、ペアリング if (found_device != None) : found_device.pair() # dongle.powered = False if __name__ == '__main__': print(__name__) logger = tools.create_module_logger('adapter') logger.setLevel(logging.DEBUG) main() |
実装ポイントです。
-
dongle.nearby_discovery(timeout=20)
でスキャン開始します。このメソッド内では、EventLoopが回るようになっていて、引数のtimeoutの時間分、スキャンし続けます。 - デバイスのスキャン結果は、D-Busで通知されます。その通知を受け取るには、
dongle.on_device_found
に関数を代入しておきます。
第一引数に、device.Device型で検出したデバイスが渡されるので、保持しておく必要があります。 - ペアリングするには、スキャンで見つかったデバイスのオブジェクトの
pair()
メソッドでペアリングを行います。
さいごに
BlueZはD-Busを経由してやり取りできるので、CLIでもPythonでも同じことができるということが分かりました。