UnityでiOS実機とmacエディタでBLEを使う

# Unity で iOS 実機と macOS Editor で BLE を使って Daydream Controller の生データを取得する
Unity で iOS 実機と macOS の Editor で、CoreBluetooth Frameworkを使って、Bluetooth Low Energyのデバイスと通信する Assetを 作成しました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">UnityエディタとiOSで動くBluetoothのプラグイン作った<a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://t.co/EeHz0iqcmL">pic.twitter.com/EeHz0iqcmL</a></p>&mdash; ふじき (@fzkqi) <a href="https://twitter.com/fzkqi/status/1176485721445556224?ref_src=twsrc%5Etfw">September 24, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# リポジトリ

https://github.com/fuziki/UnityCoreBluetooth

# 
* Unity にはBluetooth で通信する機能がないです
* iOS で Daydream のコントローラを使いたかったので、アセットを自作しました
* Unity Editorにも対応しており、Editor で実際に接続して実装して、実機は動作確認だけという開発が可能です

# サンプル
* [Daydreamのコントローラの生データを取得して表示するプロジェクトです](https://github.com/fuziki/UnityCoreBluetooth/tree/develop/Examples/UnityExample)

## Daydreamコントローラ
* 下記の条件のcharacteristicに接続すると、コントローラの生データを取得可能です
* BLEデバイスは複数のserviceを持っており、serviceは複数のcharacteristicを持っています
* characteristicごとに決められた機能が提供されており、今回はcharacteristic uuidは同名のidが複数存在するので、notifyのusageのcharacteristicを使って生データを受け取ります

| 項目 | 接続する端末の条件 |
|---|---|
| デバイス名 | Daydream controller |
| service uuid | FE55 |
| characteristic usage | notify |

## UnityCoreBluetoothを使う

### 1. スキャンの開始
* CoreBluetoothManager のシングルトンのインスタンスを取得します
* poweredOn になることを確認して、スキャンを開始します

```cs
manager = CoreBluetoothManager.Shared;
manager.OnUpdateState((string state) =>
{
    Debug.Log("state: " + state);
    if (state != "poweredOn") return;
    manager.StartScan();
});
```

### 2.  接続したいデバイス名のデバイスを見つけたら接続する

```cs
manager.OnDiscoverPeripheral((CoreBluetoothPeripheral peripheral) =>
{
    if (peripheral.name != "")
        Debug.Log("discover peripheral name: " + peripheral.name);
    if (peripheral.name != "Daydream controller") return;

    manager.StopScan();
    manager.ConnectToPeripheral(peripheral);
});
```

### 3. デバイスに接続したらサービスを探す

```cs
manager.OnConnectPeripheral((CoreBluetoothPeripheral peripheral) =>
{
    Debug.Log("connected peripheral name: " + peripheral.name);
    peripheral.discoverServices();
});

manager.OnDiscoverService((CoreBluetoothService service) =>
{
    Debug.Log("discover service uuid: " + service.uuid);
    if (service.uuid != "FE55") return;
    service.discoverCharacteristics();
});
```

### 4. 対象の uuidの サービスが見つかったら characteristic を探す

```cs
manager.OnConnectPeripheral((CoreBluetoothPeripheral peripheral) =>
{
    Debug.Log("connected peripheral name: " + peripheral.name);
    peripheral.discoverServices();
});

manager.OnDiscoverService((CoreBluetoothService service) =>
{
    Debug.Log("discover service uuid: " + service.uuid);
    if (service.uuid != "FE55") return;
    service.discoverCharacteristics();
});
```

### 5.  usage が notify の characteristic が見つかったら通知を有効にする
* 通知を有効にすることで、daydreamコントローラから連続して生データを受け取ることが可能になります

```cs
manager.OnDiscoverCharacteristic((CoreBluetoothCharacteristic characteristic) =>
{
    string uuid = characteristic.uuid;
    string usage = characteristic.propertis[0];
    Debug.Log("discover characteristic uuid: " + uuid + ", usage: " + usage);
    if (usage != "notify") return;
    characteristic.setNotifyValue(true);
});
```

### 6. characteristic から通知があったら、データを受け取る
* リアルタイムで受け取れるのですが、メインスレッド保証ではないです
* そこで、一度変数に格納して、Update関数などでUIに反映させます

```cs
manager.OnUpdateValue((CoreBluetoothCharacteristic characteristic, byte[] data) =>
{
    this.value = data;
    this.flag = true;
});
```

### 7. Manager の動作開始
* コールバックの設定が終わった後に、Start関数を呼ぶことで、Bluetooth機能を起動します

```cs
manager.Start();
```

# 終わりに

unityエディタとiOS実機で動くBLEのプラグインを作成しました。
動作確認のたびにiOSの実機を起動するのは手間がかかるので、エディタで開発可能になることで開発が数倍楽になった気がします。
このプラグインの構造などは[こちらの記事に書いてあります。](https://qiita.com/fuziki/items/2fd05b8d0904cb1a466f)