Mac上の Node-RED で BLE を利用して toio の制御（Read、Notify で値を受け取る）

Mac上で動かしている Node-RED で、BLE関連のノード「[node-red-contrib-generic-ble](https://flows.nodered.org/node/node-red-contrib-generic-ble)」を使ってデバイスへのデータ書き込みを試して、以下の記事を書いたのですが、今回は通知・読み出しを試してみようという内容です。
　●Mac上の Node-RED での BLE利用について調べてみて toio との組み合わせを少し試す（2台の toio のモーター制御を行う） - Qiita
　　https://qiita.com/youtoy/items/91965e8cc8f12b7ee528

デバイスは、上記の記事を書いた時にも利用した [toio](https://toio.io/) を使います。

## セットアップについて
「node-red-contrib-generic-ble」のノードの追加については、[前回の記事の「node-red-contrib-generic-ble を試す」という項目](https://qiita.com/youtoy/items/91965e8cc8f12b7ee528#node-red-contrib-generic-ble-%E3%82%92%E8%A9%A6%E3%81%99)で書かれた内容をご参照ください。

## node-red-contrib-generic-ble を使ったデバイスとの接続の下準備
次に node-red-contrib-generic-ble を使ったデバイスとの接続・データの読み書き等を行う下準備を行います。
こちらも詳細は、[前回の記事の「toio を BLE経由で扱ってみる（データの書き込み） ＞ Node-RED で toio に接続する下準備」という項目](https://qiita.com/youtoy/items/91965e8cc8f12b7ee528#node-red-%E3%81%A7-toio-%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%E4%B8%8B%E6%BA%96%E5%82%99)で書かれた内容をご参照ください。

## データの読み取りを行う
準備が整ったところで、いよいよデータの読み取りを行います。
そのために、今回は node-red-contrib-generic-ble の 2つのノードのうち「Generic BLE in」を使います。

### データ読み取りのための仕様
データの読み取り方法について確認するため、公式ページの「Characteristics Value Read」の部分を見てみます。

以下の通り、インジェクトノードのトピックの部分に「キャラクタリスティックUUID」を指定して、そのノードを「Generic BLE in」ノードにつなげれば良いようです。また、トピックを空にすることで、全てのキャラクタリスティックUUID に関するデータ読み取りができるようです。
![読み取りを実行するための仕様.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/4dd912a9-5080-44af-d182-657761c7e48d.jpeg)

### データの読み取りを実際に試す
「Generic BLE in」ノードの設定は以下のとおりで、デバイスのスキャン・設定も終えた状態にしています。
![BLEノードのinの設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c4d3092a-71ed-972a-daf2-d507cd7ec448.jpeg)

#### トピックを空にして読み取りを試す
インジェクトノードのトピックを空にしたものを「Generic BLE in」ノードにつなげ、さらに「Generic BLE in」ノードの後にデバッグノードをつなげ、インジェクトノードを実行してみます。
そうすると、以下のようにデータ取得ができているのを確認できました。
![トピックを空にした場合（全データ）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c1f50354-3514-d936-43c0-f6d2c21d35ea.jpeg)

#### toio を使った読み取りを試す前に仕様を確認
ここからは、特定のキャラクタリスティックUUID を指定してデータを読み取ってみます。
具体的には、ボタンとモーション検出の 2つを試してみます。

それら 2つに関する toio公式の通信仕様のページは以下のとおりです。
　●ボタン · toio™コア キューブ 技術仕様
　　https://toio.github.io/toio-spec/docs/ble_button
　●モーション検出 · toio™コア キューブ 技術仕様
　　https://toio.github.io/toio-spec/docs/ble_sensor

そして、キャラクタリスティックUUID は、それぞれ以下となります。

- キャラクタリスティックUUID の仕様
   - ボタン
      - 10B20107-5B3B-4571-9508-CF3EFCD7BBAE
   - モーション検出
      - 10B20106-5B3B-4571-9508-CF3EFCD7BBAE

インジェクトノードで上記の UUID を設定する時はハイフンは除くなどして、以下のように指定しました。

- インジェクトノードのトピックに指定する UUID
   - ボタン
      - 10b201075b3b45719508cf3efcd7bbae
   - モーション検出
      - 10b201065b3b45719508cf3efcd7bbae

#### 読み取りを試す（ボタン）
上記を利用して、ボタンに関する読み取りを試した際の出力は以下のとおりです。

以下は、toio のボタンを押していない状態で読み取りを行った時のデバッグ出力です。
![ボタン：取得できたデータ（押されていない）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/83729673-1f0a-2968-01c4-80a1d549443d.jpeg)
そして以下は、toio のボタンを押した状態で読み取りを行った時のデバッグ出力です。
![ボタン：取得できたデータ（押されている）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/664c1bbf-6769-b63d-f8dc-9347d6fbde3b.jpeg)
ボタンの押下の有無によって読み取れる値の 2バイト目が toio の通信仕様通りに変化したのが確認できました。

さらに、buffer の部分だけデバッグ出力するということも試してみます。
先ほどデバッグ出力した際の buffer の部分のパスを、デバッグ表示のボタンを使って取得します。そして取得できたパスは以下のとおりです。

```
payload.characteristics["10b201075b3b45719508cf3efcd7bbae"]
```

あとは、デバッグ出力の対象が `payload` となっている部分を 、以下のように `payload.characteristics["10b201075b3b45719508cf3efcd7bbae"]` に置きかえて読み取りを試すだけです。
![bufferの部分をデバッグ出力.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a48f9f5b-792c-4400-b727-ea094473aa50.jpeg)
以下のように、buffer の部分のみをデバッグ出力できたことが確認できました。
![デバッグ出力されたbuffer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/492093d1-4183-11e2-b832-e79c727335d9.jpeg)

#### 読み取りを試す（モーション検出）
次は、モーション検出を試した時の結果を掲載します。

以下は toio の底面を上にした状態（逆さにした状態）で読み取りを試した時の結果です。
読み取れたデータの 5バイト目（4: 0x2）の部分が仕様通りになっていることが確認できました。
![モーション検出：底面が上の時.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/f00a6ebe-d160-d0f9-67a3-b0a1eb7abac6.jpeg)
また、仕様に書かれている他の情報も合わせて読み取られて出力されているのが確認できました。

## 通知を利用する
読み取りはできたので、次は通知を受けとれるようにしてみます。

### 通知に関する仕様
通知を受け取るやり方は、以下の[公式サンプル](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/master/examples/01-read-write.json)を読み込むことで情報を得られました。
![公式サンプル：読み書き.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e8113f84-775f-4967-819e-96ccbfd9534b.jpeg)
具体的にはこの部分です。
![通知の設定の説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/165a7173-2bc6-a7ec-376d-a19a7bcf7097.jpeg)

ノードの名前には「温度を 5秒間通知する処理を開始」と書いてあります。
そのノードのプロパティを確認すると、ペイロードに `{"notify":true, "period":5000}` と設定されており、これが通知用の設定のようです。
![公式サンプルのNotifyの設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6cec9e80-288c-f199-5ba5-e80f1c34645e.jpeg)

### 通知を実際に試してみる
#### 有限の通知
ここで、ボタンのイベントの通知を実際に試してみます。

出力が分かりやすいように、デバッグ出力を buffer のみにしようと思います。
そのために、前の手順でも試したようにデバッグノードの出力対象を `payload.characteristics["10b201075b3b45719508cf3efcd7bbae"]` に変更しました。

そしてインジェクトノードのトピックに `{"notify":true, "period":2}` や `{"notify":true, "period":100}` 、 `{"notify":true, "period":1000}` などを指定して実行し、その後に toio のボタンを何度か押してみたりしました。その時のデバッグノードの出力は以下のとおりです。
![Notifyを試した時のデバッグ出力.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9b21765a-b599-783e-6e3d-8c978b86dc9f.jpeg)

`period` の設定値を変えて試したりなどしたのですが、この時点では仕様はよく分からずでした。

#### ずっと通知を受け取る
ここで、node-red-contrib-generic-ble を使った通知に関する情報があるかどうか調べるために「node-red-contrib-generic-ble notify」というキーワードでの検索をしたところ、既に Node-RED で BLE の通知を試された方の記事が Qiita にありました。

●node-red-contrib-generic-ble（notifyでデータ読み込みを行う） - Qiita
　https://qiita.com/takanorimutoh/items/9d37bfbba7c5918b3229

記事を見てみると以下のような記載があり、  `{"notify":true, "period":0}` にした時の挙動を自分のフローでも確認してみました。
![別の方が書いた記事.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1dbdfcb8-5407-fb28-7410-995e09e1a9ac.jpeg)
試してみると、継続的に通知を受信できてそうでした。

しかし、period がデータ送信回数という話のほうは、自分のフローでは想定通りに動いてませんでした。
例えば、数字を少ない値にしている場合も、連続でボタンを押すと数字よりも多い数の通知を受けとれたりしました。また、ボタンを押すタイミングを変えてみると、同じ数値を設定していた時も受けとれた通知の数が変わったりしました。

これは、toio を使っていることが影響しているのか、それとも違う理由があるのか...

#### 元のソースを見てみる
[GitHub にソースがあるので](https://github.com/CANDY-LINE/node-red-contrib-generic-ble)、Node-RED のノード自作関連の知識はないものの見てみました。
調べてみた結果について結論から書くと、関係しそうな部分が見つかったというレベルで終わった感じです（後で、また見てみようかと）。

まず、Notify・Read を行うノードが定義されていそうな部分は「[generic-ble.js の 758行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/master/src/generic-ble.js#L758)]」のようでした（ `class GenericBLEInNode` と書かれた行から始まる部分）。

その他、関係しそうな部分は以下がありそうでした。

- generic-ble.js内
   - [869行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/master/src/generic-ble.js#L869)
      - `onBleNotify(uuid, readObj, err) {` という部分
   - [720行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/master/src/generic-ble.js#L720)
      -  `r.addDataListener((data, isNotification) => {` という部分
   - [869行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/6c976faeab5e09526259c3de686d26b9340c8fcf/src/generic-ble.js#L869) 
      - `onBleNotify(uuid, readObj, err) {` という部分
   - [735行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/6c976faeab5e09526259c3de686d26b9340c8fcf/src/generic-ble.js#L735)と次の行
      - `if (period > 0) {` 、 `setTimeout(() => {` という部分
   - [681行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/6c976faeab5e09526259c3de686d26b9340c8fcf/src/generic-ble.js#L681)と次の行
      - `async subscribe(uuids = '', period = 0) {` 、 `const state = await this.connectPeripheral();` という部分

## まとめ
とりあえず、読み取り・通知の両方が実行でき、通知の `period` の部分がよく分からない状態で終わりましたが、それ以外の部分は一通り試せた状態になりました。

あとは、通知の `period` の仕様をもう少し見てみたり、BLE でつなぐデバイスを別のものにして挙動を確認したりしてみようと思います。

## 前回・今回の記事で試した中で分かったこと
前回・今回と記事を書く中で node-red-contrib-generic-ble を試した際、分かったことをここにメモしておこうと思います。

### 接続/切断処理
#### 切断
今回、公式のサンプルをフローを見ている中で接続・切断処理について書かれた部分があったため、それをここで記載します。

切断については、公式サンプルの以下の部分に書かれています。
![公式サンプルの切断の処理の部分.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/64addfe9-287e-f727-1c69-7d576581a2c8.jpeg)
この部分のインジェクトノードのプロパティを見てみると、「トピックに `disconnect` を設定する」というのが実現方法のようでした。実際に試して切断が行われることも確認できました。
![切断.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3a843065-8686-2a56-618d-1d1b26a160f5.jpeg)

また、フローのデプロイを行った時も切断が起こるようです。

#### 接続
一方、「トピックに `connect` を設定」している接続用のインジェクトノードもあったのですが、これについては前回・今回のお試しを進める中で違う内容も確認できました。
具体的には、BLE用のノードに何らか適当な内容を設定したインジェクトノードをつなぎ、それを実行するだけでも接続処理が行われました。

#### 接続/切断のトピックの設定について
今回使ったノードのソースコードを見てみると、「[generic-ble.js の 819行目](https://github.com/CANDY-LINE/node-red-contrib-generic-ble/blob/6c976faeab5e09526259c3de686d26b9340c8fcf/src/generic-ble.js#L819
)」に接続・切断を行う際のトピックに関する判定処理が書かれてそうでした。
![ソースコード：接続・切断に関するトピック.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/acd6d377-faf3-01cf-06a5-a0b6a12e3604.jpeg)