macOS Montoryでnoble（BLE）を使いたくてハマったところ #iotlt


## mac+Node.jsでBLEを使いたい

IoT関連だとBLEを使いたいよねって話題が定期的に出てきますが、Node.jsでBLEを制御するnobleというライブラリがmacだと使えなくなっていた問題が数年前くらいにありました。

そこに対して、以前書いた記事で`@abandonware/noble`を使うと使えるようになったという話までが2021年春頃の話題です。

https://zenn.dev/n0bisuke/articles/01-nodejs-ble-noble-2021

## macOS Montereyで問題再発

[当時](https://zenn.dev/n0bisuke/articles/01-nodejs-ble-noble-2021)はBigSurだったのですがMontereyに上げてから試したらインストールでこける事象に。

```bash
$ npm i @abandonware/noble

npm ERR! code 1
npm ERR! path /Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble
npm ERR! command failed
npm ERR! command sh -c node-gyp rebuild
npm ERR! CC(target) Release/obj.target/nothing/node_modules/node-addon-api/nothing.o
npm ERR!   LIBTOOL-STATIC Release/nothing.a
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@7.1.2
npm ERR! gyp info using node@15.14.0 | darwin | x64
npm ERR! gyp info find Python using Python version 3.9.10 found at "/usr/local/opt/python@3.9/bin/python3.9"
npm ERR! gyp info spawn /usr/local/opt/python@3.9/bin/python3.9
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args   '/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
npm ERR! gyp info spawn args   'binding.gyp',
npm ERR! gyp info spawn args   '-f',
npm ERR! gyp info spawn args   'make',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble/build/config.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/Library/Caches/node-gyp/15.14.0/include/node/common.gypi',
npm ERR! gyp info spawn args   '-Dlibrary=shared_library',
npm ERR! gyp info spawn args   '-Dvisibility=default',
npm ERR! gyp info spawn args   '-Dnode_root_dir=/Users/n0bisuke/Library/Caches/node-gyp/15.14.0',
npm ERR! gyp info spawn args   '-Dnode_gyp_dir=/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp',
npm ERR! gyp info spawn args   '-Dnode_lib_file=/Users/n0bisuke/Library/Caches/node-gyp/15.14.0/<(target_arch)/node.lib',
npm ERR! gyp info spawn args   '-Dmodule_root_dir=/Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble',
npm ERR! gyp info spawn args   '-Dnode_engine=v8',
npm ERR! gyp info spawn args   '--depth=.',
npm ERR! gyp info spawn args   '--no-parallel',
npm ERR! gyp info spawn args   '--generator-output',
npm ERR! gyp info spawn args   'build',
npm ERR! gyp info spawn args   '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! gyp info spawn make
npm ERR! gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
npm ERR! env: python: No such file or directory
npm ERR! make: *** [Release/nothing.a] Error 127
npm ERR! gyp ERR! build error 
npm ERR! gyp ERR! stack Error: `make` failed with exit code: 2
npm ERR! gyp ERR! stack     at ChildProcess.onExit (/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
npm ERR! gyp ERR! stack     at ChildProcess.emit (node:events:369:20)
npm ERR! gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
npm ERR! gyp ERR! System Darwin 21.4.0
npm ERR! gyp ERR! command "/Users/n0bisuke/.volta/tools/image/node/15.14.0/bin/node" "/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd /Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble
npm ERR! gyp ERR! node -v v15.14.0
npm ERR! gyp ERR! node-gyp -v v7.1.2
npm ERR! gyp ERR! not ok

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/n0bisuke/.npm/_logs/2022-05-13T03_31_42_891Z-debug.log
```

らしいです。

ふむふむ... ちなみにNode.jsのバージョンはv18系で試してましたが、エラーでたので[この時](https://zenn.dev/n0bisuke/articles/01-nodejs-ble-noble-2021)のv15系まで落としてみましたが、エラーは変わらず。

## Pythonコマンドが使えなくなっている件

普段Python使わないので気づいてなかったですが、どうやらMontereyからデフォのPythonが消えてるらしいです。

> 参考: [Python 2.7が削除される「macOS 12.3 Monterey」では、Python 3の同梱もされないもよう。](https://applech2.com/archives/20220128-python-not-include-in-macos-12-3-monterey.html)

```bash
$ python
command not found
```

たしかにいない。気付いてなかった... 

とはいえエラーログみると

```
/usr/local/opt/python@3.9/bin/python3.9
```

に3系はいるらしいです。

```bash
$ /usr/local/opt/python@3.9/bin/python3.9
Python 3.9.12 (main, Mar 26 2022, 15:51:15) 
[Clang 13.1.6 (clang-1316.0.21.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
```

いますね。ということはPython3ではなく2系を入れないといけない模様です。

## pyenvでPython2系をインストール

調べると出てきた[pyenv](https://github.com/pyenv/pyenv)を使ってPython2系をインストールしていきます。

```
brew update && brew upgrade
```

`~/.zshrc`の1番下に追記しました。

```.zshrc
(省略)
# pyenv
alias brew='env PATH="${PATH//$(pyenv root)\/shims:/}" brew'
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```


```bash
$ source ~/.zshrc
```

pyenvが使えるかチェックします。

```bash
$ pyenv

pyenv 2.3.0
Usage: pyenv <command> [<args>]

Some useful pyenv commands are:

(省略)
```

動いた模様です。調べると2系はv2.7.18が最新らしいのでインストールしてみます。

```bash
$ pyenv install 2.7.18 
```

次にパスを通します。

```bash
$ pyenv global 2.7.18 
```

確認してみます。

```bash
$ python --version
Python 2.7.18
```

きたー　v2.7.18のPythonが無事にmacOS Montereyにインストールされました。

## @abandonware/nobleのインストールに再チャレンジするもエラー

再度インストールしてみます。

```bash
$ npm i @abandonware/noble
```

しかし、またエラー出ました。。。↓

```bash
npm ERR! code 1
npm ERR! path /Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble
npm ERR! command failed
npm ERR! command sh -c node-gyp rebuild
npm ERR! CC(target) Release/obj.target/nothing/node_modules/node-addon-api/nothing.o
npm ERR!   LIBTOOL-STATIC Release/nothing.a
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@7.1.2
npm ERR! gyp info using node@15.14.0 | darwin | x64
npm ERR! gyp info find Python using Python version 3.9.12 found at "/usr/local/opt/python@3.9/bin/python3.9"
npm ERR! gyp info spawn /usr/local/opt/python@3.9/bin/python3.9
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args   '/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
npm ERR! gyp info spawn args   'binding.gyp',
npm ERR! gyp info spawn args   '-f',
npm ERR! gyp info spawn args   'make',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble/build/config.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   '/Users/n0bisuke/Library/Caches/node-gyp/15.14.0/include/node/common.gypi',
npm ERR! gyp info spawn args   '-Dlibrary=shared_library',
npm ERR! gyp info spawn args   '-Dvisibility=default',
npm ERR! gyp info spawn args   '-Dnode_root_dir=/Users/n0bisuke/Library/Caches/node-gyp/15.14.0',
npm ERR! gyp info spawn args   '-Dnode_gyp_dir=/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp',
npm ERR! gyp info spawn args   '-Dnode_lib_file=/Users/n0bisuke/Library/Caches/node-gyp/15.14.0/<(target_arch)/node.lib',
npm ERR! gyp info spawn args   '-Dmodule_root_dir=/Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble',
npm ERR! gyp info spawn args   '-Dnode_engine=v8',
npm ERR! gyp info spawn args   '--depth=.',
npm ERR! gyp info spawn args   '--no-parallel',
npm ERR! gyp info spawn args   '--generator-output',
npm ERR! gyp info spawn args   'build',
npm ERR! gyp info spawn args   '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! gyp info spawn make
npm ERR! gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
npm ERR! env: python: No such file or directory
npm ERR! make: *** [Release/nothing.a] Error 127
npm ERR! gyp ERR! build error 
npm ERR! gyp ERR! stack Error: `make` failed with exit code: 2
npm ERR! gyp ERR! stack     at ChildProcess.onExit (/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
npm ERR! gyp ERR! stack     at ChildProcess.emit (node:events:369:20)
npm ERR! gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
npm ERR! gyp ERR! System Darwin 21.4.0
npm ERR! gyp ERR! command "/Users/n0bisuke/.volta/tools/image/node/15.14.0/bin/node" "/Users/n0bisuke/.volta/tools/image/node/15.14.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd /Users/n0bisuke/Documents/ds/playground/insmart/node_modules/@abandonware/noble
npm ERR! gyp ERR! node -v v15.14.0
npm ERR! gyp ERR! node-gyp -v v7.1.2
npm ERR! gyp ERR! not ok

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/n0bisuke/.npm/_logs/2022-05-13T05_01_53_341Z-debug.log
```

ずっとPython3を見に行ってるような表示ですよね。

python2系をインストールして後にNode.jsをインストールしてみたらどうだろうと思い、Node.jsのインストールからやってみした。

```bash
$ volta install node@18
```

かつゴミを消してみました。ファイルを消せてなかったのでこっちが原因だったかも?

```bash
$ rm -rf node_modules
$ rm package-lock.json
```

## @abandonware/nobleを再度インストール

3度目の正直... ということで、

```bash
$ npm i @abandonware/noble

added 12 packages, and audited 13 packages in 19s

2 low severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
```

**やっと うまくいった模様......!**

うごいたー。

周辺のBLE機器が表示されました。

> ![スクリーンショット 2022-05-13 14.06.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/a2021fda-a69c-a93d-db04-ec7234f6aa07.png "スクリーンショット 2022-05-13 14.06.36.png")

コードは変わらず以下の通りです。

```js

'use strict';

const noble = require('@abandonware/noble');
const knownDevices = [];

//discovered BLE device
const discovered = (peripheral) => {
    const device = {
        name: peripheral.advertisement.localName,
        uuid: peripheral.uuid,
        rssi: peripheral.rssi
    };
    knownDevices.push(device);
    console.log(`${knownDevices.length}:${device.name}(${device.uuid}) RSSI${device.rssi}`);
}

//BLE scan start
const scanStart = () => {
    noble.startScanning();
    noble.on('discover', discovered);
}

if(noble.state === 'poweredOn'){
    scanStart();
}else{
    noble.on('stateChange', scanStart);
}
```

## まとめ: Node.jsでBLEを使うためにPythonを入れた

macOS Montereyでnobleを使うのにPython2系のインストールが必要でした。
（元々依存関係はあったんですね。）