カテゴリー: Tech

BlueZとは? bluetoothctlとPythonから使用する方法を紹介!

はじめに

前回に引き続き、今回も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を立ち上げます。

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での実装

今度は、ペアリングをPythonで実装してみます。冒頭で触れたとおり、bluezeroを使用して実装します。
https://github.com/ukBaz/python-bluezero

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の時間分、スキャンし続けます。
  • デバイスのスキャン結果は、D-Busで通知されます。その通知を受け取るには、 dongle.on_device_foundに関数を代入しておきます。
    第一引数に、device.Device型で検出したデバイスが渡されるので、保持しておく必要があります。
  • ペアリングするには、スキャンで見つかったデバイスのオブジェクトの pair()メソッドでペアリングを行います。

さいごに

BlueZはD-Busを経由してやり取りできるので、CLIでもPythonでも同じことができるということが分かりました。

おすすめ書籍

カイザー

シェア
執筆者:
カイザー
タグ: Bluetooth

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前