【IoTLT 2021】 ZIG SIM から送られるデータを p5.js Web Editor上で活用してみる

この記事は、[2021年の IoTLT のアドベントカレンダー](https://qiita.com/advent-calendar/2021/iotlt) の 5日目の記事です。

内容は、以下の記事を書いた時にも使った [ZIG SIM](https://zig-project.com/) の話がメインです。

●ZIG SIM と Node.js のプログラム（osc.js を利用）との間で UDP による OSC通信を軽く試す（OSC Data Monitor の話も） - Qiita
　https://qiita.com/youtoy/items/fddc750759f4ecef7ca7

これをブラウザ上で動く p5.js を使ったプログラムで活用します。
また、開発環境として  p5.js Web Editor を利用します。

## ZIG SIM について
ZIG SIM はプロトタイピングに便利なアプリで、2〜3年前くらいに知ったものの、あまり活用できていませんでした。
それを、ちょこちょこ試し始めて、冒頭に掲載した記事を書いたりしていました。

### 公式の紹介動画
以下は、公式の紹介動画です。

<iframe width="560" height="315" src="https://www.youtube.com/embed/i6pv5nflEmc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

### 利用事例
[Twitter で #ZIGSIM のハッシュタグで検索をする](https://twitter.com/search?q=%23ZIGSIM&src=typed_query&f=live)と、活用された方の事例がを見ることができます。
ざっくり見ると、TouchDesigner と合わせて使っている例が多い気がします。

## ZIG SIM をブラウザ上で動く JavaScript のプログラムで扱う
### ZIG SIM で使われる通信
ZIG SIM のアプリの設定では、通信プロトコルで「UDP」か「TCP」を選ぶことができ、メッセージのフォーマットは「JSON」か「OSC」のどちらかを選ぶことができます。
![設定画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/80c709b9-9815-dc02-d871-5ba684af0a61.jpeg)

このような通信方法になるため、ブラウザ上で動く JavaScript のプログラムでは、直接データを受けとることができません（ブラウザが、UDP・TCP を直接扱えないため）。

冒頭に記載した記事で、osc.js を使った ZIG SIM との通信を試していましたが、その理由の1つが「osc.js で OSC over UDP を OSC over WebSocket に変換」して、ブラウザ上で動くプログラムと ZIG SIM との間の通信を実現する、というものでした。

### zigsim-ws
そんな中、以下のリポジトリを見つけました。

●acrylicode/zigsim-ws
　https://github.com/acrylicode/zigsim-ws
![説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/816510bb-3642-a15c-2b7b-bf9c1126d96b.jpeg)

こちらの「How does it work ?」の部分やソースコードを見てみると、仕組みは ZIG SIM から UDP で送られてくるデータを受信し、それを WebSocket で送り出す、という仕組みのようです。

使い方は非常に簡単で、以下を実行するだけです。

1. `npm install zigsim-ws` を実行
2. 以下の内容のプログラムを作成する
3. プログラムを実行する

zigsim-ws を使うためのプログラムは、以下の通りです。

```javascript
const zigsimWs = require("zigsim-ws")

zigsimWs.init();
```

プログラムを実行すると、以下のようなメッセージが表示されます。
![プログラムの実行結果.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9e7358fe-91da-927f-f6b4-0a7cd6ade523.jpeg)
ZIG SIM からのデータを 50000番ポートで待ち受け、それを WebSocket でクライアントへと送ります。
ここで書いたクライアントは、8080版ポートで待ち受けをしている WebSocketサーバーに接続に来たクライアントを意味します。

### ZIG SIM と p5.js を使ったプログラムとの通信1
これで、ZIG SIM のデータを WebSocketサーバーに接続したクライアントへ送ることができるようになりました。

ZIG SIMアプリで、「プロトコル： UDP」・「メッセージフォーマット： JSON」に設定してデータの送信を行い、 p5.js Web Editor上では、WebSocketサーバーからメッセージを受信するプログラムを動かします。

p5.js Web Editor で扱うプログラムは、以下の記事を書いた時に作ったものを利用します。
 ●p5.js Web Editor で WebSocket を扱ってみる（wscat でローカル環境にサーバーを準備して試したり、OBS連携を実行） - Qiita
 　https://qiita.com/youtoy/items/40220a09b98a89013d0d

少しだけ手を加え、以下のような処理にしました。

```javascript
let socket;

function setup() {
  createCanvas(400, 400);
  background(220);
  noLoop();

  socket = new WebSocket("ws://localhost:8080");

  socket.addEventListener("open", function (event) {
    console.log("OK!");
  });

  socket.addEventListener("message", function (event) {
    const receivedData = event.data;
    console.log("Message from server ", receivedData);
  });
}

function draw() {}
```

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/ZIGSIM?src=hash&amp;ref_src=twsrc%5Etfw">#ZIGSIM</a> アプリのデータを、 <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> Web Editor上で受けとれた！<br>とりあえず、受けとった JSON をログで出力しただけ、という感じのものだけれど。<br><br>仲介役として、zigsim-ws を使っています。<br>　<a href="https://t.co/uHPDelnALV">https://t.co/uHPDelnALV</a> <a href="https://t.co/rHc0KeNMQk">pic.twitter.com/rHc0KeNMQk</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1467190078766485504?ref_src=twsrc%5Etfw">December 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### ZIG SIM と p5.js を使ったプログラムとの通信2
次はこちらです。
先ほどの p5.js を使ったプログラムに、少し手を加えてみました。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/ZIGSIM?src=hash&amp;ref_src=twsrc%5Etfw">#ZIGSIM</a> アプリの 2Dタッチの座標データを、 <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> Web Editor上で受けとって、キャンバス上に描画してみた！ <a href="https://t.co/Q85FgPfXZl">pic.twitter.com/Q85FgPfXZl</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1467207744713535488?ref_src=twsrc%5Etfw">December 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

プログラムは、このような感じです。

```javascript
let socket,
  x = [0, 0, 0, 0, 0],
  y = [0, 0, 0, 0, 0];
const colors = ["#6E3CBC", "#7267CB", "#98BAE7", "#B8E4F0"];

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

  socket = new WebSocket("ws://localhost:8080");

  socket.addEventListener("open", function (event) {
    console.log("OK!");
  });

  socket.addEventListener("message", function (event) {
    const receivedData = JSON.parse(event.data);
    // console.log(receivedData);

    const touchData = receivedData.sensordata.touch;
    // console.log(touchData);
    for (let i = 0; i < 5; i++) {
      if (i < touchData.length) {
        x[i] = map(touchData[i].x, -1, 1, 0, width);
        y[i] = map(touchData[i].y, -1, 1, 0, height);
      } else {
        x[i] = undefined;
        y[i] = undefined;
      }
    }
  });
}

function draw() {
  background(220);

  for (let i = 0; i < 4; i++) {
    fill(colors[i]);
    ellipse(x[i], y[i], 50);
  }
}
```

## おわりに
ZIG SIM から送られるデータを、zigsim-ws を介して p5.js Web Editor上で受信し利用することができるようになりました。

今回使った zigsim-ws のソースを見てみると、わりとシンプルな実装になっていたため、このプログラムに直接手を入れて活用するようなこともできればと思っています。
●zigsim-ws/index.js at master · acrylicode/zigsim-ws
　https://github.com/acrylicode/zigsim-ws/blob/master/index.js