Node.js(electron)アプリでBLE機器を取り扱う方法まとめ(2024/4月版)

断続的に[electron](https://electronjs.org/)でBLE機器を扱っていて、自分でもたまにやろうとした時いろいろやり方とか状況を忘れ去っていたり、NodeやOSのSDKの更新で動かなくなる時があるので備忘録も兼ねて都度都度最新の状況を書き残しておきます（記事は上書き更新します）。

## 結論 現在のオススメ！(2024/04/26時点)

@abandonware/noble でかなり整地されたのと、Node版 Webbluetoothの更新によって選択肢が増え安定した感がでてきました。また、ElectronからuserGestureもどきで実行する技を使うとほぼ機能的なデメリットなくなったので、個人的にはElectronで使う時はrendererでwebbluetooth使うと思います（ビルドがラク）。

|  Type  |  Windows  |  MacOS  |  Linux  |
| ---- | ---- | ---- | ---- |
|  @abandonware/noble  |  〇(1)  |  〇(1)  |  〇(1)  |
|  Node版 Webbluetooth  |  〇(2)   |  〇(2)  |  未確認  |
|  Chromium(Electron)版 webbluetooth  |  〇(3)  |  〇(3)  |  〇(3)  |
|  上記以外のNative  |  △(4)   |  △(5)  |  〇(6)  |

〇：注意事項がほぼ無い、△：動いたり動かなかったり注意事項がある

## (1)@abandonware/noble

- Node.jsからBLE機器と通信を行うデファクトの方法は[noble](https://github.com/noble/noble)ですが、こちらは派生になります。元リポジトリのメンテナンスが止まってしまったため混迷を極めていましたが、2023/05月現在@abandonware/nobleで3OS網羅されたのでしばらく主流となるでしょう。
- Windows
    - 1.9.2-17 からWinRT実装が組み込まれました。OSのバージョンが10.0.15063以上だとこちらのbindingsが使用されます。
        - 10.0.15063以上だとドライバーをインストールせずに使用可能です
        - 10.0.15063未満では旧来のWinUSBドライバーをインストールする必要があるモジュールが生成されます（lib/resolve-bindings.js 参照）
    - VS2017だと問題なくビルドできます
    - VS2019/VS2022の場合はWindows SDK ver.22000以上を入れる必要があります。それ以前のバージョンはC++の互換性やSDKが壊れているなどの問題でビルドできません。
    - Node16-20で動作確認済
    - 環境構築に関して、windows-build-tool をインストールする記事がよく引っかかりますが、**既にこの方法は非推奨**です。オフィシャルのNode.jsをインストールする時に、オプションで開発環境をインストールするチェックボックスがあります。そこをチェックするとChocolateyをインストールし、Chocolatey経由でPython3とVS2019 build toolをインストールしてくれます。インストール後Windows SDKのバージョンをあげれば万事OKです。
- MacOS
    - 基本的に問題なく使えますが、1.9.2-17/18あたりで動かない時期があったので、うまく動作しなかった場合は最新バージョンをいくつか試してみてください
    - Node16-20で動作確認済
- Linux
    - electronだとnobleに権限が渡らないことがあるので、テスト的には `sudo npx electron src --no-sandbox` のようにして無理やり動かしています。これ正解まだわかっていません、、、。

## (2)Node版 Webbluetooth

こちら[注目のプロジェクト](https://github.com/thegecko/webbluetooth)です。Chrome不要（つまりNode単体）で動きます。API的にWebbluetoothと同じインターフェースになっているためこのような名前がついており、Webbluetoothと同じCall方法になるため実装の共通化が図れます。

割とメンテナンスされている[SimpleBLE](https://github.com/OpenBluetoothToolbox/SimpleBLE)というクロスプラットフォームのC++(一部Rust/Python)ライブラリを利用したNodeラッパー対応がver3で実施されました。nobleがずっと綱渡りなので、SimpleBLEでBluetooth界隈が一枚岩になってくれるとうれしい、、。


## (3)Chromium(Electron)版 WebBluetooth

Chromium自身がBLE機器と通信を行えるWebBluetooth機能を実装しているため、electronアプリの場合はその機能を利用することもできます。しばらくMac/Linux/Androidのみの対応でしたが、ChromiumのV70からはWindows10でも使えるようになったため、かなりユニバーサルに使えるようになりました。Nativeビルドをする必要がない！という大きなメリットがあります。注意点は以下です。

- Chromiumの制限で自動でscanをかけることができないので、Electron側の機能（executeJavaScript）で、バイパスさせることでプログラム制御が可能です。
- 通常Webbluetoothで表示されるデバイス選択ダイアログは利用できず、何も設定しないと一番最初に見つかったデバイスに接続されます。複数のデバイスから選びたい場合、実際のBLEの取り回しはrenderer(Chromium)、接続先の制御をかけるのがmain側になるため、IPCで情報を往復させなくてはいけなくてちょっと面倒になります。

### 具体的な方法

[electron-webbluetooth](https://github.com/tkomde/electron-webbluetooth) 複数のデバイスから選択するサンプルです。
[electron-webbluetooth-auto](https://github.com/tkomde/electron-webbluetooth-auto) 自動接続・切断時自動再接続のサンプルです。WindowsとMacで挙動が異なるので、そこの処理を分けて両方でちゃんと再接続ができるようにするのに結構苦労しました、、。

### 参考情報
[Electron Documentation - webContents
](https://electronjs.org/docs/api/web-contents#event-select-bluetooth-device):   electron内のWebbluetoothの挙動が記載されています。
[Electron and Multiple BLE Devices #11865](https://github.com/electron/electron/issues/11865): この機能に関して言及されてます。

### Linux

RaspberryPi OS@RaspberryPi5で簡単に確認してみただけですが、webPreferences: {experimentalFeatures: true},を付与するとうまくいくみたいです。

## (4) 雑多なライブラリ Windows編

- [noble-winrt その1](https://github.com/urish/noble-winrt): Windows10 build 15063以降で利用でき、WebBluetoothのPolyfill(BLEServer.exe)を使用してnoble互換にするバージョンです。UUIDのフィルタが効かない、UUIDの形式がハイフン有りでnobleとは異なるなどの実装の差が多少あります。またpoweredOn/powerdOffはきちんとハンドリングされていません。ビルドが走らないため、開発環境に依存されないのが利点です。
- [noble-winrt その2](https://github.com/Timeular/noble-winrt): Windows10 build 15063以降で利用でき、build 17134 SDK 以降のC++/WinRT APIをcallするバージョンです。discoverSomeServicesAndCharacteristicsには未対応。こちらVS2019だったり最近のSDKではビルドできません。
- [noble-uwp](https://github.com/jasongin/noble-uwp): Windows10のビルド15063で改善対応されたBLEスタックを使用した元祖Windows10用の汎用ライブラリがnoble-uwpです。ライブラリ内で使用しているNode-RTのソースがV8等の更新についてこれておらず、ビルド的にも無駄が多いので2019/8の時点ではレガシー化しており、もはやビルド不能です。
- [Node-RT](https://github.com/NodeRT/NodeRT)という、WinRTをそのまま叩けるライブラリを使うという技があります。単なるWinRTのラッパーじゃんって話もあるのですが、nobleと異なりBluetoothだけではなくすべてのWinRT APIのラッパーを自動生成しているため利用している開発者が多く、ゆえにミドルウェアや開発環境の更新で出てきた不具合を直してくれる確率が高いです。ただnode-rtの中でもビルドできないモジュールが存在し、2023年3月現在、windows.devices.bluetooth.genericattributeprofileが動きませんでした。注意点としては以下です。
    - WinRT APIではクラス名、メソッドなど頭文字大文字だが、Node-RTはキャメルケースになる   
    - インストールされているSDKやVisualStudioのバージョンに合わせてnpmでインストールするものを変える

## (5) 雑多なライブラリ Mac編

- [noble-mac](https://github.com/Timeular/noble-mac): nobleのほうでMacOSのunofficialな方法を使っていたのがmac OS 10.14 (Mojave)でエラーになってしまったらしく、officialな方法で繋がるようにしたのがこちらのレポジトリです。noble-winrtと同じく作者はTimeularさん。xpc-connectionのコードが入っているので新しい環境でビルドエラーになることがあります。

## (6) 雑多なライブラリ Linux編

- [jrobeson/noble#merged](https://github.com/jrobeson/noble/tree/merged): noble本体に溜まっていた様々なプルリクをマージしたもの。自分の手元ではRaspberryPi Zero/3/4で動作を確認してます。
    - 純正NobleだとNode.js 8より大きいバージョンでビルドがコケますが、こちらのブランチではNode.js 10/12で動くようになります
- ちゃんとメンテされているBlueZをDBus経由で叩く以下のモジュールを使用するのが良いでしょう。
    - [node-bluez](https://github.com/WaeCo/node-bluez)
    - [node-ble](https://github.com/chrvadala/node-ble)

## Changelog

- 2024/4/26更新 electronで遜色なく使う方法が分かったので、優先度Up
- 2023/5/16更新 大幅書き換え
- 2023/3/14更新 Node-SimpleBLEの記述を追加してトーンダウン
- 2023/2/15更新 Windowsの記述を修正
- 2022/12/1更新 Windowsの記述を修正
- 2020/12/9更新 Linuxの記述を修正
- 2020/11/13更新 WebBluetoothの記述を修正
- 2020/11/4更新 Macの記述を修正
- 2020/4/5更新 WebBluetoothの記述を修正 
- 2020/3/9更新 Linuxの記述を修正
- 2019/9/3更新 Linux(Raspbian)の記述を追加
- 2019/8/2更新 noble-uwpがレガシー化してきたので、noble-winrtの優先度上げました