---
# System prepended metadata

title: Bluetooth Low Energyとは

---

# 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);

}

```