Node.jsでBLE Peripheralの実装をするパッケージblenoを使ってみる


Node.jsでBLEのPeripheralの実装をしてみます。ライブラリは[bleno](https://github.com/noble/bleno)を利用します。

Centralの実装をしたい場合は[noble](https://github.com/noble/noble)を利用しましょう。[Node.jsでBLEを扱うパッケージのnobleとnoble-deviceで非公式SDKっぽいものを作ってみる](https://qiita.com/n0bisuke/items/62624b473f827958fd54)などではCentral側でした。

同じ作者なので姉妹プロジェクトですね。

* [noble](https://github.com/noble/noble) - BLE Central
* [bleno](https://github.com/noble/bleno) - BLE Peripheral


## インストール

Node.js v8.11.3で試してみました。

```
npm i bleno
```

ちなみに、Node.js v10系で試すとインストール時に以下のエラーが発生しました。Node.jsのversion下げるとビルドが通ります。 v8系で試してみましょう。(2018/6/24時点)

```
make: *** [Release/obj.target/binding/src/XpcConnection.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/Users/n0bisuke/.nodebrew/node/v10.0.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:258:23)
gyp ERR! stack     at ChildProcess.emit (events.js:182:13)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:225:12)
gyp ERR! System Darwin 17.6.0
gyp ERR! command "/Users/n0bisuke/.nodebrew/node/v10.0.0/bin/node" "/Users/n0bisuke/.nodebrew/node/v10.0.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/n0bisuke/dotstudio/playground/tello-nodejs/node_modules/xpc-connection
gyp ERR! node -v v10.0.0
gyp ERR! node-gyp -v v3.6.2
gyp ERR! not ok
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: bluetooth-hci-socket@0.5.1 (node_modules/bluetooth-hci-socket):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for bluetooth-hci-socket@0.5.1: wanted {"os":"linux,android,win32","arch":"any"} (current: {"os":"darwin","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: xpc-connection@0.1.4 (node_modules/xpc-connection):
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: xpc-connection@0.1.4 install: `node-gyp rebuild`
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: Exit status 1
```

## 数値データを発信する簡単なBLE Peripheralの実装

シンプルな例です。

UUIDは https://www.uuidgenerator.net/ などで生成しましょう。

```ble_peripheral.js
'use strict'

const bleno = require('bleno');
const BlenoPrimaryService = bleno.PrimaryService;

const SERVECE_UUID = `D5875408-FA51-4763-A75D-7D33CECEBC31`; //適宜書き換え
const CHARACTERISTIC_UUID = `A4F01D8C-A037-43B6-9050-1876A8C23584`; //適宜書き換え
const DEVICE_NAME = `n0bisuke-BLE-device`; //デバイス名
console.log(`bleno - ${DEVICE_NAME}`);

let counter = 0;
setInterval(()=>{counter++}, 1000); //値の変化を見るために毎秒インクリメント

const Characteristic = bleno.Characteristic;
const characteristic = new Characteristic({
    uuid: CHARACTERISTIC_UUID,
    properties: ['read'],
    onReadRequest: (offset, callback) => { //Central側からReadリクエストが来ると発火
        console.log(counter); //READリクエストでカウントを表示
        const result = Characteristic.RESULT_SUCCESS;
        const data = new Buffer.from(`${counter}`);
        callback(result, data);
    }
});

bleno.on('stateChange', (state) => {
    console.log(`on -> stateChange: ${state}`);
    if (state === 'poweredOn') {
        bleno.startAdvertising(DEVICE_NAME, [SERVECE_UUID]);
    } else {
        bleno.stopAdvertising();
    }
});

bleno.on('advertisingStart', (error) => {
    console.log(`on -> advertisingStart: ${(error ? 'error ' + error : 'success')}`);
    if(error) return;

    const blenoService = new BlenoPrimaryService({
        uuid: SERVECE_UUID,
        characteristics: [characteristic]
    });

    bleno.setServices([blenoService]);
});
```

## 実行

`Mac Book Pro(high Sierra)`と`Nexus 5(Android)`で通信してみます。

イメージはこんな感じ

```
Peripheral(Mac) <---READ---- Central(Nexus 5)
```

Node.jsを実行します。

```
$ node ble_peripheral.js

bleno - n0bisuke-BLE-device
on -> stateChange: poweredOn
on -> advertisingStart: success
```

実行するとこの状態で待機になります。

スマホ(Nexus 5)側でBLE Centralを作ってアクセスしてみます。

このアプリを利用しました。

https://play.google.com/store/apps/details?id=com.macdom.ble.blescanner&hl=ja

起動するとこのように作成したデバイス名が表示されました。

![](https://i.gyazo.com/d094eee04accd9f5f69dd5ae9b8a5737.png)


Connectして値を読み込むとNode.js側でonReadRequestの箇所が発火し、数字が表示されます。

```
58
69
70
75
77
78
81
```

## 所感

結構便利なんですけど、実装例がなかなか見つからず仕組み理解に時間がかかりました。

Subscribe周りの実装も試してみたいですね。

NefryBT(ESP32)との接続も試せたので別途書いてみたいです。