# Bluetoothとは Bluetoothは無線通信の技術標準の一つであり、WiFiとは違い短距離のデータ交換を目的としています。 <br/> ## Bluetoothのバージョン Bluetoothは現在も進化しており、それぞれのバージョンごとに性能や機能が追加されている。 (2023/11/02時点ではVer5.4が公開されている。) <br/> ## Bluetoothの種類 Bluetoothには、<span style="color: red; ">Bluetooth Classic</span>と<span style="color: red; ">Bluetooth Low Energy(BLE)</span>の2種類があります。 - Bluetooth Classic 従来のBluetooth. 音声や画像のデータ送信に秀でているが、消費電力が多い。 使用例 : - PC - 無線イヤホン - Bluetooth Low Energy Ver4.0から追加された低消費電力版Bluetooth. 消費電力が低いが、送信速度や送信量が犠牲となっている。センサーデータの送信などIoTデバイスでよく使われている。 使用例 : - IoTデバイス - 無線マウス・キーボード <br/> (Ver5.3でLE Audioが発表され、今後は無線イヤホンでもBLEが活用されると思われる。) <br/> ## デモ 実際にBLE通信してみる <br/> #### 使用デバイス - ESP32 : 2台 #### 使用環境 - IDE : Arduino IDE - ボード : ESP Dev Module ### BLE通信の流れ 2台のデバイスを、それぞれ「Server」と「Client」と役割分けする。 ① Serverが発見してもらうために電波を発する ② Clientが周りの電波をスキャンする ③ 電波の情報から接続したいデバイスを見つけ、接続要求を送る ④ 通信確立する ### コード ESP32でBLEを使うライブラリは複数あるが、今回は「ESP32 BLE Arduino」ライブラリを使用する。 デフォルトで入っているのでライブラリの追加は必要ない。 <br/> - Client側 ``` #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEScan.h> #include <BLEAdvertisedDevice.h> // 接続先のサービスUUID static BLEUUID demo_serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); // 接続先のキャラクタリスティックUUID static BLEUUID demo1_characteristicUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); static BLEClient* pClient = nullptr; // Server or Client のクライアント側 static BLEAdvertisedDevice* connDevice; // 接続するデバイスサーバー static BLERemoteService* pRemoteService; // サービスを操作するインスタンス static BLERemoteCharacteristic* pRemoteCharacteristic; // キャラリスを操作するインスタンス /*******************/ /** 各コールバック **/ /*******************/ // デバイスをスキャンしたか監視するコールバック class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { //アドバタイズデバイスを見つけたら呼び出す if (advertisedDevice.getName() == "demo_ServerDevice") { //デバイス名でソートする BLEDevice::getScan()->stop(); connDevice = new BLEAdvertisedDevice(advertisedDevice); } } }; //自身の通信状態を監視するコールバック class MyClientCallbacks : public BLEClientCallbacks { // デバイスと接続したら呼び出される void onConnect(BLEClient* pclient) { Serial.println("Client Connected!"); } // デバイスと切断したら呼び出される void onDisconnect(BLEClient* pclient) { Serial.println("Client Disconnected!"); delete pClient; pClient = nullptr; } }; /** * connectToServer関数 * */ bool connectToServer(){ if(pClient == nullptr){ Serial.println("client null"); //BLE接続の初期設定 pClient = BLEDevice::createClient(); pClient->setClientCallbacks(new MyClientCallbacks()); if(!pClient->isConnected()){ Serial.println("no connect"); //BLEサーバーに接続する pClient->connect(connDevice); } } // サービスUUIDが存在しているか pRemoteService = pClient->getService(demo_serviceUUID); if (pRemoteService == nullptr) { Serial.println("no service"); return false; } // キャラクタリスティックUUIDが存在しているか pRemoteCharacteristic = pRemoteService->getCharacteristic(demo1_characteristicUUID); if (pRemoteCharacteristic == nullptr) { Serial.println("no chararis"); return false; } return true; } /** * setup関数 * マイコン起動時に実行される関数。1度きり。 * 主に初期化処理を実行する関数 * * 1. シリアルの初期化。ボートレートは115200 * 2. BLEDeviceの初期化。ここでデバイス名を指定できる。 * 3. Scan処理の初期化。アドバタイズコールバックとモードを設定する。 * 4. 30秒間Scanを開始する。 */ void setup(){ Serial.begin(115200); BLEDevice::init("demo_ClientDevice"); BLEScan* pBLEScan = BLEDevice::getScan(); pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setActiveScan(true); pBLEScan->start(30, false); } /** * loop関数 * setup後に呼び出される関数。デフォルトで無限ループになっている。 * 主にメイン処理を実行する関数 * * 1. BLE接続処理をconnectToServer関数に任せる。 * 真なら接続中の処理、偽なら未接続中の処理を実行する。 * 2. 現状何も書いていない。 * * 以降繰り返し */ void loop(){ if (connectToServer()) { // BLE接続中の処理 } else { // BLE未接続中の処理 } delay(10); } ``` - Server側 ``` #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> static BLEUUID demo_serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); static BLEUUID demo1_charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); static BLEServer* pServer = NULL; //Server or Client のサーバー側 static BLEService* pService; //サービスのインスタンス static BLECharacteristic* pCharacteristic; //キャラリスのインスタンス bool deviceConnected = false; bool oldDeviceConnected = false; /*******************/ /** 各コールバック **/ /*******************/ //自身の通信状態を監視するコールバック class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer* pServer) { //デバイスと接続したら呼び出す Serial.println("1"); deviceConnected = true; } void onDisconnect(BLEServer* pServer) { //デバイスと切断したら呼び出す //Serial.println("切断"); Serial.println("0"); deviceConnected = false; } }; //指定されたキャラリスを監視するコールバック class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { //値が書き込まれたら呼び出す String serial_val = ""; std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { for (int i = 0; i < rxValue.length(); i++){ serial_val += rxValue[i]; } Serial.println(serial_val); delay(10); } } }; //BLEサーバーのセットアップ void ble_server_setup() { BLEDevice::init("demo_ServerDevice"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService* pService = pServer->createService(demo_serviceUUID); pCharacteristic = pService->createCharacteristic( demo1_charUUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE); pCharacteristic->setCallbacks(new MyCharacteristicCallbacks()); pService->start(); pServer->getAdvertising()->start(); } void setup() { Serial.begin(115200); ble_server_setup(); delay(10); } void loop() { if (deviceConnected) { //接続中 if (!deviceConnected) ble_server_setup(); } else { //接続待ち } //通信が切断されたときの処理 if (!deviceConnected && oldDeviceConnected) { delay(500); pServer->startAdvertising(); oldDeviceConnected = deviceConnected; } if (deviceConnected && !oldDeviceConnected) { oldDeviceConnected = deviceConnected; } delay(10); } ```