XIAO ESP32C3を使ってみる その5(Bluefluit Connect、iPhoneとBLE通信)
はじめに
今回はXIAO ESP32C3とBluefluit Connectというスマートフォン向けのアプリで、BLE通信を試してみました。
以前Light Blueというアプリを使って通信していましたが、また別のアプリです。
▼こちらの記事ではLight Blueを使っています。
Light Blueではシリアルプロッタのようにグラフ表示することはできなかったので、他のアプリを探していました。Bluefluit Connectでは数値データをグラフとして表示することができました。
▼こんな感じです。
ただしBluefluit Connectの利用方法に関する情報があまり見つからなかったので苦戦しました。今回はアプリのUARTとPlotterの機能だけ利用しています。
▼以前の記事はこちら
関連情報
▼Adafruitのページはこちら
https://learn.adafruit.com/bluefruit-le-connect/ios-setup
本来はAdafruitが販売しているデバイスで利用する前提のようです。サンプルプログラムはあるもののXIAO ESP32C3ではすぐに実行できなかったので、アプリの機能を十分に利用したいのであれば対応しているデバイスを購入したほうが良さそうです。
▼ページの左にあるFeaturesをクリックするとアプリの機能について解説がありました。いくつかサンプルプログラムを試したのですが、factory resetで停止したりして実行できませんでした。今回は詳しくは見ていません。
Arduino IDEにはAdafruit BluefruitLE nRF51というライブラリがあり、様々なサンプルがあります。
ただしAdafruitのnRF51822で使うためのものだからなのか、XIAO ESP32C3では実行できませんでした。
▼気になるサンプルがあるのですが、実行できませんでした...
https://www.arduino.cc/reference/en/libraries/adafruit-bluefruitle-nrf51
▼AdafruitのnRF51822はこちら。なんとスニッフィングツールで、Wiresharkにデータを送信できるようです。
▼こちらのIoTデバイスのセキュリティに関する書籍で見たことがあります。特殊なマイコンという感じがしますね。
なお、今回は私のiPhone 8にBluefluit Connectをインストールして動作確認を行っています。
▼Apple Storeのページはこちら
https://apps.apple.com/us/app/bluefruit-connect/id830125974
▼Google Playのページはこちら
https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect
BLE通信のUARTについて
Bluefluit Connectでグラフ表示するにあたって、今回はBLEのサンプルプログラムの中でもUARTのサンプルを参考にしています。
▼ExamplesのBLEにあります。
連続でデータを送信するだけなら、Notifyでも実行できます。Light BlueではSubscribeすることで、連続的にデータを表示することができました。
▼こんな感じで表示されます。
今回UARTを参考にするのは、Bluefluit Connectでグラフ表示するのにBLE UART通信が必要だからです。アプリのPlotterのHelpに書かれていました。
▼PlotterのHelpの表示はこちら
プログラムを書く
今回はXIAO ESP32C3のA0ピンに可変抵抗を接続して、analogRead()で読み取り、その数値をBLE通信で送信するようにしてみました。
▼ブレッドボードで配線しています。
▼サンプルプログラムにanalogRead()の処理を追加したり、関数化したりしています。
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
const int pin = A0;
void setup() {
Serial.begin(115200);
BLE_setup("XIAO ESP32C3");
}
void loop() {
if (deviceConnected) {
char str[8];
int data = analogRead(pin);
sprintf(str, "%d\n", data);
Serial.println(str);
pTxCharacteristic->setValue(str);
pTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
}
};
class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
Serial.println("*********");
}
}
};
void BLE_setup(String name) {
// Create the BLE Device
BLEDevice::init(name);
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
30行目にあるsprintf()で、analogRead()で読み取った数値の後ろに"\n"を追加しています。
これはBluefluit Connectでグラフ表示するPlotterの機能を利用する上で必要な処理です。
▼再度Helpを見てみると、それぞれのデータは'\n'で終わることや、二つ以上のデータをプロットするには特定の文字で区切ることについて書かれています。
Bluefluit Connectと通信してみる
Bluefluit Connectを開いて、XIAO ESP32C3と接続してみます。
▼デバイス名をXIAO ESP32C3にしています。
BLE通信を通してアプリで利用できる機能が表示されます。
▼今回はUARTとPlotterを利用します。
▼UARTの画面では、数値データが連続で表示されています。
画面下に文字を入力して、Sendすることもできます。
▼Arduino IDEのシリアルモニタで、送信された文字列が表示されています。
Plotterでは数値データがグラフで表示されています。
▼可変抵抗を回すと数値が変わっていることが一目瞭然ですね。
最後に
Bluefluit Connectを利用して、BLE通信でXIAO ESP32C3と接続できました。画面構成はArduino IDEのシリアルモニタとシリアルプロッタに似ていますね。
今回はUARTとPlotterのみでしたが、Pin I/OやImage Transferなどの機能が気になっています。サンプルプログラムで引っかかっていた部分をコメントアウトして試していたのですが、XIAO ESP32C3では実行できませんでした。
Adafruit系のBLEデバイスは使ったことが無いので、また試してみようと思います。