ESP32用のMicroPython
ESP32用のMicroPythonもBluetooth Low Energy(BLE)をサポートしています。
NimBLEというスタックを組み込んでいるようです。
Windows10 上の Ubuntu でビルドし、ESP32本体で動作確認を行うことができます。
Windows10でUbuntuをインストール
Ubuntuインストールの準備とインストール
Windows PowerShell を「管理者として実行する」で起動し、次のコマンドで Windows Subsystem for Linux オプション機能を有効にします。
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Windows10 の Microsoft Store で、Ubuntuを検索し、Ubuntuをインストールします。
今回、Ubuntu 20.04 LTS (GNU/Linux 4.4.0-18362-Microsoft x86_64)をインストールしました。
**参照:**https://aka.ms/wslinstall
Ubuntuの初期化
インストール後、Ubuntuを起動し、Linuxユーザーアカウントの設定を行います。
設定後、自動的にログインするので、ディストリビューションのパッケージの更新とアップグレードを行います。
sudo apt update && sudo apt upgrade
参照: https://docs.microsoft.com/ja-jp/windows/wsl/initialize-distro
必要なツールのインストール
sudo apt update
sudo apt install make wget gcc
wget https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py
pip install virtualenv
ディレクトリ構成
Windowsからソースコードにアクセスしやすいようにする為、Cドライブの直下に、esp32
ディレクトリを作成し、最終的に次のようなディレクトリ構成とします。
/mnt/c/esp32
+ /micropython
+ /esp-idf
セットアップとインストール
ディレクトリの作成
Cドライブの直下にesp32
ディレクトリを作成します。
cd /mnt/c
mkdir esp32
MicroPythonの取得(gitクローンとブランチの切り替え)
/mnt/c/esp32/micropython
ディレクトリにMicroPythonのソースコードを取得します。
cd /mnt/c/esp32
git clone https://github.com/jp-96/micropython-esp32nimble.git micropython
bleperipheral
というブランチに切り替えます(checkout
)。
cd /mnt/c/esp32/micropython
git branch -a
git checkout origin/bleperipheral
git checkout bleperipheral
git branch -a
ESP-IDFの取得(gitクローンとリビジョン)
/mnt/c/esp32/esp-idf
ディレクトリにESP-IDFのソースコードを取得(gitクローン)します。
ただし、MicroPythonは特定のESP-IDFのリビジョンに依存しますので、そのリビジョンを取得します(checkout
)。
make ESPIDF=
を実行すると依存するリビジョンが表示されますので、そのリビジョンをgit checkout
のパラメーターに与えます。
※ 2020/06/18 現在、Supported git hash (v4.0) (experimental): 4c81978a3e2220674a432a588292a4c860eef27b
と表示されました。
cd /mnt/c/esp32/micropython/ports/esp32
make ESPIDF=
cd /mnt/c/esp32
git clone https://github.com/espressif/esp-idf.git esp-idf
cd /mnt/c/esp32/esp-idf
git checkout 4c81978a3e2220674a432a588292a4c860eef27b
git submodule update --init --recursive
esp-idfツールのインストール
esp-idf
に付属するinstall.sh
を実行し、クロスコンパイラ(Toolchain
)等のツールをインストールします。
ただし、今回のUbuntu 20.04 LTS
には、python3
しかインストールされていないので、install.sh
を実行するとエラーが発生して実行に失敗します(/usr/bin/env: ‘python’: No such file or directory
)。
そこで、まずは、python
というpython3
へのシンポリックリンクを作成します。
sudo ln -s /usr/bin/python3 /usr/bin/python
その後、インストールを実行します。
cd /mnt/c/esp32/esp-idf
./install.sh
クロスコンパイラ(Toolchain) とPython仮想環境が ~/.espressif
ディレクトリに展開されます。
ビルド
Python仮想環境の有効化
次のコマンドで、インストールされたPython仮想環境を有効化します。
source ~/.espressif/python_env/idf4.0_py3.8_env/bin/activate
ビルド環境の設定
次のコマンドで、ビルド環境を設定します。
. /mnt/c/esp32/esp-idf/export.sh
組み込みスクリプトのプリコンパイル
MicroPythonの組み込みスクリプトの一部をバイトコードにプリコンパイルします。
cd /mnt/c/esp32/micropython/mpy-cross
make mpy-cross
berkeley-db-1.xxモジュールのアップデート
berkeley-db-1.xx
モジュールをアックデートします。
cd /mnt/c/esp32/micropython
git submodule init lib/berkeley-db-1.xx
git submodule update
ubleperipheralモジュールのアップデート
ubleperipheral
モジュールをアックデートします。
cd /mnt/c/esp32/micropython
git submodule init extmod/ubleperipheral
git submodule update
ESP32用のMicroPythonのビルド
ESP32用のMicroPythonのファームウェアをビルドします。
ファームウェアのイメージファイルは、build
ディレクトリに作成されます。
(bootloader.bin
, partitions.bin
, application.bin
の3つ)
cd /mnt/c/esp32/micropython/ports/esp32
make submodules
make PYTHON2=python FROZEN_MANIFEST=boards/manifest_bleperipheral.py
※ python2が見つからないというエラーが出てしまうので、make
にPYTHON2=python
パラメーターを渡しています。
ファームウェアの書き込み
USBシリアルポートの設定
ESP32とは、USBシリアルポートで通信しますが、例えば、 /dev/ttyS1 (COM1)にアクセスしようとするとエラーが発生することがあります。
次のように、ユーザーを dialout グループに追加しておく必要があります。
sudo usermod -a -G dialout $USER
ESP32の接続
ESP32 をUSBケーブルでパソコンに接続し、デバイスマネージャで、ポートを確認します。
例えば、Windows10で、COM14
として認識されている場合、Ubuntuでは、/dev/ttyS14
として認識されます。
消去と書込
ファームウェアをESP32マイコンに書き込む前に、make erase
でフラッシュメモリの消去を行います。その後、make deploy
で書き込みます。
デフォルトでは、通信速度(BAUD
)が460800
に、通信ポート(PORT
)が/dev/ttyUSB0
に、それぞれ設定されていますので、パラメーターで明示的に指定しています。PORT
は、デバイスマネージャーで確認したポートに合わせてください。
cd /mnt/c/esp32/micropython/ports/esp32
make erase BAUD=115200 PORT=/dev/ttyS14
cd /mnt/c/esp32/micropython/ports/esp32
make deploy BAUD=115200 PORT=/dev/ttyS14
サンプルプログラムの動作確認
プログラム書き込みツールのインストール
プログラム書き込みツールとして、ampy
をインストールします。
source ~/.espressif/python_env/idf4.0_py3.8_env/bin/activate
pip install adafruit-ampy
サンプルプログラムの転送
/mnt/c/esp32/micropython/extmod/ubleperipheral/examples
ディレクトリにBLEのサンプルプログラムがありますので、全てのファイルをESP32へ転送します(put
)。
cd /mnt/c/esp32/micropython/extmod/ubleperipheral/examples
ampy --port=/dev/ttyS14 put ble_temperature.py
ampy --port=/dev/ttyS14 put ble_uart_peripheral.py
ampy --port=/dev/ttyS14 put ble_uart_repl.py
ampy --port=/dev/ttyS14 put main.py
サンプルプログラムの動作確認
ESP32を再起動するとサンプルプログラムがimport
されますので、ESP32とシリアル通信して、temp()
関数を実行します。BLEが接続可能状態となりますので、スマホアプリのnRF Connect
等を使って温度計の動作確認できます。
スニペットの説明
ble_temperature.py
で、GATT仕様書と読み比べてみましょう。
環境センシングプロファイル
まずは、ble_temperature.py
で使用している、環境センシングプロファイル(ESP-Environmental Sensing Profile)の概要図を確認します。
参照: ESP, p.8, 2.2 Role/Service Relationships
環境センシングは、3つのサービスからなっていて、1つ目の環境センシングサービスは、実装が必須で、残りの2つは、任意です。
BLEPeripheral.build
の第1引数のタプルで、これらのサービスを与えます。サンプルプログラムでは、_ENV_SENSE_SERVICE
として定義された環境センシングサービスのみのタプルを指定しています。
class BLETemperature:
def __init__(self, connected, disconnected, multi_connections):
:
:
((self._handleTempChar,),) = self._bleperipheral.build(
(_ENV_SENSE_SERVICE, ),
adv_services=[_ENV_SENSE_UUID],
adv_name="upy-temp",
adv_appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER
)
:
残りの引数は、アドバタイジングで示される情報です。
引数 | 内容 |
---|---|
adv_services | BLEサービスのUUID配列 |
adv_name | 表示するローカル名 |
adv_appearance | アイコンなどで示される番号 |
環境センシングサービス
環境センシングプロファイルで示された環境センシングサービスの詳細は、環境センシングサービス仕様書で確認できます。
しかし、仕様書には、実装に必要なUUIDの値は記載されていませんので、GATTサービスのページを参照します。ここで、環境センシングのUUID(割当番号)が、0x181A
であることがわかります。
名称 | Uniform Type Identifier | 割当番号 | 仕様コード |
---|---|---|---|
Environmental Sensing | org.bluetooth.service.environmental_sensing | 0x181A | GSS |
# org.bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
温度特性
さらに、環境センシング (Environmental Sensing)のリンク先を開くと、詳細な仕様を確認できます。
環境センシングには、たくさんの特性(characteristic)が定義されていますが、その中の@type:org.bluetooth.characteristic.temperature
が、温度特性です。
ここで、プロパティを確認しておきます。ble_temperature.py
では、read
とnotify
を実装しています。
※ 'read'や'write'というのは、Collectorから見た操作を示しています。
プロパティ | 要否 | 適用 |
---|---|---|
read | Mandatory | x |
write | Excluded | |
writewithoutresponse | Excluded | |
signedwrite | Excluded | |
reliablewrite | Excluded | |
notify | Optional | x |
indicate | Excluded | |
writableauxiliaries | Optional | |
broadcast | Excluded | |
extendedproperties | Optional |
この温度特性の詳細な情報は、GATTの特徴のページを参照します。特性のUUID(割当番号)が0x2A6e
であることがわかります。
名称 | Uniform Type Identifier | 割当番号 | 仕様コード |
---|---|---|---|
Temperature | org.bluetooth.characteristic.temperature | 0x2A6E | GSS |
これらの仕様をもとに、特性が定義されています。
_TEMP_CHAR = (
bluetooth.UUID(0x2A6E),
bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
)
さらに、続けて、環境センシングサービスが、定義されています。
_ENV_SENSE_SERVICE = (
_ENV_SENSE_UUID,
(_TEMP_CHAR,),
)
特性のハンドル
プロファイル仕様書とサービス仕様書で、環境センシングサービスをタプルの階層構造で定義しましたが、センサー(peripheral)から、各特性に対して操作をする際に、ハンドルを指定して操作します。
その特性のハンドルは、BLEPeripheral.build()
の戻り値で取得します。これも、サービスで定義したタプルの階層構造(順序)でハンドルが戻りますので、そのハンドルを保持しています(self._handleTempChar
)。
class BLETemperature:
def __init__(self, connected, disconnected, multi_connections):
:
:
((self._handleTempChar,),) = self._bleperipheral.build(
(_ENV_SENSE_SERVICE, ),
adv_services=[_ENV_SENSE_UUID],
adv_name="upy-temp",
adv_appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER
)
:
温度(値)の送信
class BLETemperature:
:
:
def set_temperature(self, temp_deg_c, notify=False):
# Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
# Write the local value, ready for a central to read.
self._bleperipheral.write(self._handleTempChar, struct.pack("<h", int(temp_deg_c * 100)), notify)
Temperatureのリンク先を開くと、温度特性の詳細な仕様を確認できます。
項目 | 説明 |
---|---|
informativetext | Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius |
requirement | Mandatory |
format | sint16 |
unit | org.bluetooth.unit.thermodynamic_temperature.degree_celsius |
decimalexponent | -2 |
温度特性ハンドルに対して、16ビット符号付き整数に変換して送信しています(1は、摂氏0.01度)。
最後に
ESP32用のMicroPythonで、サンプルプログラムのBLE温度計の動作確認を行いました。
GATT仕様書が読めるようになれば、サービスと特性をタプル階層構造で定義するだけで、BLE peripheralを簡単に実装できます。