M5StickCでBLEデバイスを検索する

BLEを使ってみようとしましたが、まずはデバイスのUUIDを調べないといけないので、調べるツールを作ってみました。

※現時点の情報ですので、最新情報はM5StickC非公式日本語リファレンスを確認してください。

BLEとは?

Bluetooth 4.0で規定されているBluetooth Low Energyです。Bluetooth LEとも表現されることがあるみたいです。

3.0まではClassicとかSimpleとかでよばれていることが多いみたいです。

BLEデバイスの構造

デバイスアドレス

6バイトで前半3バイトが製造会社のIDで、後半3バイトが任意に使えて製造番号的なものが入っています。 11:22:33:44:55:66みたいな形で表現されていることが多いです。

この番号は重複しないので、同じデバイスを複数持っていてもすべて違う番号になっています。

デバイス名

こちらの文字列でもデバイスの識別ができます。ただしすべてのデバイスでデバイス名が定義されているわけではないようです。

サービスUUID

マウスだったり、キーボードだったり特定の機能を表すサービスのIDです。複数の機能がある場合には、複数のサービスが登録されています。

サービスを識別するのがサービスUUIDになります。一般的には有名なサービスは定義済みになっており、この中のサービスを提供していることとなります。

定義済みサービスUUID

https://www.bluetooth.com/ja-jp/specifications/gatt/services/

キャラクタリスティックUUID

サービスの中にさらにキャラクタリスティックがあります。こちらは実際の値を保存しているもので、書き込みや読み込みなどの実際の操作を行うことができる機能のUUIDです。

バッテリー残量だったり、キーボードなどの入力値などの機能です。こちらも有名なものは定義済みになっています。

定義済みキャラクタリスティックUUID

https://www.bluetooth.com/ja-jp/specifications/gatt/characteristics/

サンプルスケッチ

#include "BLEDevice.h"

// 検索するBLEデバイス。serviceUUIDを調べる場合には空にする(例はHuman Interface Device"00001812-0000-1000-8000-00805f9b34fb")
static BLEUUID serviceUUID("1812");

static BLEAdvertisedDevice* myDevice;

// 接続してCharacteristic一覧を取得
bool connectToServer() {
  Serial.print("接続先 : ");
  Serial.println(myDevice->getAddress().toString().c_str());
  BLEClient*  pClient  = BLEDevice::createClient();
  pClient->connect(myDevice);

  // サービス取得
  BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
  if (pRemoteService == nullptr) {
    pClient->disconnect();
    return false;
  }

  // Characteristic一覧
  Serial.println("characteristic一覧");
  std::map<std::string, BLERemoteCharacteristic*>* mapCharacteristics = pRemoteService->getCharacteristics();
  for (std::map<std::string, BLERemoteCharacteristic*>::iterator i = mapCharacteristics->begin(); i != mapCharacteristics->end(); ++i) {
    Serial.print(" - characteristic UUID : ");
    Serial.print(i->first.c_str());
    Serial.print(" Broadcast:");
    Serial.print(i->second->canBroadcast()?'O':'X');
    Serial.print(" Read:");
    Serial.print(i->second->canRead()?'O':'X');
    Serial.print(" WriteNoResponse:");
    Serial.print(i->second->canWriteNoResponse()?'O':'X');
    Serial.print(" Write:");
    Serial.print(i->second->canWrite()?'O':'X');
    Serial.print(" Notify:");
    Serial.print(i->second->canNotify()?'O':'X');
    Serial.print(" Indicate:");
    Serial.print(i->second->canIndicate()?'O':'X');
    Serial.println();
  }

  // stop
  Serial.println("プログラム停止!");
  while (1) delay(1000);
}

// 検索したデバイスを受信するコールバック関数
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      Serial.print("BLE デバイス発見 : ");
      Serial.println(advertisedDevice.toString().c_str());

      if (advertisedDevice.haveServiceUUID() &amp;&amp; advertisedDevice.isAdvertisingService(serviceUUID)) {
        // 指定デバイスだったら接続する
        BLEDevice::getScan()->stop();
        myDevice = new BLEAdvertisedDevice(advertisedDevice);
      }
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("BLEデバイス検索開始...");
  BLEDevice::init("");

  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
}

void loop() {
  if (myDevice != NULL) {
    connectToServer();
  }

  delay(1000);
}

最初はserviceUUIDを空にして実行すると、待受中のBLEデバイスすべてを列挙することができます。

その後にCharacteristicを取得したいserviceUUIDを指定することで、そのserviceUUIDが持つCharacteristicを列挙します。

ただし、同じ種類のデバイスが複数待受中になっている場合は、serviceUUIDだけで接続してしまうと、違うデバイスに接続しにいってしまう場合があるので、その場合にはアドレスやデバイス名などを条件に加えてください。

実行結果例

BLEデバイス検索開始...
BLE デバイス発見 : Name: AB Shutter3       , Address: ff:ff:c1:??:??:??, appearance: 961, serviceUUID: 00001812-0000-1000-8000-00805f9b34fb
接続先 : ff:ff:c1:??:??:??
characteristic一覧
[E][BLERemoteCharacteristic.cpp:273] retrieveDescriptors(): esp_ble_gattc_get_all_descr: Unknown
[E][BLERemoteCharacteristic.cpp:273] retrieveDescriptors(): esp_ble_gattc_get_all_descr: Unknown
[E][BLERemoteCharacteristic.cpp:273] retrieveDescriptors(): esp_ble_gattc_get_all_descr: Unknown
[E][BLERemoteCharacteristic.cpp:273] retrieveDescriptors(): esp_ble_gattc_get_all_descr: Unknown
 - characteristic UUID : 00002a4a-0000-1000-8000-00805f9b34fb Broadcast:X Read:O WriteNoResponse:X Write:X Notify:X Indicate:X
 - characteristic UUID : 00002a4b-0000-1000-8000-00805f9b34fb Broadcast:X Read:O WriteNoResponse:X Write:X Notify:X Indicate:X
 - characteristic UUID : 00002a4c-0000-1000-8000-00805f9b34fb Broadcast:X Read:X WriteNoResponse:O Write:X Notify:X Indicate:X
 - characteristic UUID : 00002a4d-0000-1000-8000-00805f9b34fb Broadcast:X Read:O WriteNoResponse:X Write:X Notify:O Indicate:X
 - characteristic UUID : 00002a4e-0000-1000-8000-00805f9b34fb Broadcast:X Read:O WriteNoResponse:O Write:X Notify:X Indicate:X
プログラム停止!

ダイソーのスマホ用リモートシャッターを調べたものです。コンパイルオプションでエラーを表示するようにしているので、エラーが4行見えます。

この結果を見ると定義済みのcharacteristicが5つ見えます。

  • 2a4a : HID Information
  • 2a4b : Report Map
  • 2a4c : HID Control Point
  • 2a4d : Report
  • 2a4e : Protocol Mode

ただ、おそらくこのデバイスはcharacteristicの構造がおかしいようでして、ただしく利用することができませんでした。

iPhoneでcharacteristicを調べるアプリ「GATTBrowser」を使っても「180a : PnP ID」と「180f : Battery Level」の2つしか見えませんでした。

検索して、このデバイスに接続してcharacteristicを取得すると、端末にリセットがかかるので、標準ライブラリだと利用することができないと思います。

検索しても同じようにリセットがかかっている人が多いので、接続先デバイスによってESP32からBLE接続をすると本体のリセットがかかって、接続できないようです。

他のデバイスで接続する実験を行ってみたいと思います。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)