p5.js Web Editor で #obniz を動かす（ #obnizOS ＋ #M5StickC ）

ある時からちょこちょこ利用している JavaScriptライブラリの [p5.js](https://p5js.org/)。
これをオンラインで実行できる環境として [p5.js Web Editor](https://editor.p5js.org/) というものがあります。

そんな中、ふと「p5.js Web Editor と obniz を組み合わせて使えないかな？」と思い、試してみたのが今回の内容です。

## obnizOS の簡単な処理を動かす
p5.js Web Editor上で処理を書いていく前に、まずは HTML+JavaScript の中で簡単な処理を動かし、動作確認を行ってから次に進んでいこうと思います。

動作テスト用に、まずは以下の公式ページにある、サンプルプログラムを実行して動かしてみます。

●起動とWi-Fi設定 - obniz Docs
　https://obniz.com/ja/doc/reference/m5stickc/quick-start
![プログラムのリンクの場所.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ecad1f19-dede-d346-ae90-a89c1ee44de4.jpeg)

上記の画像にある[「プログラムエディタ」のリンク](https://obniz.com/ja/console/program)をクリックした先では、以下の内容が実行できました。

```html
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script
      src="https://unpkg.com/obniz@3.14.0/obniz.js"
      crossorigin="anonymous"
    ></script>
  </head>
  <body>
    <div id="obniz-debug"></div>
    <h3>Connect From Your Browser</h3>
    <button class="btn btn-primary" id="on">LED ON</button>
    <button class="btn btn-primary" id="off">LED OFF</button>

    <div>
      <input type="text" id="text" value="Hello World🐶" />
      <button class="btn btn-primary" id="showtime">Print on obniz</button>
    </div>

    <div>Press "M5" Button!</div>
    <div id="print"></div>

    <script>
      var obniz = new Obniz.M5StickC("OBNIZ_ID_HERE");

      obniz.onconnect = async function() {
        obniz.display.drawing(false);
        obniz.display.clear();
        obniz.display.print("Hello World😁");
        obniz.display.drawing(true);

        obniz.buttonA.onchange = function(state) {
          $("#print").text(`button=${state}`);
        };

        $("#showtime").on("click", function() {
          obniz.display.drawing(false);
          obniz.display.clear();
          obniz.display.print($("#text").val());
          obniz.display.drawing(true);
        });

        $("#on").click(function() {
          obniz.led.on();
          obniz.display.drawing(false);
          obniz.display.clear();
          obniz.display.print("ON⭐");
          obniz.display.drawing(true);
        });

        $("#off").click(function() {
          obniz.led.off();
          obniz.display.drawing(false);
          obniz.display.clear();
          obniz.display.print("OFF🌩️");
          obniz.display.drawing(true);
        });
      };
    </script>
  </body>
</html>
```

上記は特に問題なく動きました。
そして、上記と公式ドキュメントを見つつ少し内容を変えたものを作り、こちらでも動作確認をしてみました。

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>obnizOSのテスト</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.css"
    />
    <script src="https://unpkg.com/obniz@3.14.0/obniz.js"></script>
  </head>
  <body>
    <section class="section">
      <div class="container">
        <h1 class="title">操作用ボタン</h1>
        <button
          class="button is-success is-light"
          type="button"
          onclick="onButtonClick()"
        >
          処理実行
        </button>
      </div>
    </section>

    <script>
      console.log("start!!");
      let obniz = new Obniz.M5StickC("OBNIZ_ID_HERE");
      console.log(obniz.connectionState);

      console.log("connecting...");
      obniz.onconnect = async function () {
        console.log(obniz.connectionState);

        obniz.display.drawing(false);
        obniz.display.clear();
        obniz.display.print("Hello World😁");
        obniz.display.drawing(true);

        obniz.buttonA.onchange = function (state) {
          console.log(state);
          if (state === true) {
            obniz.led.off();
            obniz.display.drawing(false);
            obniz.display.clear();
            obniz.display.print("OFF🌩️");
            obniz.display.drawing(true);
          }
        };
      };

      async function onButtonClick() {
        if (obniz.connectionState === "connected") {
          console.log("clicked!");
          obniz.led.on();
          obniz.display.drawing(false);
          obniz.display.clear();
          obniz.display.print("clicked⭐");
          obniz.display.drawing(true);
        }
      }
    </script>
  </body>
</html>
```

## p5.js Web Editor で環境を整える
それでは、p5.js Web Editor で obniz を動かすプログラムを書いてみます。

デフォルトでは p5.js Web Editor上で表示されるのは sketch.js ですが、画面左のメニューを開いて index.html を編集します。
![htmlを編集.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/62f52efb-a29f-45c3-1680-149e1e1fd9f3.jpeg)
具体的には、以下を追加します。

```html
    <script src="https://unpkg.com/obniz@3.14.0/obniz.js"></script>
```

## p5.js Web Editor で処理を書いていく
そして、sketch.js を編集していきます。デフォルトの内容は以下のとおりです。

```javascript
function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}
```

まずは、obniz と接続する処理を書き足して実行してみます。具体的には以下になります。

```javascript
console.log("start!!");
let obniz = new Obniz.M5StickC("OBNIZ_ID_HERE");
console.log(obniz.connectionState);

function setup() {
  createCanvas(400, 400);

  console.log("connecting...");
  obniz.onconnect = async function () {
    console.log(obniz.connectionState);

    obniz.display.drawing(false);
    obniz.display.clear();
    obniz.display.print("Hello World😁");
    obniz.display.drawing(true);
  };
}
```

そして上記を実行すると、以下のエラーが表示されました。
![エラー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ead555fc-7d14-8205-e681-317bb654a84d.jpeg)

### エラーの対応
調べてみると、「https の上で wss ではなく ws を使おうとしたら出るもの」のようでした。

Chrome の開発者ツールを開いて見た感じ、wss での接続を行っていそうな感じなのですが。
![開発者ツールでの表示.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/d88a1a32-5592-76f8-27ed-496d4930b08b.jpeg)

そんな中、ふと以下の仕様が頭をよぎり、「何か影響しているかも？」と思って確かめてみました。
　●ローカルコネクト - obniz Docs
　　https://obniz.com/ja/doc/reference/common/connection/localconnect
やったことは、PC と obniz がローカルで通信できないよう、PC を別の Wi-Fi につなぐというもの（両方のデバイスを自宅の Wi-Fi につないでいたのですが、片方をスマホのテザリングにして同一ネットワークではない状態にしました）。

その状態でプログラムを実行すると問題なく動作しましたが、本当に上記が原因なのか・良い対処法が他にないか等は、もう少し調査したいところです。
（上の方で掲載していた HTML＋JavaScript のファイルを、Netlify にアップして https で動かすと、普通に動いたりしたっぽいんだけど...）

### 【追記】 ローカルコネクトを使わないようにする
その後、ローカルコネクトを利用しない設定にできると知り、試してみました。
　●複数プログラムからの接続 - obniz Docs
　　https://obniz.com/ja/doc/reference/common/connection/multi-connectioz
結論から書くと、この対処を行うことで、上で書いていたエラーがでなくなりました。
具体的には、以下のような書きかえを行いました。

```javascript
// 書きかえ前
let obniz = new Obniz.M5StickC("OBNIZ_ID_HERE");
　　　↓
// 書きかえ後
let obniz = new Obniz.M5StickC("OBNIZ_ID_HERE",{local_connect : false});
```

### その他の対応
他に、プログラムの中を見てみると、以下のメッセージが出ていました。
![async.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2a95cba3-75c8-00a9-c027-52371355d36e.jpeg)

調べてみた感じだと、これが表示されないようにするには JavaScript のプログラムに `/*jshint esversion: 8 */` という記載を加えると良さそう？

## p5.js Web Editor上の処理を追加する
さらに、p5.js Web Editor で書いたプログラムに、PC のキーボード操作・obniz のボタン操作を使う処理を追加して動かしてみます。

```javascript
/*jshint esversion: 8 */

console.log("start!!");
let obniz = new Obniz.M5StickC("OBNIZ_ID_HERE",{local_connect : false});
console.log(obniz.connectionState);

function setup() {
  createCanvas(400, 400);

  console.log("connecting...");
  obniz.onconnect = async function () {
    console.log(obniz.connectionState);

    obniz.display.drawing(false);
    obniz.display.clear();
    obniz.display.print("Hello World😁");
    obniz.display.drawing(true);

    obniz.buttonA.onchange = function (state) {
      if (state === true) {
        obniz.led.off();
        obniz.display.drawing(false);
        obniz.display.clear();
        obniz.display.print("OFF🌩️");
        obniz.display.drawing(true);
      }
    };
  };
}

function keyPressed() {
  if (keyCode === LEFT_ARROW) {
    if (obniz.connectionState === "connected") {
      console.log("clicked!");
      obniz.led.on();
    }
  }
}
```

上記のエラー回避方法を使いつつ書きかえたプログラムを実行すると、無事に意図した通りの動作をさせられるのを確認できました。

## まとめ
今後、p5.js の描画まわりの処理を連動させるようなものや、[ml5.js](https://ml5js.org/) 等の [p5.js のライブラリ](https://p5js.org/libraries/)を組み合わせたものを何か試せればと思っています。