ESP-IDF:リベンジ:examplesでBLEの感じを掴む(ble_mesh_consoleble_mesh_node)#2
BLE MESHの入口としてexampleを試してみたところ、プロビショニング出来ずエラーになってしまう穴に嵌りまして。
早速素人が手を出すな!と言われたかの様な仕打ち。
とりあえず例題も動かせない様では入り口にも立てないって事で、色々と調べて回ったのですが
基本的にBLE MESHの実装形はリファレンスデザインみたいなものがあまり定まっておらず、いくつかのスタックが並立している様な状況の様ですね。
これらすべてを一つ一つ勉強するには時間が足りませんので、とりあえずは目前の問題に取り掛かりたいと思います。
さて、プロビショナーもESP32に書き込めばきっとすんなりexampleも通るのでしょうけれど、、
プロビショナの動作を習得するのはノードの動きを知ってからかなと思いますので、やはり今回も既存のアプリに頼ります。
そんなわけで検索して回って何が判ったかといいますと、、
ESPRESSIF – ESP-IDF – ISSUES – ESP32 BLE mesh example fails to provision (IDFGH-3365) #5341
なんと6日前の投稿。(実際にテストした日より)
まさにワタクシと同じ症状が。
投稿を読むと、nRF-Meshアプリで同じ様な症状が起こっている事が報告されています。
やはりプロビショナーとエレメントの間で齟齬があった様です。
読み進めてみると、どうやらGATTのMTUサイズが足りなくてプロビショナーから弾かれてしまっている様子。
ESP-IDFライブラリのonoff_serverデフォルトではGATTベアラ用のMTUサイズが23バイトとなっているが、恐らくnRF-Meshアプリ的にはBluetooth4.2以降を想定している為か、もっと大きなMTUでプロビショニングを行うのではないかと。
そして少々乱暴な方法ですが、ESP-IDFライブラリのGATTベアラ用のMTUデフォルトサイズを69にしたらちゃんと動いたよとの書き込みが。
こういうのはちゃんとキャリブレーションするコードを書くべきなんでしょうけれど、、、
テストするだけでキャリブレーションを書くのも面倒ですので、本当かどうか試しにワタクシも同じ方法で試みてみます。
コメント投稿者はパッチまで用意してくれておりますが、とりあえず面倒ですので手動で、、
components/bt/esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c
void bt_mesh_gatt_init(void)
{
// BTA_GATT_SetLocalMTU(GATT_DEF_BLE_MTU_SIZE);
BTA_GATT_SetLocalMTU(69); // MTUサイズを69に変更
#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \
CONFIG_BLE_MESH_GATT_PROXY_SERVER
:
:
パッチの通りの修正を行いました。
尚、直接ライブラリを編集してしまっているので、事後には元に戻しておいた方が良いです。
しかし、なんかちょっと混沌としてますね
components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h には、
#define BLE_MESH_GATT_DEF_MTU_SIZE 23
とかありますし、
components/bt/host/bluedroid/api/include/api/esp_gatt_common_api.h には、
// Maximum Transmission Unit used in GATT
#define ESP_GATT_DEF_BLE_MTU_SIZE 23 /* relate to GATT_DEF_BLE_MTU_SIZE in stack/gatt_api.h */
とかありますし
もしかしたら個々に設定している深い意味があるのかもしれませんが、、、
私が見た限りでは、同じESP-IDFでも使うライブラリによって値が違うなんて事にもなりかねず、
もう少しちゃんと纏めた方が良いのではないかしらん(汁
とりあえずこれでビルドして動作を確認します。
ESP32に転送しまして、再び登場の「NORDIC SEMICONDUCTOR nRF-Mesh」を使います。
プログラムを転送したら、まずはESP32にシリアルでアクセスし、以下の通りコマンドを発行します。
This is an example of ESP-IDF console component.
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
esp32> bmreg
I (8224) ble_mesh_node_console: Node:Reg,OK
esp32> bmoob -o 0 -x 0
I (11244) ble_mesh_node_console: OOB:Load,OK
esp32> bminit -m 0x1000
I (14334) ble_mesh_node_console: Provisioning:Register,OK
esp32> bmnbearer -b 0x3 -e 1
I (17604) ble_mesh_node_console: Node:EnBearer,OK
esp32>
そしておもむろにnRF Meshアプリで検索し、PROVISIONをタッチ。
おぉ、プロビショニングが通ったンゴねぇ
確かスマホはPB-ADVには非対応だとか見た記憶があるので、nRF-Meshで行うプロビショニングもPB-GATTなのでしょう。
まだよくわかりませんが、前述のGATTのデフォルト値の変更は正しかった!?
先日のエラーの時、何処でエラーになったかというと
プロビショナー)Sending probisioning invite → OK
クライアント)Probisioning capabilities received ← OK
プロビショナー)Sending probisioning start → OK
プロビショナー)Sending probisioning public key → OK
クライアント)Probisioning public key received ← NG
クライアント側(ESP32側)で、public key が正しく受け取れなかった感じですね。
そして今回のOKケースでは、、、
Completeの窓が邪魔で良く見えないンゴ・・・
もう一回、、、タイミングよくスクショを・・・
うん、進んでる。
進んでるという事位しか判らないけどもね!
このプロビショナーとエレメントとのやり取りがすべて正しく行われなければいけない訳ですね。
、、、とても覚えられないので、作る時に掘り起こす事にします・・・
さて
ESP32のシリアルコンソールには以下の様にメッセージが表示されていました。
esp32>
I (22374) ble_mesh_node_console: Node:LinkOpen,OK,2
I (28104) ble_mesh_node_console: Node:LinkClose,OK,2
I (28104) ble_mesh_node_console: Provisioning:Success,2
ソースのこのメッセージを出している箇所を追ってやれば、プロビショニングの段取りも多分判るっぽい。
今はやりませんが・・・
さてOKを押すと、登録されたノードが表示されました。
Elementsが1、Modelsが2
エレメントは恐らくプロビショニングできたデバイスの数(ESP32)で、Modelsは2種類のモデルがあるノードですよって事なのかな。
ちょっとよく判らないので押してみます。
タイトルに、「Node Configuration」とあります。
BLE MESHは、プロビジョニングを行いネットワークに参加した状態になってからコンフィグを行うという事なのでしょう。
ざっくりと見た感じ、Element(ESP32等の個別デバイス)が持つモデルの個別設定と操作、ネットワークキー、アプリケーションキーの変更や、TTL、Proxy設定、それからノードのリセット等が行える様ですね。
これらの設定可能項目は、多分プロビショニングを行う時に、エレメントがプロビショナーに「ワタクシはこういう者ですょ」と伝えているんだと思うます。(未確認)
この辺りはプロビショナーを作る段になったらまた調べます。
さて、エレメントのESP32側では特に何も役割を設定しておらず、コンフィグだけ操作してもつまらないので、「Generic On Off Server」モデルにLチカでも仕込んでみます。
ざっくりソースを見るに恐らく「ble_mesh_generic_server_model_cb」でメッセージを受け取っているっぽいので、On/Offの指令を受けたらボードのLEDを操作する様にします。
NodeMCU-32S のオンボードLED(電源LEDではない2個目の青色LED)のGPIO番号は2だそうです。
これをHIGHにするとLEDが点灯するそうですので、、、
まずは app_main がある ble_mesh_console_main.c でGPIOを初期設定し
ble_mesh_console_main.c
// OnBoardLED
#include "driver/gpio.h"
#define GPIO_ONBOARD_LED 2 // NodeMCU-32S onboard led2
gpio.h をincludeしないとGPIOを操作できないので頭の方に追加しておきます。
app_mainの中でGPIOを初期化しておきます。
// Onboard LED init
gpio_config_t onboardled_gpio_conf;
// 割り込み処理を停止
onboardled_gpio_conf.intr_type = GPIO_PIN_INTR_DISABLE;
// OUTPUT MODE OUTOUT
onboardled_gpio_conf.mode = GPIO_MODE_OUTPUT;
// GPIOピンビットマスクを設定
onboardled_gpio_conf.pin_bit_mask = (1ULL<<GPIO_ONBOARD_LED);
// プルアップなし
onboardled_gpio_conf.pull_up_en = 0;
// プルダウンなし
onboardled_gpio_conf.pull_down_en = 0;
// 設定をセットする
gpio_config(&onboardled_gpio_conf);
// 一応LOWにセット
gpio_set_level(GPIO_ONBOARD_LED, 0);
次にnodeにイベントが来た時の処理を追加。
ファイルは ble_mesh_register_node_cmd.c を開いてください。
ble_mesh_register_node_cmd.c
まずは適当な位置でdriver/gpio.hをincludeしておいて
// OnBoardLED
#include "driver/gpio.h"
ble_mesh_generic_server_model_cbに処理を追加します。
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
// LEDの操作 ---------------------------------------------------- この辺に追加
if(param->value.set.onoff.onoff > 0) {
gpio_set_level(GPIO_NUM_2, 1); // GPIOピン指定はマクロで済ませてしまう
} else {
gpio_set_level(GPIO_NUM_2, 0);
}
// /LEDの操作 ---------------------------------------------------
ESP_LOGI(TAG, "GenOnOffServer:SetStatus,OK,%d", param->value.set.onoff.onoff);
ble_mesh_node_set_state(param->value.set.onoff.onoff);
ble_mesh_node_get_state(status);
esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(status), &status);
挿入するのは「ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET」をトリガにした位置です。
この辺り、非常に似たような名前の定数が並んでいて紛らわしいですので、詳しくはAPIリファレンスを確認してください。
ESPRESSIF – ESP-IDF Programming Guide – ESP-BLE-MESH
適当にこんな感じで動かしてみます。
コンパイルして転送して、、
プロビショニングして、nodeの初期設定をして、、
ちょっと手順が多くて萎えますが、、
ふむふむ、こんな感じで動かせるわけですね。
なんかBLEに関する用語が少し独特でして、、
リファレンスを読む時に用語がイメージとマッチしていないと、ほんと「何言ってるのかちょっとわかんないですね・・・」状態になるます。
脳内マッチングが捗りませんので、ちゃんと覚えてまとめておいた方が良いかもしれません。
そんなわけでだいぶ躓きましたが、全体の流れと構造、見るべきポイントは何となく判りましたので、ちょっと構想を練ってみようと思います。
ESP32を2個以上並べて互いに交信させてみたり、3デバイス以上でちゃんとMESH出来ているか、中継できているか等を確認したいンゴねぇ
今回のサンプルはコンソールが付いてたりして少し冗長な構成でしたので、次はプログラム全体が見渡せるもっとシンプルなものにしないと読めませぬね
ESP-IDFもつい数日前に導入したばかりですし、流れを追うのも大変っスね;
いきなり凄く簡単にコードが書けるarduinoは、やっぱり凄いんだなと実感。
とりあえず疲れたので今日はこの辺で。
ディスカッション
コメント一覧
まだ、コメントがありません