Node.jsでBLEのPeripheralの実装をしてみます。ライブラリはblenoを利用します。
Centralの実装をしたい場合はnobleを利用しましょう。Node.jsでBLEを扱うパッケージのnobleとnoble-deviceで非公式SDKっぽいものを作ってみるなどではCentral側でした。
同じ作者なので姉妹プロジェクトですね。
インストール
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/ などで生成しましょう。
'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を作ってアクセスしてみます。
このアプリを利用しました。
起動するとこのように作成したデバイス名が表示されました。
Connectして値を読み込むとNode.js側でonReadRequestの箇所が発火し、数字が表示されます。
58
69
70
75
77
78
81
所感
結構便利なんですけど、実装例がなかなか見つからず仕組み理解に時間がかかりました。
Subscribe周りの実装も試してみたいですね。
NefryBT(ESP32)との接続も試せたので別途書いてみたいです。