はじめに
nobleが虫の息というか、もう息の根を止めてあげていい状態なので他に移行しなければならない。さて次は何がいいだろうかと調べてみてラズパイ用途で行き当たるのは以下の2つくらいじゃないだろうか。
node-bleが開発が活発に見えるが、node-bluezもシンプルでよさげ。両方やってみることにする。試した環境はこちら
uname -a
Linux raspberrypi.local 5.8.0-1016-raspi #19-Ubuntu SMP PREEMPT Tue Feb 9 20:12:43 UTC 2021 aarch64 aarch64 aarch64 GNU/Linux
前準備
node-bluzが依存するライブラリとnode.jsをインストールする
sudo apt install -y libglib2.0-dev libdbus-1-dev
sudo apt install -y nodejs npm
ここで入るnodeのバージョンは12.xで古い。nで最新を入れる
sudo npm i -g n
sudo n latest
sudo apt remove --purge nodejs
sudo apt autoremove
/usr/local/bin
にlatest versionが入るのでパスを通しておく
export "$HOME/usr/local/bin:$PATH"
source ~/.profile
node -v
v15.13.0
TypeScriptの準備
mkdir -p work && cd $_
npm init -f
npm i -S typescript ts-node bluez node-ble sleep-promise
npx tsc --init
Promiseまわりのエラー回避で tsconfig.jsonのlibを以下にする
lib: ["ES2015", "dom"],
node-bleでやってみた
import { createBluetooth } from 'node-ble';
import sleep from 'sleep-promise';
const main = async () => {
const { bluetooth, destroy }: any = createBluetooth();
const adapter: any = await bluetooth.defaultAdapter();
if (! await adapter.isDiscovering()) {
console.log('Discovering:');
await adapter.startDiscovery();
while (true) {
const devices: any = await adapter.devices();
console.log(devices);
await sleep(3000);
}
}
};
main();
実行する
npx ts-node node-ble.ts
Discovering:
[ '4E:2E:8E:F1:63:91', 'E1:A6:93:4A:ED:C3' ]
[ '4E:2E:8E:F1:63:91', '5B:A0:F3:EB:BB:0D', 'E1:A6:93:4A:ED:C3' ]
[ '4E:2E:8E:F1:63:91', '5B:A0:F3:EB:BB:0D' ]
[ '4E:2E:8E:F1:63:91', '5B:A0:F3:EB:BB:0D' ]
[ '4E:2E:8E:F1:63:91', '5B:A0:F3:EB:BB:0D', 'E1:A6:93:4A:ED:C3' ]
[ '4E:2E:8E:F1:63:91', '5B:A0:F3:EB:BB:0D', 'E1:A6:93:4A:ED:C3' ]
とれた。Adapterにイベントハンドラがないので Adapter.device()
を一定時間ループで回してとる手法。nobleでイベントドリブンな取得に慣れていたのでこれ思いつかなくてしばらくハマった。一回device()しただけじゃ絶対とれないし。これはこれでコールバックじゃない分制御の汎用性は高いと思うけど。好みの問題だろうか。
node-bluezでやってみた
import Bluez from 'bluez';
const bluetooth = new Bluez();
const handleOn = async (address: string, props: any) => {
console.log(`[NEW] Device: ${address}, ${JSON.stringify(props.Name)}`);
const dev = await bluetooth.getDevice(address);
dev.on("PropertiesChanged", (props) => {
console.log(`[CHG] Device: ${address}, ${props}`);
});
};
const main = async () => {
try {
bluetooth.on('device', handleOn);
await bluetooth.init();
const adapter = await bluetooth.getAdapter();
await adapter.StartDiscovery();
console.log("Discovering");
} catch (e) {
throw new Error(e);
}
}
main();
実行する
npx ts-node node-bluez.ts
Discovering
[NEW] Device: 54:AB:0C:6F:15:E6, undefined
[NEW] Device: E1:A6:93:4A:ED:C3, "tkr"
[NEW] Device: D1:1C:63:61:E0:01, undefined
[NEW] Device: E1:A6:93:4A:ED:C3, "tkr"
[NEW] Device: FB:33:A1:32:7F:75, "tkr"
[NEW] Device: E1:A6:93:4A:ED:C3, "tkr"
とれた。こちらはAdaptorにイベントハンドラがあって受信したタイミングでパケットが降ってくる。tkr
は財布とかに入れてある忘れ物防止タグのTrackRだ。
おわりに
どちらもざっくりコードをみるかぎりDbus APIのラッパーな感じ。アドバタイジングとるだけならイベントドリブンなnode-bluezのほうが好み。ケースバイケースで使っていこうと思う。やっとnobleの葬式ができそう。