03.BasicのBLEスケッチ例(1)

03.BasicのBLEスケッチ例(1)

BLEのスケッチ例

Arduino IDE > ファイル > スケッチ例 > ESP32 BLE Arduino > にスケッチが8ファイルあります。
  1. BLE_scan.ino
  2. BLE_server.ino
  3. BLE_write.ino
  4. BLE_notify.ino
以下は次回予定です。
  1. BLE_server_multiconnect.ino
  2. BLE_uart.ino
  3. BLE_iBeacon.ino
  4. BLE_client.ino
動作確認は、M5Stack BasicとAndroid 10のスマホです。
M5Stack Basicの無線は、Wi-Fi, Classic Bluetooth と Bluetooth Low Energy(BLE) の dual mode Bluetoothがあります。Classic Bluetooth は Bluetooth Basic Rate(BR) と Enhanced Data Rate(EDR)があります。ESP32は、Bluetooth v4.2のBR/EDRおよびBLEに準拠しています。
スケッチ例では表示はシリアルモニタのみなので、ほぼ2行修正すれば動作します。
1行目に
#include <M5Stack.h>
を追加し、
void setup() {
の下の
Serial.begin(115200);
を消し、
M5.begin();
へ変更します。

BLE_scan.ino

M5がBLEデバイスをスキャンします。
1.スケッチを修正してM5Stack Basicに書込みます。
2.シリアルモニタに見つけたデバイス名, アドレス, メーカーデータが表示されます。
例) 一部は、・・・で省略しました。

デバイス:Name: , Address: 4d:18:・・・, manufacturer data: 0600・・・ (ノートPCです)
デバイス:Name: , Address: 14:b7:・・・, manufacturer data: 0600・・・ (ディスクトップPC)
デバイス:Name: TNT_BW , Address: c4:49:・・・, serviceUUID: 273e・・・・ (不明)
デバイス:Name: , Address: 10:4e:・・・, manufacturer data: 8700・・・(腕時計)
デバイス:Name: , Address: 7c:ec:・・・, manufacturer data: dc00・・・ (歯ブラシ)
見つかったデバイス: 5
スキャン完了

* このスケッチは、フラッシュメモリの78%を使います。

スケッチ


// BLEをスキャンしName, Address, manufacturer dataをシリアルモニタに表示
#include <M5Stack.h>            // M5Stack Basic
#include <BLEDevice.h>          // 
#include <BLEUtils.h>           // 一般的なBLEユーティリティのセット
#include <BLEScan.h>            // BLEスキャンを実行および管理
#include <BLEAdvertisedDevice.h>//スキャンによって検出されたBLEアドバタイズされたデバイスの表現
int scanTime = 5;               // スキャン時間(秒)
BLEScan* pBLEScan;              // 定義

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("デバイス:%s \n", advertisedDevice.toString().c_str());
  }
};
void setup() {
  M5.begin();  // シリアルクリア,115200bps,LCD初期化,電源管理の初期化
  Serial.println("スキャン中...");    // シリアルモニタ表示
  BLEDevice::init("");              // BLE環境を初期化(デバイス名)
  pBLEScan = BLEDevice::getScan();  // スキャンに使用するScanオブジェクトを取得
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());//コールバックが呼び出されるように設定
  pBLEScan->setActiveScan(true);//多くの電力を使用するが結果を速く取得(true=アクティブスキャン,それ以外=パッシブスキャン)
  pBLEScan->setInterval(100);       // スキャン間隔(mS)
  pBLEScan->setWindow(99);          //setInterval値以下 アクティブにスキャンするようにウィンドウを設定(mS)
}

void loop() {
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  //スキャンを開始し、スキャンが完了するまでブロック(スキャン時間(秒),継続)
  Serial.print("見つかったデバイス: ");       // シリアルモニタ表示
  Serial.println(foundDevices.getCount()); //最後のスキャンで見つかったデバイスの数を返します。
  Serial.println("スキャン完了");            // シリアルモニタ表示
  pBLEScan->clearResults();                // BLEScanバッファから結果を削除しメモリを解放
  delay(2000);                             // 2秒待つ
}

BLE_server.ino

スケッチ内の文字列をスマホに表示します。
1.スケッチを修正してM5に書込みます。
2.スマホのBLE Scannerアプリで"M5_Basic_server"を探し、CONNECT > CUSTOM SERVICE > CUSTOM CHARACTERISTICのR(read) をタップします。
3.Value:の項目に"Hello World says Neil"と表示されます。
* このスケッチは、フラッシュメモリの78%を使います。

スケッチ


// スケッチ内に記入した文字列を要求があればスマホに表示
#include <M5Stack.h>    // M5Stack Basic
#include <BLEDevice.h>  // 
#include <BLEUtils.h>   // 一般的なBLEユーティリティのセット
#include <BLEServer.h>  // 
#define SERVICE_UUID        "24dd2658-c789-11eb-b8bc-0242ac130003"  // PCのフォルダ名に相当
#define CHARACTERISTIC_UUID "24dd2716-c789-11eb-b8bc-0242ac130003"  // PCのファイル名に相当

void setup() {
  M5.begin();  // シリアルクリア,115200bps,LCD初期化,電源管理の初期化
  Serial.println("BLE開始");                       // シリアルモニタに表示
  BLEDevice::init("M5_Basic_server");             // BLE環境を初期化(デバイス名)
  BLEServer *pServer = BLEDevice::createServer(); // サーバーの新しいインスタンスを作成
  BLEService *pService = pServer->createService(SERVICE_UUID);  // BLEサービスを作成(新しいサービスのUUID)
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ |
    BLECharacteristic::PROPERTY_WRITE
  );//このサービスに関連付けられた新BLE特性を作成(特性UUID,特性プロパティ)
  pCharacteristic->setValue("Hello World says Neil"); // スマホに表示 漢字はだめ 文字列データから特性値を設定
  pService->start();                                  // サービスを開始
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();  // 接続待ち開始
  pAdvertising->addServiceUUID(SERVICE_UUID);  // サービスの公開リストにサービスUUIDを追加
  pAdvertising->setScanResponse(true);         // 
  pAdvertising->setMinPreferred(0x06);         // iPhone接続の問題に役立つ機能
  pAdvertising->setMinPreferred(0x12);         // 
  BLEDevice::startAdvertising();               // 
  Serial.println("スマホに文字を送ります。(R)で読めます");  // シリアルモニタに表示
}
void loop() {
  delay(2000);  // 2秒待つ
}

BLE_write.ino

スマホに入力した文字をM5へ送ります。
1.スケッチを修正してM5に書込みます。
2.スマホのBLE Scannerアプリで"M5_Basic_write"を探し、CONNECT > CUSTOM SERVICE > CUSTOM CHARACTERISTICのW(write) をタップします。
3.Write Value が Byte Arrayの場合、18 > ok と入力すると、スマホにHex:0x18と表示されますが、シリアルモニタは文字化けしています。
4.Write Value が Textの場合、入力するとValue:の後ろに表示され、シリアルモニタにも表示されます。漢字を入力するとスマホには表示されませんが、シリアルモニタに表示されます。
* このスケッチは、フラッシュメモリの78%を使います。

スケッチ


// スマホに入力するとシリアルモニタに表示されます
#include <M5Stack.h>    // M5Stack Basic
#include <BLEDevice.h>  // 
#include <BLEUtils.h>   // 一般的なBLEユーティリティのセット
#include <BLEServer.h>  // 
#define SERVICE_UUID        "24dd2da6-c789-11eb-b8bc-0242ac130003" // PCのフォルダ名に相当
#define CHARACTERISTIC_UUID "24dd2e5a-c789-11eb-b8bc-0242ac130003" // PCのファイル名に相当 

class MyCallbacks: public BLECharacteristicCallbacks { //イベントを通知するためにBLE特性に関連付けることができるコールバック
  void onWrite(BLECharacteristic *pCharacteristic) { //
    std::string value = pCharacteristic->getValue(); // 特性の現在の値を取得
    if (value.length() > 0) {                  // 入力されたら
      Serial.print("M5入力文字:");              // シリアルモニタに表示
      for (int i = 0; i < value.length(); i++) // 文字列の長さ分ループ
        Serial.print(value[i]);                // シリアルモニタに1文字表示
      Serial.println();                        // 改行 for文の外
    }
  }
};
void setup() {
  M5.begin();                               // シリアルクリア,115200bps,LCD初期化,電源管理の初期化
  BLEDevice::init("M5_Basic_write");                          // BLE環境初期化(デバイス名)
  BLEServer *pServer = BLEDevice::createServer();             // サーバーの新しいインスタンスを作成
  BLEService *pService = pServer->createService(SERVICE_UUID);// BLEサービスを作成(新しいサービスのUUID)
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ |
    BLECharacteristic::PROPERTY_WRITE
  );//このサービスに関連付けられた新BLE特性を作成(特性UUID,特性プロパティ)
  pCharacteristic->setCallbacks(new MyCallbacks());           //この特性のコールバックハンドラーを設定
  pCharacteristic->setValue("ABCDEFG");  // スマホに表示 漢字はだめ 文字列データから特性値を設定
  pService->start();                                          // サービスを開始
  BLEAdvertising *pAdvertising = pServer->getAdvertising();//サーバーの存在をアドバタイズするために使用できるアドバタイズオブジェクトを取得
  pAdvertising->start();                                      // 広告を開始
}

void loop() {
  delay(2000);                                                // 2秒待つ
}

BLE_notify.ino

M5で変化していく数値をスマホに送ります。
NotifyはM5からスマホに変更を通知するための機能で、以下の流れで利用できます。
1.スマホは、M5に対して「監視したい」と設定しておきます。
2.M5は値が変わったら(変わってなくても)スマホにNotifyを送れます。
3.スマホはそれを受取ってM5の新情報を取得できます。
ここで、M5はペリフェラル、スマホはセントラルです。

1.スケッチを修正してM5に書込みます。
2.スマホのBLE Scannerアプリで"M5_Basic_notify"を探し、CONNECT > CUSTOM SERVICE > CUSTOM CHARACTERISTICのR(Read)をタップします。
3.M5から送られてきたデータを見ることができます。スケッチでは1ずつカウントupした値を送信しているので、Rを再度タップするとHex値が増えていきます。
4.また、Nをタップすると自動で読込みます。
* このスケッチは、フラッシュメモリの78%を使います。

スケッチ


// M5で変化していく数値をスマホに送る
// 接続を受信すると定期的に通知を送信するBLEサーバーを作成
// サーバーに関連付けられた接続ハンドラーは、数秒ごとに通知を実行するバックグラウンドタスクを開始
// Video: https://www.youtube.com/watch?v=oCMOYS71NIU
#include <M5Stack.h>   // M5Stack Basic
#include <BLEDevice.h> // 
#include <BLEServer.h> // 
#include <BLEUtils.h>  // 一般的なBLEユーティリティのセット
#include <BLE2902.h>   // クライアント特性設定の記述子
BLEServer* pServer = NULL;                 // 定義
BLECharacteristic* pCharacteristic = NULL; // 定義
bool deviceConnected = false;              // 接続状態変数
bool oldDeviceConnected = false;           // 古い接続状態変数
int value = 0;                             // 送信数値 1加算していく
#define SERVICE_UUID        "24dd24d2-c789-11eb-b8bc-0242ac130003" // PCのフォルダ名に相当
#define CHARACTERISTIC_UUID "24dd259a-c789-11eb-b8bc-0242ac130003" // PCのフォルダ名に相当

class MyServerCallbacks: public BLEServerCallbacks { // BLEサーバーの操作に関連するコールバック
  void onConnect(BLEServer* pServer) {             // 新しいクライアント接続を処理
    deviceConnected = true;                        // 接続状態変数
  };
  void onDisconnect(BLEServer* pServer) {          // 既存のクライアントの切断を処理
    deviceConnected = false;                       // 接続状態変数
  }
};
void setup() {
  M5.begin();               // シリアルクリア,115200bps,LCD初期化,電源管理の初期化
  BLEDevice::init("M5_Basic_notify");             // BLE環境を初期化(デバイス名)
  pServer = BLEDevice::createServer();            // step1 BLEサーバーを作成
  pServer->setCallbacks(new MyServerCallbacks()); //この特性のコールバックハンドラーを設定
  BLEService *pService = pServer->createService(SERVICE_UUID);//step2 BLEサービスの作成(新サービスのUUID)
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ   |
    BLECharacteristic::PROPERTY_WRITE  |
    BLECharacteristic::PROPERTY_NOTIFY |
    BLECharacteristic::PROPERTY_INDICATE
  ); // step3 サービスでBLE特性を作成(特性UUID,特性プロパティ)
  pCharacteristic->addDescriptor(new BLE2902()); // step4 特性にBLEディスクリプタを作成
  pService->start();                             // step5 サービス開始
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); // step6 接続待ち開始
  pAdvertising->addServiceUUID(SERVICE_UUID);    // サービスの公開リストにサービスUUIDを追加
  pAdvertising->setScanResponse(false);          //
  pAdvertising->setMinPreferred(0x0);    // このパラメータをアドバタイズしないように0x00に設定
  BLEDevice::startAdvertising();                 //
  Serial.println("通知のためにスマホの接続を待機");    // シリアルモニタに表示
}
void loop() {
  if (deviceConnected) {                            // 接続されていれば
    pCharacteristic->setValue((uint8_t*)&value, 4); // 特性値を設定(設定データ,データ長(byte))
    pCharacteristic->notify();                      // 通知を送信(最初の20byteまで)
    value++;                                        // 1加算 変更値を通知
    delay(500);                 // 0.5S待つ 3mS以上 送信パケットが多すぎるとBluetoothスタックが込合う
  }
  if (!deviceConnected && oldDeviceConnected) { // 接続→切断の時
    delay(500);  // 0.5秒待つ Bluetoothスタックに準備を整える機会を与える
    pServer->startAdvertising();                // 広告を再開
    Serial.println("広告を開始");                 // シリアルモニタに表示
    oldDeviceConnected = deviceConnected;       // 接続状態変数を古いのにする
  }
  if (deviceConnected && !oldDeviceConnected) { // 切断→接続の時
    oldDeviceConnected = deviceConnected; // 接続状態変数を古いのにする 接続時にここで処理をする
  }
}

資料

UUIDの生成

サービスのUUIDとキャラクタリスティックのUUIDなどを生成します。
https://www.uuidgenerator.net/
のVer1で上記全UUIDを違う番号として14個とります。
例)
4303a7b0-c1bc-11eb-8529-0242ac130003
4303a9ea-c1bc-11eb-8529-0242ac130003
4303aac6-c1bc-11eb-8529-0242ac130003等

BluetoothのVer

Ver / 年 / 内容
4.2 / 2014 / LEの通信速度x2.5 (ESP32の仕様)
5.0 / 2016 / 通信速度x2, 通信範囲x4, 通信容量x8(4.0に対して)、メッシュネットワーク対応
5.1 / 2019 / 方向探知追加
5.2 / 2020 / LE Audio追加

BluetoothのClass

ESP32は、Class1, 2, および3の送信電力に対応しています。
BR/EDR
Class / 出力 / 到達距離max
1 / 0.1W / 100m
2 / 2.5mW / 10m
3 / 1mW/ 1m

BLE
Class / 出力
1 / 0.1W
1.5 / 10mW
2 / 2.5mW
3 / 1mW

ESP32 Datasheet V3.1のBluetooth

https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
(Google翻訳です)
3.6 Bluetooth
ESP32は、BluetoothリンクコントローラーとBluetoothベースバンドを統合し、ベースバンドプロトコルと、変調/復調、パケット処理、ビットストリーム処理、周波数ホッピングなどの他の低レベルリンクルーチンを実行します。

3.6.1 Bluetoothラジオとベースバンド
ESP32 Bluetooth無線とベースバンドは、次の機能をサポートしています。
• クラス1、クラス2、およびクラス3の送信出力電力、および最大24dBの動的制御範囲
• π/4DQPSKおよび8DPSK変調
• 97dBを超えるダイナミックレンジを備えたNZIFレシーバー感度の高性能
• 外部PAなしのクラス1操作
• 内部SRAMにより、フルスピードのデータ転送、音声とデータの混合、およびフルピコネット操作が可能になります
• 前方誤り訂正、ヘッダーエラー制御、アクセスコード相関、CRC、復調、暗号化ビットストリーム生成、ホワイトニング、および送信パルス整形のロジック
• ACL, SCO, eSCO and AFH
• PCMインターフェイスのA-law、µ-law、およびCVSDデジタルオーディオCODEC
• SBCオーディオコーデック
• 低電力アプリケーションの電力管理
• 128ビットAESを使用したSMP

3.6.2 Bluetooth Interface
• 最大4MbpsのUARTHCIインターフェースを提供します。
• SDIO / SPIHCIインターフェースを提供します。
• PCM /I²Sオーディオインターフェースを提供します。

3.6.3 Bluetoothスタック
ESP32のBluetoothスタックは、Bluetooth v4.2 BR/EDRおよびBLE仕様に準拠しています。

3.6.4 Bluetooth Link Controller
リンクコントローラは、スタンバイ、接続、スニフの3つの主要な状態で動作します。 複数の接続を可能にし、照会、ページ、安全なシンプルペアリングなどの他の操作により、PiconetとScatternetが有効になります。以下の機能があります。

• Classic Bluetooth
– デバイス検出(照会、および照会スキャン)
– 接続の確立(ページ、およびページスキャン)
– マルチ接続
– 非同期データの送受信
– 同期リンク(SCO/eSCO)
– マスター/スレーブスイッチ
– 適応周波数ホッピングとチャネル評価
– ブロードキャスト暗号化
– 認証と暗号化
– 安全なシンプルペアリング
– マルチポイントおよびスキャッターネット管理
– スニフモード
– コネクションレス型スレーブブロードキャスト(送信機と受信機)
– 強化された電力制御
– Ping

• Bluetooth Low Energy
– 広告
– スキャニング
– 同時広告とスキャン
– 複数の接続
– 非同期データの送受信
– 適応周波数ホッピングとチャネル評価
– 接続パラメータの更新
– データ長の拡張
– リンク層暗号化
– LE Ping