p5.js Web Editor で MQTT を扱ってみる（MQTT.js や shiftr.io Desktop を利用）

今回の内容は、以下の記事の別バージョンのようなものです。

●p5.js Web Editor で WebSocket を扱ってみる（wscat でローカル環境にサーバーを準備して試したり、OBS連携を実行） - Qiita
　https://qiita.com/youtoy/items/40220a09b98a89013d0d

上記では WebSocket を使ってリアルタイム通信を行っていましたが、今回は MQTT を利用します（とは言いつつ、MQTT の通信を支える部分は、今回 WebSocket が担うというややこしい感じの形なのですが...）。

今まで、リアルタイム通信を利用したガジェット・サービス連携を行う際は、WebSocket を使うよりも MQTT を使うことが多かったです（例えば、M5Stack＋UIFlow というデバイス＋開発環境の組み合わせを使う場合は、MQTT用の処理が用意されるという場合もあったり）。
それについて、例えば、以下が過去に書いた Qiita の記事で MQTTが関連するものです。

●「mqtt user:youtoy」の検索結果 - Qiita
　https://qiita.com/search?sort=&q=mqtt+user%3Ayoutoy

その中で使ってきた仕組み（MQTTブローカーや MQTT用のライブラリ等）を用いて、p5.js Web Editor上での MQTT利用を試してみます。

## 今回 MQTT を利用する際の構成
### MQTT関連のサービスやライブラリ
上で出てきた WebSocket を利用する場合も WebSocketサーバーが必要になりますが、MQTT を利用する場合も同様です。
MQTT の場合は「MQTTブローカー」と言われたりします。

MQTTブローカーは自分でたてる方法もありますが、無料で使えるオンラインサービスやデスクトップアプリとして動かせるものがあったりします。
過去に試したものはいろいろありますが、自分が複数回利用したものをいくつか抜き出すと、以下のようになります。

- [shiftr.io](https://www.shiftr.io/)
   - [無償枠ありのクラウド版 MQTTブローカー](https://www.shiftr.io/cloud/)
   - [ローカルで動作させられるデスクトップ用アプリ](https://www.shiftr.io/desktop)
- Beebotte
   - [無償枠ありのクラウド版](https://beebotte.com/)
- [Eclipse Mosquitto](https://mosquitto.org/)
   - [ローカル版](https://mosquitto.org/download/)
- Aedes
   - [GitHubリポジトリ](https://github.com/moscajs/aedes)
   - [Node-RED用のノード](https://flows.nodered.org/node/node-red-contrib-aedes)

また、クライアント側を実装する際のライブラリで、自分が複数回利用したものもいくつか記載してみます。

- [MQTT.js](https://github.com/mqttjs/MQTT.js)
- [Aedes](https://github.com/moscajs/aedes)
- [Eclipse Mosquitto](https://mosquitto.org/)

### 今回用いるもの
上記のとおり、MQTTブローカーもライブラリもいろいろありますが、今回は以下の構成で試してみようと思います。

- MQTTブローカー： shiftr.io Desktop
- p5.js Web Editor で利用するライブラリ： MQTT.js

## 実際に試していく
### MQTTブローカーの準備
デスクトップ上で動作する MQTTブローカーをダウンロードするため、以下のページへアクセスします。

●Desktop - shiftr.io
　https://www.shiftr.io/desktop

ページ内の以下から、自分が使っている OS に合わせたファイルをダウンロードしてください。
自分は Mac用のもので DMG のほうを使っています。
![デスクトップ版アプリ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/20e045ed-04bb-bcb9-965d-b67401d4c5ef.jpeg)

ダウンロードとインストールを行い、アプリを起動します。
以下の画面が表示されれば OK です。
![MQTTブローカーの機動.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/64c59cd6-b9a3-a2d8-2c61-eeb68b699af1.jpeg)

#### 利用するポートについて
MQTTブローカーにクライアントからアクセスする際、接続先のポートも指定する必要があります（※ デフォルト設定のポートと一致していれば、省略できる場合もありますが）。
ここで、shiftr.io Desktop が使うポートについて補足しておきます。

公式ドキュメントの以下の部分に書かれている内容です。

●MQTT Interface - shiftr.io
　https://www.shiftr.io/docs/broker/mqtt-interface
![ポートについて.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/0bc4a9ed-d9d3-a2ca-f404-3d662d59d15c.jpeg)

上の画像の下側に書いてある話で、shiftr.io Desktop が利用するポートは 1883 と 1884 の2つがあり、1883 は TCP によるもの、1884 は WebSocket（WS/HTTP）によるものと書いてあります。
今回はブラウザで MQTT.js　のクライアントを動かす形ですが、その場合は TCP は使えないため WebSocket による通信が行われます。

そのため、今回のブラウザ上の処理で接続先を指定する際は、ポート番号を 1884　にする必要があります。

### p5.js Web Editor のプログラム
以下の公式サンプルを参考にしつつ、MQTT での通信を行うプログラムを書いていきます。

●mqttjs/MQTT.js: The MQTT client for Node.js and the browser
　https://github.com/mqttjs/MQTT.js#webpack

#### ライブラリの読み込み
その前に、p5.js Web Editor上でライブラリを読み込む必要があるので、その対応を行います。
ライブラリは、以下の公式ページに書かれた CDN のもの（クラウド上にあるもの）を利用します。

●mqttjs/MQTT.js: The MQTT client for Node.js and the browser
　https://github.com/mqttjs/MQTT.js#via-cdn

HTML の中に、以下の 1行を追加します。

```html
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
```

具体的には、p5.js Web Editor で「index.html」を表示させ、その中の p5.js 等を読み込ませている部分の下に上記の 1行を追加してやります。
![ライブラリの読み込み.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/cad47bcd-7408-33c5-5766-a87be7915234.jpeg)

#### プログラムの内容
上記の対応が終わったら、今度は p5.js Web Editor上で「sketch.js」を表示させ、そこにプログラムを書いていきます。

以下の2行目に出てくる「TOPIC」というのは、MQTT でメッセージを送受信する時に使う仕組みに関係する部分ですが、今の事例の中では「メッセージを送受信したいクライアント同士で、同じものを指定する部分」という感じの認識で大丈夫です。
かなりざっくりな書き方なので、もっときちんと知りたいという方は、例えば以下のリンク先をご覧いただくと便利に使う方法などが分かるかもしれません。
　●初めての MQTT > Topic
　https://gist.github.com/voluntas/89000a06a7b79f1230ab#topic

その他の補足は、プログラムを書いた後に記載していきます。

```javascript
let client;
const TOPIC = "test";

function setup() {
  const MQTTURL = "ws://localhost:1884";

  createCanvas(400, 400);
  background(220);
  noLoop();

  client = mqtt.connect(MQTTURL);

  client.on("connect", function () {
    console.log("接続完了");
    client.subscribe(TOPIC);
  });

  client.on("message", function (topic, message) {
    console.log(`受信： ${topic} ${message}`);
  });
}

function draw() {}

function keyPressed() {
  switch (key) {
    case "1":
      console.log("送信： Hello!!");
      client.publish(TOPIC, "Hello!!");
      break;
    case "2":
      console.log("送信： Hi!!");
      client.publish(TOPIC, "Hi!!");
      break;

    default:
      break;
  }
}
```

MQTTブローカーの接続設定をしている部分は `"ws://localhost:1884";` という部分です。
上で書いたとおり、ポート番号は 1884 となります。また、ブラウザで通信させる場合は WebSocket を使うので、 `ws` で始まる形です。

`client.on("connect", ...` という部分は、MQTTブローカーとの接続が確立された際に呼ばれる処理で、 ` client.on("message", ...` の部分は MQTTブローカーからメッセージを受信した際に呼ばれる処理です。
前者の処理部分では、 `client.subscribe(TOPIC);` という処理で、特定のトピック（今回は `const TOPIC = "test";` で指定した「test」という文字列）のメッセージを受信するようにしています。

そして、キーが押された時に実行される処理部分で、 `client.publish(TOPIC, "...");` という部分がありますが、この部分は MQTTブローカーに対して「test」というトピックで「Hello!!」や「Hi!!」という文字列をメッセージで送る処理です。
今回、送り側も受け側も p5.js Web Editor上で書いた同一のクライアント、という形になるため、送られたメッセージは自分自身で受信するような形になります。

それと用語に関する補足ですが、受信のための処理は「Subscribe」・送信のための処理は「Publish」と言ったり、送受信を「Pub/Sub」と言ったりします。

#### プログラムを実行する
ここで、p5.js Web Editor で書いたプログラムを実行してみます。

実行をした直後、shiftr.io Desktop上の表示が、以下のように変化します。
![クライアントが接続した状態.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3cb609e6-31cb-1f91-7a33-03f37d9ba748.jpeg)
クライアントが 1つ接続してきた、という意味の表示です。

さらに、 `function keyPressed()` の中で指定している数字キー（「1」と「2」のキー）を押してみます。

例えば「1」のキーを押すと、shiftr.io Desktop上でメッセージがやりとりされた情報が以下のように表示されます。
![数字の1を押した時.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/80dc4999-d5ea-8380-ca3e-af97e737ef3c.jpeg)
また、p5.js Web Editor のコンソールでは、以下が出力されます。
![数字の1を押した時（コンソール）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/28615f63-4566-12be-38f3-e7806e614949.jpeg)

そして「2」のキーを押すと、shiftr.io Desktop上と p5.js Web Editor のコンソールで以下の表示・出力が行われます。
![数字の2を押した時.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/418f9050-acf1-4df9-7598-6c8071f8f030.jpeg)
![数字の2が押された時（コンソール）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3043a0a6-4e1e-4291-c6e3-dd1e6b1058f8.jpeg)

先ほどとトピック（「test」という文字列の部分）は同じですが、送受信されたメッセージは「Hello!!」ではなく「Hi!!」になっているのが分かります。

何らかサービス間・デバイス間連携をするときは、それらの間で共通のトピックの文字列を設定しつつ、そこでやりとりするメッセージは「Hello!!」や「Hi!!」といった適当な内容ではなく、良い感じの分かりやすい・使いやすい内容に変えてしまってください。

## まとめ
今回は p5.js Web Editor上で、サービス間・デバイス間連携を行う際に便利な MQTT による通信を組み込んでみました。

ただし、その通信の送り側も受け側も今回は同一のクライアントという形だったので、サービス間・デバイス間連携を実装した事例も、別で試して記事にできればと思います。

## 【追記】 MQTT で 2台のデバイス間をつなぐお試し
その後、MacBook と iPad、また 2台のスマホを、それぞれ連動させるようなことを試してみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">先日、 <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> のプログラムにリアルタイム通信の仕組み（WebSocket、MQTT）を試しに組み込んだものを活用して、MacBook と iPad の間でのリアルタイム通信を試した！<br><br>MacBook のブラウザと iPad のブラウザの表示領域との間を、動く円が行き来するような表示がされるプログラムを書いてみた。 <a href="https://t.co/DgHpIdBljF">pic.twitter.com/DgHpIdBljF</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1428759249291677696?ref_src=twsrc%5Etfw">August 20, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">この前試した、 <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> とリアルタイム通信（MQTT）の組み合わせで MacBook と iPad のそれぞれの画面間をつないだような処理をやった話の発展形！<br><br>今度は、スマホ 2台の画面をつないだのですが、その2つの画面のつながる方向が、動的に縦方向だったり横方向だったり、変化するような実装にしてみた！ <a href="https://t.co/WmCev0oBfx">pic.twitter.com/WmCev0oBfx</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1430905469149663240?ref_src=twsrc%5Etfw">August 26, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>