前回に引き続き、今回もBluetooth編です。
Bluetoothは、様々なプロトコルから構成される「プロトコルスタック」です。そのLinux版の実装といえるのが、BlueZになります。
今回は、BlueZをCLIとPythonで使う方法を紹介していきます。
BlueZでは主に次のようなことができます。
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の機能を経由することで、BlueZとやり取りすることができます。
Pythonでは、dbus-pythonというパッケージを使用することで、D-Busとの通信ができるようになります。
ただ、D-Busの理解した上でないと使うのがむずかしいので、今回はBlueZが提供しているD-Busインターフェイスを、Pythonでラップした bluezeroというパッケージを使用します。
bluetoothctlはBlueZに付属するCLIです。対話型でBlueZとやり取りすることができます。まずは、bluetoothctlを立ち上げます。
pi@raspberrypi:~ $ bluetoothctl Agent registered [bluetooth]#
ペアリングをするために、周りのデバイスをスキャンします。スキャンをするには scan on
コマンドです。(MACアドレスはマスクしています。)
[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とペアリングしてみます。
[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
コマンドを実行してみます。
[bluetooth]# paired-devices Device 00:00:00:00:00:00 My iPhone
先ほどペアリングしたデバイスが表示されています。前回の記事で触れましたが、この時にボンディングもされていて、BlueZ内に交換した鍵が格納されているので、以降BlueZ経由で相手のデバイスとセキュア通信をすることができます。
今度は、ペアリングをPythonで実装してみます。冒頭で触れたとおり、bluezeroを使用して実装します。
https://github.com/ukBaz/python-bluezero
まず、bluezeroをpipでインストールします
$ pip3 install bluezero
次に、Pythonスクリプトを実装していきます。
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の時間分、スキャンし続けます。dongle.on_device_found
に関数を代入しておきます。pair()
メソッドでペアリングを行います。BlueZはD-Busを経由してやり取りできるので、CLIでもPythonでも同じことができるということが分かりました。