ESP32 + Noodl + MQTTでpub/subを試してみる

# ESP32 + Noodl + MQTTでpub/subを試してみる

## 初めに
以前ESP-WROOM-02はよく触っていましたが、新しくなったESP-WROOM-32（以降ESP32と記述）は持っていませんでした。なので最近日本に展開され始めたNoodlと組み合わせ、MQTTプロトコルを使用し動作させてみました。

# Noodl

## Noodlとは
エンジニアでなくても比較的簡単にビジュアルデザインとアプリ、IoT・センサーをつなぐUI/UXプロトタイピングツールで、ビジュアルプログラム言語に近いイメージです。
もともとスウェーデンのデザインファームTOPP社が提供しており、2019年6月に日本で展開され始めたばかりなので比較的新しいノンプログラミングツールです。

[公式リンク](https://tensorx.co.jp/noodl-jp/)

## 使い方 
Noodlをダウンロードしログインを行うとトップ画面に遷移します。

[ダウンロードリンク](https://classic.getnoodl.com/download)


そこから簡単なチュートリアル（英語）を行えるのでこれでイメージがつかめると思います。


![チュートリアル.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/25e7d3d6-84b8-5192-0f4d-99a019c42f49.png)



# MQTT（Message Queueing Telemetry Transport）
今回はHTTPではなく、MQTTというプロトコルを使用し通信を実装します。

## MQTTとは
TCP/IPネットワークで利用できる通信プロトコルでM2MやIoTを実現するのに適した非常に軽量なプロトコルです。


## 特徴

- Publish/Subscribe
送信者（Publisher）と受信者（Subscriber）は直接やり取りせずに、Broker（仲介役）を経由し通信を行います。


- ヘッダーが軽量
ヘッダー容量を最小で２バイトまで絞ることが可能です。これにより軽量な通信が可能になります。



- 双方向の通信が可能
MQTTでは1つのデバイスが同時にPublisher/Subscriberのどちらにもなることができるため、双方向の通信も可能です。



- 故障や切断を想定した機能
    - Retain
    PublishされたメッセージをBrokerに残しておくことができ、Subscriberの接続が一時的に切れていても再受信が可能です。
    - Will
    遺書と呼ばれる機能で、Subscriberの接続が切れた時に特定のメッセージを自動で通知することができます。


# ESP32
ESP32はEspressif Systems社が開発しているWiFiとBluetoothを内蔵したSoCのマイクロコントローラーです。
ESP02と比較し、金額はほんのわずかにESP32のほうが高いですが、スペックはほぼ上位互換です。またESP02と同じようにArduinoIDEでの開発が行えるのも特徴です。

今回使用した開発キットはESP-32S NodeMCU開発ボード2.4GHzを使用しました。Amazonで800円ほどで購入できました。



![ESP32.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/e8771ace-4b80-375d-34ba-db0bb84e6c2c.png)


[データシート](https://www.es.co.th/Schemetic/PDF/ESP32.PDF)



# shiftr.io
無料で使用できるMQTTサーバーで今回はBrokerの役目を担います。
設定手順はシンプルで[shiftr.io](https://shiftr.io/)にアクセスしユーザー登録、ログイン後、Namespaceを作成し、TokenにFullAccessを付与するだけで、shiftr.ioのMQTTサーバーURLが発行されます。
これでMQTTサーバーの設定は完了です。



![shiftr.io.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/d68d8740-b9f4-8ec6-af5a-68936e86242a.png)


# 全体構成
![全体構成図.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/f74d579b-25bc-5669-0590-2ad005fd4dc0.png)

NoodlでPublisherを担い、broker(shiftr.io)を経由しESP32にメッセージを送ります。

# Noodlの設定
今回のNoodl構成はcircleをTapするとsendMessageイベントが走るように設定します。

![Noodl_setting.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/9ac0a8ef-dece-61d0-9831-61cfae51acbd.png)



またプロジェクトの設定からBroker URLの欄にshiftr.ioで取得したURLを入力します。

この状態でデプロイを行うとshiftr.ioのダッシュボードで接続が確認できると思います。


# ESP32とshiftrの接続
ESP32の書き込みはArduinoIDEで行います。
今回はシリアルモニターで受信した文字列を確認します。

```
#include <MQTT.h>
#include <MQTTClient.h>
#include <WiFi.h>

/* WiFiの設定 */
const char ssid[] = "xxxxxxxxxx";
const char pass[] = "xxxxxxxxxx";

WiFiClient net;
MQTTClient client;

void connect() {
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.print("\nconnecting...");

  /* 
   shiftr.ioで発行されたURL内のパラメーターを入力
   mqtt://xxx:ooo@broker.shiftr.io
  */
  while (!client.connect("arduino", "xxx", "ooo")) {
    delay(1000);
  }

  Serial.println("connected");

  client.subscribe("/hello");
}

void messageReceived(String &topic, String &payload) {
  Serial.print("topic: " + topic);
  Serial.println("payload: " + payload);
}

void setup() {
  WiFi.begin(ssid, pass);
  client.begin("broker.shiftr.io", net);
  client.onMessage(messageReceived);

  connect();

}

void loop() {
  Serial.begin(115200);
  client.loop();
  delay(100);

  if (!client.connected()) {
    connect();
  }

}
```


# 疎通確認

ここまでで以下のような役割で構築してきたので疎通確認を行います。

| 送信者（Publisher） | 仲介（Broker） |受信者（Subscriber） |
| ------------- | ------------- |------------- |
| Noodl  | shiftr.io  | ESP32  |



すべて正常に接続されていると画像のようにボタン押下からBrokerを介してESP32のシリアルモニターにデータが受信できているのを確認できると思います。


![疎通確認.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320055/21ed4284-5684-6267-a2cb-29b432d78400.gif)



# おわりに
やはりESP32はArduinoで開発するほうが、学習コストが少なくやりやすい印象を受けました。

また今回使用したNoodlのようなビジュアルプログラミング言語がもう少し普及し、使用できるブロックを公開しライブラリの用な位置づけで開発ができる面白いと感じました。

今回Subscribeが一台のみの構成でしたがMQTTのメリットを生かすのであれば複数台から小さいデータを大量にもらいたいなどの用途で使用するのがいいと思います。