PubNubで5分でリアルタイムWebこと初め + MQTTでデバイス連携も #protoout #iotlt #ヒーローズリーグ


PubNubを使うと簡単にリアルタイムWeb的なものを作れます。老舗サービスですが今更ながらまとめてみます。[IoTLTで紹介した](https://speakerdeck.com/n0bisuke/pubnubwojiu-nishi-tutemitayo-number-iotlt-number-m5stick-number-pubnub-number-djuko)やつですね。

`#ヒーローズリーグ`のハッカソンでPubNubを触ったので改めてメモ。

> [M5Stackハッカソン](https://mashupawards.connpass.com/event/188452/)でやった内容メモです。

とりあえず簡単なリアルタイムWebとMQTTの利用を試してみます。

5分で、って書いたのは一旦ブラウザ上だけで試すところくらいまでです。

[SDKの数が多い](https://www.pubnub.com/docs/platform/home#all-sdks)ので色々なアプリケーションの接着剤的に使えるかなと思います。

## PubNubとは

PUbNubはリアルタイムなメッセージングやMQTTなどの裏側の仕組みを肩代わりしてくれるBaaSサービスです。

リアルタイムチャットなどでWebsocketやSocket.ioのサーバーを自前で用意しなくても、デバイスとのやりとりでMQTTブローカーを自前で用意しなくても良いという便利サービスです。

しかもけっこう無料で使えます。(そんなに調べてない)

## アプリケーション作成し、Pub/Subキーの取得

まずはアカウント作成しましょう。

> https://www.pubnub.com/

* ログイン後の画面

> ![スクリーンショット 2020-09-21 23.50.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/7b259fe7-02a3-d37d-a9e3-d1bc0a0d54db.png "スクリーンショット 2020-09-21 23.50.38.png")

* APP作成、 `CREATE NEW APP`から

> ![](https://i.gyazo.com/9a8555be9e1e5c1e2a7c48763c9e4c89.png)


今回M5Stackで使いたかったのでfor_m5stackというアプリ名にしました。`Chat App`と`
Other Messaging Use Cases`が選択できますが、 **`Other Messaging Use Cases`を選択します。**

まず試すだけだとこちらの方が入りやすいです。

> ![](https://i.gyazo.com/6f889bebbb2ce9a44faced03f0da2213.png)

作成したアプリを選択すると`Publish KEY`と`Subscribe Key`がわかります。

> ![](https://i.gyazo.com/e13ba6b4e0c33e33fd2a69f2e4df9ac6.png)

`Publish Key`と`Subscribe KEY`を記録しておきましょう。

## ブラウザで試す

まずはブラウザで簡単なメッセージングを試します。

PubNubはWebsocketの接続を提供してくれます。

**片方のブラウザを操作すると、もう片方のブラウザでも反応がある** といった仕組みをコピペで作ってみます。

### HTMLファイルの作成

index.htmlを作成、VScodeなどで作成しましょう。

![](https://i.gyazo.com/1f3beb091f427c248bb8e915a4eb3fb1.png)

キーは適宜変更しましょう。

```html
<!DOCTYPE html>
<html>
<head>
  <title>Publish Subscribe Tutorial</title>
</head>

<body>
<input id="publish-button" type="submit" value="Click here to Publish"/>
</body>

<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.21.7.min.js"></script>
<script>

  const uuid = PubNub.generateUUID();
  const pubnub = new PubNub({
    publishKey: "pub-c-xxxxxxxxxxxxxxx",
    subscribeKey: "sub-c-xxxxxxxxxxxxxxx",
    uuid: uuid
  });

  const button = document.getElementById('publish-button');

  button.addEventListener('click', () => {
    pubnub.publish({
      channel : "pubnub_onboarding_channel",
      message : {"sender": uuid, "content": "Hello From JavaScript SDK"}
    }, function(status, response) {
      //Handle error here
    });
  });

  pubnub.subscribe({
    channels: ['pubnub_onboarding_channel'],
    withPresence: true
  });

  pubnub.addListener({
    message: function(event) {
      let pElement = document.createElement('p');
      pElement.appendChild(document.createTextNode(event.message.content));
      document.body.appendChild(pElement);
    },
    presence: function(event) {
      let pElement = document.createElement('p');
      pElement.appendChild(document.createTextNode(event.uuid + " has joined. That's you!"));
      document.body.appendChild(pElement);
    }
  });

  pubnub.history(
    {
      channel: 'pubnub_onboarding_channel',
      count: 10,
      stringifiedTimeToken: true,
    },
    function (status, response) {
      let pElement = document.createElement('h3');
      pElement.appendChild(document.createTextNode('historical messages'));
      document.body.appendChild(pElement);

      pElement = document.createElement('ul');
      let msgs = response.messages;
      for (let i in msgs) {
        msg = msgs[i];
        let pElement = document.createElement('li');
        pElement.appendChild(document.createTextNode('sender: ' + msg.entry.sender + ', content: ' + msg.entry.content));
        document.body.appendChild(pElement);
      }
    }
  );

</script>
</html>
```

### 試す

[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)などでローカルサーバーを起動させてアクセスします。

> ![](https://i.gyazo.com/bfe5a16aac52d5ac809cfe12061febbb.png)

こんな表示になります。そして **複数のブラウザでアクセス**し、片方のボタンを押すと、もう片方にも反応があれば成功です。

> ![](https://i.gyazo.com/14eddc6e5ec621ecb8b4f3c460ed49e4.gif)

ブラウザ(クライアント)間でのメッセージングが出来ている状態です。

同じパソコン内でやってるとイメージがつきにくいかもしれないですが、別のパソコンやスマホ同士でも問題なく動作します。

## おまけ: MQTTも試す

ブラウザではWebSocketですが、デバイスに接続する際はMQTTも利用できます。

### mosquitto_pubとmosquitto_sub でMQTT確認

ここまでで一旦のメッセージングは

インストールはbrewで(macのみ)

```bash
$ brew install mosquitto
```

#### Subscribe(mosquitto_sub)

`n0bisuke`がクライアントID。任意の文字列で大丈夫。
`m5stack`がトピック名。これも任意の文字列で大丈夫。

```
$ mosquitto_sub -h mqtt.pndsn.com \
-t 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/m5stack' \
-i 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/n0bisuke' \
```

#### Publish(mosquitto_pub)

`n0bisuke`がクライアントID。任意の文字列で大丈夫。
`m5stack`がトピック名。これも任意の文字列で大丈夫。

```
$ mosquitto_pub -h mqtt.pndsn.com \
-t 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/m5stack' \
-i 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/n0bisuke' \
-m 'ほげほげ'
```

#### ためす

mosquitto_subを起動した状態で、mosquitto_pubを実行すると、-mで送ったメッセージ(今回はほげほげ)がmosquitto_sub側に表示されます。

> ![](https://i.gyazo.com/a9c39bfac860880244be66d84a1d764b.png)

#### Arduinoで試す

ESP32用ですが、Arduinoで試す方法もこちらに簡単にまとめてます。

> [M5Atom(Arduino)とPubNubでMQTTのサンプル #ヒーローズリーグ #protoout
](https://qiita.com/n0bisuke/items/bc9032fc5c92247c61da)

#### ブラウザ+デバイス(MQTT)

ブラウザとブラウザ(WebSocket)、デバイスとデバイス(MQTT)を試しましたが、ブラウザ+デバイスを試します。

先ほどのブラウザのコードを変えずに試してみます。

* ブラウザ -> デバイス

元々のコードでチャンネル(MQTT的にはトピック)が`pubnub_onboarding_channel`となっていました。なのでmosquitto_subでは以下のように設定して試してみましょう。

```
$ mosquitto_sub -h mqtt.pndsn.com \
-t 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/pubnub_onboarding_channel' \
-i 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/n0bisuke' \
```

ブラウザのボタンを押すと、mosquitto_subに反応があります。

> ![](https://i.gyazo.com/44c03c86759ac83f4793c8a7c3d34ac3.png)

* デバイス -> ブラウザ

デバイスからブラウザに送るときはmosquitto_pubで`{"content":"Hello!!! from MQTT!"}`といったメッセージを送るとブラウザ側にメッセージが表示されます。

```
$ mosquitto_pub -h mqtt.pndsn.com \
-t 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/pubnub_onboarding_channel' \
-i 'pub-c-xxxxxxxxxxxxxxx/sub-c-xxxxxxxxxxxxxxxx/n0bisuke' \
-m '{"content":"Hello!!! from MQTT!"}'
```

> ![](https://i.gyazo.com/c718296a0cfba49c19e5f1088b88cb6a.png)

## まとめ

* ブラウザ+ブラウザ
* デバイス+デバイス
* ブラウザ+デバイス (双方向)

を簡単に紹介しました。デバイスと言いつつMac上のMQTTクライアントなので実際にはデバイス側コードは各自試してみてください。

HTTPだけしか知らないと、デバイス+デバイスや、ブラウザ->デバイスはなかなか難しいのでIoT系の何かを作るときにも使えますし、デバイス無しでチャットアプリみたいなものを作るときも使えると思います。

使いこなしていきたい。