ESP32のMicroPythonでBluetooth(BLE)を試す


MicroPythonの更新状況のウオッチを最近さぼっていたのですが、気がついたら汎用のBLEプロトコルスタックのモジュールが追加されていました。
ESP32でも使用できるようになっているので、試してみました。

このモジュールはソースツリーの中ではextmodの中に入っていて、ファイルシステムやlwIP等と同じく、プラットホーム非依存なモジュールの位置づけになっています。
もちろん、デバイス部分はプラットホームに依存しますのでプラットホーム側での対応は必要です。
ESP32用MicroPythonでは、ESP-IDFのv4.0系ビルドで対応しています。

というわけで、まずはビルドしてみました。
ESP-IDFのv4.0系はExperimentalであるため、これまではv3.0系でビルドしていたので、まずESP-IDFを更新します。
私は以前導入した開発環境を流用したため、ビルド手順の詳細は端折りますので、詳しくは公式のREADMEを参照してください。

ESP-IDFはバージョンアップが激しいため、MicroPythonでは特定のリビジョンを使用します。
リビジョンの情報はMakefileに書かれていますので、そのリビジョンをcheckoutします。

$ cd micropython
$ grep IDF ports/esp32/Makefile | head -5
# the git hash of the currently supported ESP IDF version
ESPIDF_SUPHASH_V3 := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df
ESPIDF_SUPHASH_V4 := 310beae373446ceb9a4ad9b36b5428d7fdf2705f
$(info Supported git hash (v3.3): $(ESPIDF_SUPHASH_V3))
$(info Supported git hash (v4.0-beta1) (experimental): $(ESPIDF_SUPHASH_V4))

ここで表示されたESPIDF_SUPHASH_V4の値(上記では”310be…”)を以下のgit checkoutのパラメータで与えます。

$ git clone https://github.com/espressif/esp-idf.git
$ git checkout ESPIDF_SUPHASH_V4
$ git submodule update --init --recursive

ESP-IDFの準備はこれで完了です。

MicroPythonをビルドします。
先にmpyクロスコンパイラをビルドしておきます。

$ make -C mpy-cross

次にESP32用MicroPythonをビルドします。ここではDevKit-C用なのでボードはデフォルトの”GENERIC”を使用しています。

$ cd ports/esp32
$ make clean
$ make

ビルドが完了したら、DevKit-Cを接続してファームウェアを書き込みます。

$ make deploy

なお、ビルドにはPython3とpyparsingパッケージのバージョン2.4未満が必要です。
私の環境(Ubuntu 16.04)ではPython2系がデフォルトだったので、ビルドに先立ってvenvを設定しました。

$ python3 -m venv venv
$ source venv/bin/activate
$ pip install --upgrade pip
$ pip install pyserial 'pyparsing<2.4'

では試用してみます。

>>> help('modules')
__main__          flashbdev         select            upip_utarfile
_boot             framebuf          socket            urandom
_onewire          gc                ssl               ure
_thread           hashlib           struct            uselect
_webrepl          heapq             sys               usocket
apa106            inisetup          time              ussl
array             io                ubinascii         ustruct
binascii          json              ucollections      utime
bluetooth         machine           ucryptolib        utimeq
btree             math              uctypes           uwebsocket
builtins          micropython       uerrno            uzlib
cmath             neopixel          uhashlib          webrepl
collections       network           uhashlib          webrepl_setup
dht               ntptime           uheapq            websocket_helper
ds18x20           onewire           uio               zlib
errno             os                ujson
esp               random            uos
esp32             re                upip
Plus any modules on the filesystem
>>> 

"bluetooth"モジュールがありますね。(無ければビルドがどこかで失敗しています。)

モジュールに関するドキュメントは以下にあります。

ubluetooth — low-level Bluetooth — MicroPython 1.11 documentation

私はBLEについては以前koshianを使ってみたことがあるくらいで、あまり詳しくないのですが、今回は、MicroPythonのmicropython/examples/bluetoothディレクトリにサンプルが2つ入っていますので、これを試してみました。

事前に、このディレクトリにある

・ble_advertising.py
・ble_uart_peripheral.py
・ble_temperature.py
・ble_uart_repl.py

の4つのファイルをESP32に転送しておきます。

◆サンプル1:温度センサ

ESP32がBLE接続のセンサになり、スマホなどから値を読み取ります。
ただし、サンプルなので温度の値は実際に測定しているわけではなく、ランダムに変動します。

読み取り側のアプリとしては、Android用の無料アプリ「nRF Connect」を使ってみました。

nRF Connect for Mobile - Google Play のアプリ

ESP32側で'ble_temperature.py'を実行します。

>>> exec(open('ble_temperature.py').read())
I (18740) BTDM_INIT: BT controller compile version [a482cda]
I (38101) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (38201) phy: phy_version: 4102, 2fa7a43, Jul 15 2019, 13:06:06, 0, 0
GAP procedure initiated: stop advertising.
GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=7 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=800 adv_itvl_max=800

これでESP32側ではサーバが起動しています。
nRF Connectから、スキャンするとmpy-tempというBLEデバイスが見つかります。

CONNECTをタップして接続し、CLIENTタブを見ると「Environmental Sensing」というサービスが見つかるはずですので、さらにこれをタップします。

すると、「Temperature」という項目があり、タップすると温度の値が表示されます。
この値は1秒おきに更新されていきます。

◆サンプル2:UART

BLEで接続できるUARTポートを生成し、そのUARTポートにos.dupterm()でREPLを接続します。
対向で通信するアプリとしては、Adafruit製の「Bluefruit」を使った、とソースコードに書かれているので、そちらを使用しました。
検証はAndroid版で行ったとありますが、このアプリはiPhone版もあります。

Adafruit Bluefruit LE Connect - Google Play のアプリ

‎Adafruit Bluefruit LE Connect on the App Store

以下のスクリーンショットはiPhone版です。

まず、ESP32側で'ble_uart_repl.py'を実行します。
このモジュール内のstart()を実行すると、dupterm()を使ってBLE UARTにREPLが接続されます。

>>> import ble_uart_repl
>>> ble_uart_repl.start()
I (36580) BTDM_INIT: BT controller compile version [a482cda]
I (46938) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (47048) phy: phy_version: 4102, 2fa7a43, Jul 15 2019, 13:06:06, 0, 0
GAP procedure initiated: stop advertising.
GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=7 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=800 adv_itvl_max=800
>>> 

Bluefruitを起動し、スキャンすると「mpy-repl」というデバイスが見つかるので、タップします。

CONNECTし、UARTをタップします。

するとターミナルエミュレータの画面に変わりますが、ここでまず改行コードの設定をします。
デフォルトは\nですが、\r\nまたは\n\rに設定する必要があります。

これでスマホからBluetooth経由でREPLにアクセスできます。
下の画面は"help()"と入力したところです。

参考リンク:
micropython/ports/esp32 at common-ble-api-esp32-nimble · jimmo/micropython

Common BLE API by jimmo · Pull Request #5051 · micropython/micropython

esp32: BLE support using Nimble by jimmo · Pull Request #5171 · micropython/micropython

コメント