M1 Macでopnizを試してみた - Lチカ編 (TIPS→すべて解消済)

# はじめに

IoTLT vol.84で @n0bisuke さんが opniz で Lチカ を試されていました。

https://iotlt.connpass.com/event/236918/

https://twitter.com/n0bisuke/status/1493569929148514310

https://twitter.com/n0bisuke/status/1493532445685157889

### opnizとは

@miso_develop さんが開発された、「M5StackといったESP32デバイスをNode.jsからobnizライクに制御するためのSDKおよびArduinoライブラリ」です。

https://speakerdeck.com/miso/zhao-ming-gatuitetaraxiao-sisok-kerudakefalsedebaisuwozuo-tutetahazuga-itufalsejian-nikaobniztupoinanikawozuo-tuteitajian-nituite

https://speakerdeck.com/miso/opnizfalsegoshao-jie

https://speakerdeck.com/miso/yi-wai-toyi-nili-tutaopniz

https://speakerdeck.com/miso/opnizfalsegoshao-jie-ver2

https://speakerdeck.com/miso/opniz-atupudetoshao-jie

https://twitter.com/miso_develop/status/1493549189984567296

だったり、

![スクリーンショット 2022-02-16 21.17.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/88b09181-1885-6398-4602-e476a164894d.png)

という噂も..。

# きっかけ

イベント終了後の懇親会で開発者の @miso_develop さんが参加され、M1 Macで動作確認をしてみるという話の流れになりました。

https://twitter.com/Zakkiea/status/1493562473257250816

# まずはコレ

https://twitter.com/miso_develop/status/1483396619781677068

M1 Macでopnizハンズオンを試してみます。

https://qiita.com/miso_develop/items/0c2ee20bd1cc1e7aaeea

# opniz-cliをインストールして実行する (デバイスへスケッチを書き込む)

## つまずきポイント1: Node v15以上が必要 (→opniz CLI@v0.3.3でv15.x以上が必要と表示)
最初、M1 Macで実行してエラーになったので、Intel Macでも実行したところ同じくエラーが出力されました。
エラーの内容はこちら。

```bash
$ npm install opniz-cli

> opniz-cli@0.3.2 postinstall /Users/kitazaki/tmp/20220215/node_modules/opniz-cli
> node ./dist/setup.js

internal/modules/cjs/loader.js:1025
  throw new ERR_REQUIRE_ESM(filename);
  ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/kitazaki/tmp/20220215/node_modules/zx/globals.mjs
    at Object.Module._extensions..mjs (internal/modules/cjs/loader.js:1025:9)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14)
    at Module.require (internal/modules/cjs/loader.js:848:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/ui/command/install.js:16:1)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14) {
  code: 'ERR_REQUIRE_ESM'
}
npm WARN notsup Unsupported engine for zx@4.3.0: wanted: {"node":">= 14.13.1"} (current: {"node":"12.14.1","npm":"6.13.4"})
npm WARN notsup Not compatible with your version of node/npm: zx@4.3.0
npm WARN notsup Unsupported engine for globby@12.2.0: wanted: {"node":"^12.20.0 || ^14.13.1 || >=16.0.0"} (current: {"node":"12.14.1","npm":"6.13.4"})
npm WARN notsup Not compatible with your version of node/npm: globby@12.2.0
npm WARN 20220215@1.0.0 No description
npm WARN 20220215@1.0.0 No repository field.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! opniz-cli@0.3.2 postinstall: `node ./dist/setup.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the opniz-cli@0.3.2 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/kitazaki/.npm/_logs/2022-02-15T15_19_04_406Z-debug.log
```

```bash
$ npm install opniz-cli

> opniz-cli@0.3.2 postinstall /Users/kitazaki/tmp/20220215/node_modules/opniz-cli
> node ./dist/setup.js

/Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/config.js:10
exports.opnizHomePath = `${os.homedir().replaceAll("\\", "/")}/.opniz-cli`;
                                        ^

TypeError: os.homedir(...).replaceAll is not a function
    at Object.<anonymous> (/Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/config.js:10:41)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/ui/command/install.js:19:18)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
npm WARN 20220215@1.0.0 No description
npm WARN 20220215@1.0.0 No repository field.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! opniz-cli@0.3.2 postinstall: `node ./dist/setup.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the opniz-cli@0.3.2 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/kitazaki/.npm/_logs/2022-02-15T15_24_12_381Z-debug.log
```

エラーの原因はNode v15から導入されたString.prototype.replaceAll()が使用されていることでした。

https://yongjinkim.com/nodejstypeerror-string-replaceall-is-not-a-function-%E3%81%AE%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95/

M1 Mac (macOS Monterey 12.1) は Node v14、Intel Mac (macOS Big Sur 11.6.3) は Node v12 だったので、nodebrew コマンドや nvm コマンドで Node v16 をインストールして解決しました。

```bash
$ node -v
v16.14.0
```

```bash
$ npm install opniz-cli

added 137 packages, and audited 138 packages in 1m

20 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
npm notice 
npm notice New minor version of npm available! 8.3.1 -> 8.5.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.5.0
npm notice Run npm install -g npm@8.5.0 to update!
npm notice 
```

## つまずきポイント2: index.jsの実行権限をつける (→opniz CLI@v0.3.3で対応済)

npxコマンドの実行がPermission deniedで失敗しました。

```bash
$ npx opniz upload
sh: /Users/kitazaki/tmp/20220215/node_modules/.bin/opniz: Permission denied
```

実際に実行するopnizコマンドを調べたところ実行権限が不足していました。

```bash
$ ls -la /Users/kitazaki/tmp/20220215/node_modules/.bin/opniz
lrwxr-xr-x  1 kitazaki  staff  26  2 16 00:22 /Users/kitazaki/tmp/20220215/node_modules/.bin/opniz -> ../opniz-cli/dist/index.js
$ ls -la /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/index.js 
-rw-r--r--  1 kitazaki  staff  128  2 16 00:32 /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/index.js
```

実行権限をつけて解決しました。

```bash
$ chmod 755 /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/index.js
```

## つまずきポイント3: 改行コードを変更する (CRLF→LF) (→opniz CLI@v0.3.3で対応済)

今度は別のエラーが出力されました。

```bash
$ npx opniz upload
env: node\r: No such file or directory
```

改行コードの問題で env コマンドが node コマンドを見つけられずに失敗します。
似たような事象を見つけました。

https://stackoverflow.com/questions/30344858/node-script-executable-not-working-on-mac-env-node-r-no-such-file-or-directo

解決方法は改行コードを変更する (CRLF→LF) ことでしたので、brew コマンドで dos2unix コマンドをインストールして対応することにしました。

```bash
$ brew install dos2unix
$ dos2unix /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/index.js
dos2unix: converting file /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/index.js to Unix format...
```

dos2unixコマンドを実行して解決しました。

## つまずきポイント4: ネットワークのエラーを回避する (Wi-Fi機能をOFF→ONする) (→arduino-cli@#1668で修正済 →opniz CLI@v0.3.4で対応済)

issue

https://github.com/arduino/arduino-cli/issues/1666

PR

https://github.com/arduino/arduino-cli/pull/1668

arduino-cliのNightly buildsで修正されていることを確認しました。

https://twitter.com/Zakkiea/status/1495195947135299584

opniz@0.3.4で修正されました。

https://twitter.com/miso_develop/status/1495279261581647875

npxコマンドを実行するとネットワークのエラー？！(mdns lookup error: write udp6)が出力されました。

```bash
$ npx opniz upload
✖ Loading serial port
/Users/kitazaki/tmp/20220215/node_modules/zx/dist/bundle.cjs:15261
        let output = new ProcessOutput({
                     ^

ProcessOutput [Error]: Error detecting boards: Error getting board list: [listing ports from discovery builtin:mdns-discovery: command failed: mdns lookup error: write udp6 [::]:54974->[ff02::fb]:5353: sendto: no route to host]
    at /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/ui/prompt.js:42:29
    exit code: 5
    at ChildProcess.<anonymous> (/Users/kitazaki/tmp/20220215/node_modules/zx/dist/bundle.cjs:15261:22)
    at ChildProcess.emit (node:events:520:28)
    at maybeClose (node:internal/child_process:1092:16)
    at Socket.<anonymous> (node:internal/child_process:451:11)
    at Socket.emit (node:events:520:28)
    at Pipe.<anonymous> (node:net:687:12)
```

Wi-Fi機能をOFFにして、もう一度 npxコマンドを実行したところエラー(Arduino Cloudからボード情報を取得する！？)が出力されました。

```bash
$ npx opniz upload
✖ Loading serial port
/Users/kitazaki/tmp/20220215/node_modules/zx/dist/bundle.cjs:15261
        let output = new ProcessOutput({
                     ^

ProcessOutput [Error]: Error detecting boards: Error getting board info from Arduino Cloud
    at /Users/kitazaki/tmp/20220215/node_modules/opniz-cli/dist/ui/prompt.js:42:29
    exit code: 5
    at ChildProcess.<anonymous> (/Users/kitazaki/tmp/20220215/node_modules/zx/dist/bundle.cjs:15261:22)
    at ChildProcess.emit (node:events:520:28)
    at maybeClose (node:internal/child_process:1092:16)
    at Process.ChildProcess._handle.onexit (node:internal/child_process:302:5)
```

仕方がないので、もう一度Wi-Fi機能をONにして npxコマンドを実行したところ、今度はうまくいきました。
M1 Macでも、Intel Macでも同じ事象になりました。
(Mac特有の問題なのか、ネットワーク環境の問題なのか切り分けができていません。)
デバイスはM5Aom Liteを使用しました。

```bash
$ npx opniz upload
? デバイスのシリアルポートを選択してください: /dev/cu.usbserial-29522A14F3
? デバイスを接続するWi-FiのSSIDを入力してください: XXXXXXXXXX-2G
? デバイスを接続するWi-Fiのパスワードを入力してください: **************
? opnizプログラム実行マシンのIPアドレスを選択してください: 
? opnizプログラム実行マシンのIPアドレスを選択してください: 192.168.3.19
? デバイスを選択してください: m5atom
? opnizプログラムの通信ポート番号を入力してください: 3000
✔ Install library
⠹ Compile sketchSketch uses 958990 bytes (73%) of program storage space. Maximum is 1310720 bytes.
Global variables use 40516 bytes (12%) of dynamic memory, leaving 287164 bytes for local variables. Maximum is 327680 bytes.
✔ Compile sketch
⠼ Upload opniz to port: /dev/cu.usbserial-29522A14F3esptool.py v3.0-dev
Serial port /dev/cu.usbserial-29522A14F3
Connecting......
Chip is ESP32-PICO-D4 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, Embedded Flash, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 24:a1:60:47:ec:b0
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 1500000
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 8192 bytes to 47...
Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 16553.9 kbit/s)...
Hash of data verified.
Compressed 17120 bytes to 11164...
Writing at 0x00001000... (100 %)
Wrote 17120 bytes (11164 compressed) at 0x00001000 in 0.1 seconds (effective 1100.4 kbit/s)...
Hash of data verified.
Compressed 959104 bytes to 553925...
Writing at 0x00010000... (2 %)
Writing at 0x00014000... (5 %)
Writing at 0x00018000... (8 %)
Writing at 0x0001c000... (11 %)
Writing at 0x00020000... (14 %)
Writing at 0x00024000... (17 %)
Writing at 0x00028000... (20 %)
Writing at 0x0002c000... (23 %)
Writing at 0x00030000... (26 %)
Writing at 0x00034000... (29 %)
Writing at 0x00038000... (32 %)
Writing at 0x0003c000... (35 %)
Writing at 0x00040000... (38 %)
Writing at 0x00044000... (41 %)
Writing at 0x00048000... (44 %)
Writing at 0x0004c000... (47 %)
Writing at 0x00050000... (50 %)
Writing at 0x00054000... (52 %)
Writing at 0x00058000... (55 %)
Writing at 0x0005c000... (58 %)
Writing at 0x00060000... (61 %)
Writing at 0x00064000... (64 %)
Writing at 0x00068000... (67 %)
Writing at 0x0006c000... (70 %)
Writing at 0x00070000... (73 %)
Writing at 0x00074000... (76 %)
Writing at 0x00078000... (79 %)
Writing at 0x0007c000... (82 %)
Writing at 0x00080000... (85 %)
Writing at 0x00084000... (88 %)
Writing at 0x00088000... (91 %)
Writing at 0x0008c000... (94 %)
Writing at 0x00090000... (97 %)
Writing at 0x00094000... (100 %)
Wrote 959104 bytes (553925 compressed) at 0x00010000 in 9.2 seconds (effective 831.4 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 128...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (128 compressed) at 0x00008000 in 0.0 seconds (effective 2880.4 kbit/s)...
Hash of data verified.Leaving...
Hard resetting via RTS pin...

✔ Upload opniz to port: /dev/cu.usbserial-29522A14F3
```

# opniz SDKをインストールしてサンプルコードを実行する (デバイスをLチカする)

サンプルコードをダウンロードします。デバイスはM5Atom Liteを使用しました。(デバイス毎にダウンロードするサンプルコードのURLが異なるので注意)

```bash
$ curl -fsSLk https://raw.githubusercontent.com/miso-develop/opniz-sdk-nodejs/main/examples/blink/blink-m5atom.js > index.js
```

opniz SDKをインストールします。

```
$ npm install opniz

added 32 packages, and audited 170 packages in 6s

20 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

サンプルスクリプトを実行します。

```bash
$ node index.js 
[connected]
```

[connected]と表示され、デバイス(M5Atom Lite)のLEDが1秒毎に点滅を繰り返せば正常です。

![FLsyWoVaAAAumaL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/244bd02c-e2f6-63f9-79aa-cc779d84d705.jpeg)

写真ではMacとデバイス(M5Atom Lite)がUSBケーブルで接続されていますが、Macとデバイス(M5Atom Lite)はネットワーク(Wi-Fi)で接続されていますので、USBケーブルを抜いてUSBアダプタへ接続しても問題なく動作します。

# パケットキャプチャ

デバイス(M5Atom Lite)の電源を入れると、デバイスからMacへ接続要求が繰り返されています。
Macでサンプルスクリプトを実行するとtcpポート:3000で待ち受け状態になるので、デバイスからMacへ接続が成功します。
接続後にMacからデバイスへ命令が送信されていることを確認できます。
通信路は暗号化されていませんので、命令内容(jsonフォーマット)を確認できます。

![スクリーンショット 2022-02-16 22.49.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/5440fa12-7fb3-07b8-9cbb-fcb1a6cb6c5d.png)