つれづれなる備忘録

日々の発見をあるがままに綴る

Win10環境下のpythonでBLE通信

1. Win10下のpythonによるBLE通信

 今回はWindows10の環境下のpythonでBLE(Bluetooth Low Energy)通信する方法について紹介したい。実際には業務上で調べていたことなので具体的なデバイス名は伏せるが、参考にしたサイトの情報に従って通信に成功できた。いろいろなデバイスで試したわけではないので、必ず通信できるとは限らないと思うが、Win10下のBLE通信でつまづいている人の参考になればと思う。

2. Win10でのBLE通信の課題

 実際にIoTセンサの類でBLE通信を使ったことがあれば実感が湧くと思うが、IoTセンサのモニタを無線(BLEが多く使われる)でモニタリングしようとすると、iOS/Androidアプリという形でメーカーから提供されることが多い。(BLEの通信距離が短いためモバイルとの相性がよいためかも)ただ業務用でPCを使う場合Windows10が恐らく標準なので、IoTセンサから無線経由でデータを回収するにはWindows10の環境下でpythonユーザであればpythonで行いたくなる。ゼロベースからコーディングを行うのであれば別だが、pythonの場合はモジュールを利用することにより効率よくコーディングを行える。

 pythonで使えるBLEのモジュールについて代表的なものは PythonからBLEを制御するライブラリの調査 - masato-ka's diaryにまとめられている。このうちpybluezがwindowsで利用可能なように見えるが、インストールしてみる(Visual C++ 14 とwindows10 SDKが必要)とBLEの機能だけ使用できない。恐らく通常のBluetoothは使えるが公式ドキュメント参照:1. Installing PyBluez — PyBluez master documentation)には

For experimental Bluetooth Low Energy support (only for Linux platform - for additional dependencies please take look at: ble-dependencies)

とあり、Linuxしかサポートしていない旨が記述されている。なおRaspberry pipythonを使ってBLE通信する場合はpybluezを用いているケースが多い。

3. Bleakの利用

 半年ぐらい前までは検索で全く引っかかってこなかったのだが、つい最近調べてみるとBleakというモジュールがWindows10環境下でBLE通信に使えるということがわかってきた。公式ドキュメント https://bleak.readthedocs.io/en/latest/#を見ると2017年末に初めて公開されて、昨年(2019)と今年(2020)でかなり更新されており2020年7月現在はバージョン0.7.1となっている。標準的には

pip install bleak

でインストールできる。なお使用するPCのBluetoothがBLE対応になっていることを確認し、BLE対応でなければBLEドングル(Bluetooth 4.0やSmart Readyなど)の購入が必要。Bluetoothの規格については過去記事も参照

atatat.hatenablog.com

4. BLE通信の流れ

 BLEで接続するにはデバイス側(Peripheral)が電波を出すAdvertiseからはじまり、PC側(Central)がScanをして周辺にあるデバイスを検索して、特定のアドレス(MACアドレス)を持つデバイスとConnectして制御(Read,Write,Notify)を行い、終了したらdisconnectというのが一連の流れになる。BLE通信の仕組みは開発視点の超簡単BLE入門が参考になる。PC側としてはBLEのScanとConnectの操作が必要で、これをPython+Bleakで実行する。

5. BleakによるScan

 Bleakを使ってソニーのtoioを動かしている例Pythonライブラリ bleakでWindows10/macOS/Linux上でtoioコア キューブを動かしてみる - Qiitaがあるのでそちらも参考になる。公式ドキュメントhttps://bleak.readthedocs.io/en/latest/scanning.htmlにあるように以下のコードを記述して、pyファイルとしてコマンドラインから実行してScanを行う。なおJupyter NotebookのようなIPythonカーネルを使用するツールはエラーがでるので注意が必要だ。

import asyncio
from bleak import discover

async def run():
    devices = await discover()
    for d in devices:
        print(d)

loop = asyncio.get_event_loop()
loop.run_until_complete(run())

実行すると

24:71:89:CC:09:05: CC2650 SensorTag
4D:41:D5:8C:7A:0B: Apple, Inc. (b'\x10\x06\x11\x1a\xb2\x9b\x9c\xe3')

のようにコンソール上に表示される。一番左の例えば24:71:89:CC:09:05MACアドレスでConnectの際に必要になる。なお上のコードのprint(d)のところprint(d.address,d.name,d.rssi)などとするとMACアドレス,デバイス名,RSSI値が表示される。特定のデバイス名がわかっていればif(d.name=='xxxx'):とすれば特定のデバイスのみ表示できる。RSSI値は電波の受信強度をdBで表したもので、RSSI値からおおよそのデバイスまでの距離を推定することができる。iBeaconやEddystoneといった屋内測位機能においてRSSI値が使われている。(詳しくはRSSI と TxPower からビーコンとの距離および近接度(Proximity)を推定する - Qiitaを参照)

6. Bleakによる接続

 次にデバイスに接続して、読み出し(Read)を行うには以下のようなコードを記述して、Scanと同じくpyファイルとしてコマンドラインから実行する。なおaddressはscan時に得られた接続先のMACアドレスで、uuidは"00002a24-0000-1000-8000-00805f9b34fb"のようなフォーマットでデバイスのマニュアルなどを参照する必要がある。

import asyncio
from bleak import BleakClient

address = "24:71:89:cc:09:05"
UUID = "00002a24-0000-1000-8000-00805f9b34fb"

async def run(address, loop):
    async with BleakClient(address, loop=loop) as client:
        x = await client.is_connected()
        print("Connected: {0}".format(x))
        y = await client.read_gatt_char(UUID)
        print(y)

loop = asyncio.get_event_loop()
loop.run_until_complete(run(address, loop))

まず接続できているかどうか確認するには、is_connected()を利用する。上記ではx=await client.is_connected()として接続できているればTrueが返ってくる。デバイスから何か情報を読み出すにはread_gat_char(UUID)を利用する。どのような情報を読み出すかは、デバイスのマニュアルを参照して適切なUUIDを指定する必要がある。上記ではy = await client.read_gatt_char(UUID)でyにデータを格納して、単にprint(y)としている。yはバイト列として返される場合は、マニュアルを参照して、各バイトがどの情報に相当するか、センサ値であれば適切に値を変換する処理が必要になる。書き出しの場合はawait client.write_gatt_char(UUID, write_data)の書式でデータを書き込む。その他メソッドは公式マニュアルhttps://bleak.readthedocs.io/en/latest/api.htmlを参照。

7. まとめ

 今回はWindows10の環境下でpythonのBleakモジュールを用いてBLE通信するための設定を紹介した。Bleakはバージョンとしては0.7.1で昨年から今年にかけて頻繁に更新されているので、バージョンが上がると使い勝手は(良い方に)変わる可能性があるが、今のところWindows環境下のpythonを使ってBLE通信できる唯一の方法だと思う。