LoginSignup
1
1

More than 3 years have passed since last update.

BLEセンサー(Peripheral)を作成して、GATT仕様書と読み比べる - ESP32 MicroPython

Posted at

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が見つからないというエラーが出てしまうので、makePYTHON2=pythonパラメーターを渡しています。

ファームウェアの書き込み

USBシリアルポートの設定

ESP32とは、USBシリアルポートで通信しますが、例えば、 /dev/ttyS1 (COM1)にアクセスしようとするとエラーが発生することがあります。
次のように、ユーザーを dialout グループに追加しておく必要があります。

sudo usermod -a -G dialout $USER

ESP32の接続

ESP32 をUSBケーブルでパソコンに接続し、デバイスマネージャで、ポートを確認します。
例えば、Windows10で、COM14 として認識されている場合、Ubuntuでは、/dev/ttyS14 として認識されます。
image.png

消去と書込

ファームウェアを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

image.png

環境センシングは、3つのサービスからなっていて、1つ目の環境センシングサービスは、実装が必須で、残りの2つは、任意です。
BLEPeripheral.buildの第1引数のタプルで、これらのサービスを与えます。サンプルプログラムでは、_ENV_SENSE_SERVICEとして定義された環境センシングサービスのみのタプルを指定しています。

ble_temperature.py
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
ble_temperature.py
# org.bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)

温度特性

さらに、環境センシング (Environmental Sensing)のリンク先を開くと、詳細な仕様を確認できます。
環境センシングには、たくさんの特性(characteristic)が定義されていますが、その中の@type:org.bluetooth.characteristic.temperatureが、温度特性です。

ここで、プロパティを確認しておきます。ble_temperature.pyでは、readnotifyを実装しています。
※ '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

これらの仕様をもとに、特性が定義されています。

ble_temperature.py
_TEMP_CHAR = (
    bluetooth.UUID(0x2A6E),
    bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
)

さらに、続けて、環境センシングサービスが、定義されています。

ble_temperature.py
_ENV_SENSE_SERVICE = (
    _ENV_SENSE_UUID,
    (_TEMP_CHAR,),
)

特性のハンドル

プロファイル仕様書とサービス仕様書で、環境センシングサービスをタプルの階層構造で定義しましたが、センサー(peripheral)から、各特性に対して操作をする際に、ハンドルを指定して操作します。
その特性のハンドルは、BLEPeripheral.build()の戻り値で取得します。これも、サービスで定義したタプルの階層構造(順序)でハンドルが戻りますので、そのハンドルを保持しています(self._handleTempChar)。

ble_temperature.py
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
        )
            :

温度(値)の送信

ble_temperature.py
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を簡単に実装できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1