Ⅰ. ESP32によるMQTTアプリケーション開発の基礎知識

 MQTTはHTTPに比べて圧倒的に軽量であることから、IoT(Internet of Things)やM2M(Machine to Machine)など、メモリの制約がきつかったりネットワーク帯域幅が限られているような環境での利用に適しています。また非同期で1対多の通信ができるのも大きな特長です。
 実際に実験してみると、HTTPとの比較はさておき、ほとんどプロトコルの詳細を知らなくても利用できたり、メッセージのルーティングがとても簡単にできてしまうのが印象的です。


1.MQTTとは

 MQTTはTCP/IPプロトコル上で動作する軽量なプロトコルです。1999年にIBMによって作成され、2013年にOASIS(Organization for the Advancement of Structured Information Standards: 構造化情報標準促進協会)にバージョン3.1が提示されました。現在使用されているのは2014年に制定されたv3.1.1ですが、2019年4月には大幅な改善を伴ったv5.0が登場していっそうの利用拡大が期待されています。
 名前はMessage Queuing Telemetry Transportの略称ですが、開発経緯に由来するものであり、その名前にもかかわらずメッセージキューの機能はもっていません。
 特長を列記すると
 ・プロトコルがシンプル
   HTTPなどに比べるとパフォーマンスが高い。
 ・軽量である
   最小ヘッダーサイズが2byteと小さい。
   制約が厳しいデバイスや帯域幅が限られたネットワーク上でも実装できる。
 ・Publish/Subscribeシステム
   柔軟性の高いメッセージ配布が可能。
 ・非同期メッセージング
   スケーラビリティの面で優れる。
 ・データ長に幅がある
   最大253MBまで可能。IoTではデータ長の短縮が課題で、このサイズは十分。
などがあげられます。
 詳細は次節で説明しますが、MQTT通信ではブローカーと呼ばれる仲介サーバーを使用します。情報を発信するクライアントは、情報のカテゴリーを示すトピックを付けてブローカーにメッセージを送信します。別の複数のクライアントは、このトピックを指定することでブローカーからそのメッセージを受信することができます。
 MQTTは情報をプレーンテキストで送信するので、機密性を要するアプリケーションではTLS(Transport Layer Security: トランスポート層セキュリティ)の使用が推奨されています。ただし、大幅なオーバーヘッドの増加を伴うため、本来のメリットとのトレードオフに注意する必要があります。


2.MQTTの基本概念

 MQTT通信システムの実験を行うにあたって、次のような基本概念を理解しておく必要があります。
○メッセージ(Message)

 MQTT通信の基本となる単位がメッセージです。データかコマンドかを問わず、デバイス間で交換される情報を意味します。メッセージは、それを仕分け・識別するためのキー情報「トピック」を伴います。

○トピック(Topic)

 メッセージ送受信のキーになる情報で、そのメッセージの種類を指定するものです。下の例のように、/(スラッシュ)で区切られた階層構造で指定することができます。メッセージをPublish(送信)する時もSubscribe(受信)する時も、必ずトピックを指定する必要があります。
  (例)                                                   
     tokyo/1F/temp  東京オフィス1階の温度
     tokyo/1F/humd東京オフィス1階の湿度
     tokyo/2F/temp東京オフィス2階の温度
     tokyo/2F/humd東京オフィス2階の湿度
     osaka/8F/temp大阪オフィス8階の温度
     osaka/8F/humd大阪オフィス8階の湿度
     osaka/9F/temp大阪オフィス9階の温度
     osaka/9F/humd大阪オフィス9階の湿度
 オフィスのそれぞれの階のクライアント(センサーデバイス)は、自身のトピックを付けて計測値をPublishします。受信したいクライアントは、必要なトピックを指定することでそのデータを受信することができます。なお、受信側ではトピックにワイルドカード(#,+)を指定することもできます。
  (例)            
     +/+/tempすべてのオフィスとフロアの温度情報を得たい
     osaka/#  大阪オフィスだけの計測情報を得たい

○パブリッシュ(Publish)/サブスクライブ(Subscribe)モデル

  MQTTの基本となる通信の仕組みで、ちょうど書籍の流通に似た方法で情報を伝達します。情報を送信するクライアントはパブリッシャー(Publisher)とも呼ばれ、トピックと共にメッセージを出版(Publish)します。送信先を特定するのでなく、ブローカーという書籍の中継ぎ店的なサーバーに向けて送りつけます。その店に加盟しているクライアント、つまりブローカーに接続されているサブスクライバー(Subscriber)と呼ばるクライアントは、購読(Subscribe)したいトピックを指定して情報を受信することができます。
 このように、Publisherは宛先を限定せずに情報を発信して、複数のSubscriberは、それぞれが関心のあるメッセージだけをトピックで選択して受信することができます。

 さらに、それぞれのクライアント(Device)は、PublisherにもSubscriberにもなることができます。これによって、次図のように多対多の相互通信網を構成することが可能になります。ただし、特定のデバイスを指定した通信はできません。また、ブローカーにはメッセージの蓄積機能がないため、過去のメッセージをSubscribeすることはできません。PublisherとSubscriberはそれぞれ独立していて、Publisherにアクセス情報が通知されることはありません。


○ブローカー(Broker)

  MQTT通信の結節点を構成するサーバーです。ブローカーはすべてのメッセージの受信、フィルタリング、トピックに関心をもつデバイスの決定、そしてSubscribeしているすべてのクライアントへのメッセージ送信を担います。
 OSS(Open Source Software)のMQTT Brokerもたくさんあり、それぞれ実装している機能や仕様に違いがあるので事前に検討が必要です。

 以上からわかるように、MQTTの大きな特徴は、従来のクライアント/サーバーアーキテクチャーと異なり、受信者とメッセージの発行者が分離されていることです。パブリッシャーとサブスクライバーはお互いを知る必要がありません。それらの間の接続はブローカーによって処理されます。


3.サービス品質(QoS)

 QoSとはQuality of Service(サービスの品質)のことで、メッセージ配信についての品質保証レベルを意味します。送信中にエラーが発生した場合に、どこまで伝達を保証するかを次の3段階で指定することができます。それぞれの図でやり取りしているパケットについては、「5.プロトコルの概要」を参照してください。
 ・QoS0: At most once
   最高1回は配信されます。メッセージが送信先に確実に届くかどうかの保証はされません。

 ・QoS1: At least once
   最低1回は配信されます。確実に届くが、メッセージが重複して届く可能性があります。

 ・QoS2: Exactly once
   正確に1回配信されます。重複なく届くことが保証されますが、品質が高い反面、通信回数が増えて遅くなります。

 QoSはPublisher側とSubscriber側でそれぞれ指定します。Publisher側のQoSレベルよりよりSubscriber側のQoSレベルの方が低い場合はレベルダウンが発生して、Subscriber側のレベルに下げられます。また、ブローカーによってはQoSの3つのレベルすべてに対応しているとは限らないので注意が必要です。
 あまり厳密さを必要としない(時にはデータが脱落することも許容できる)データの伝送などではQoS0を指定し、重複もロストも許されないようなシーンに限定してQoS2を指定するといった感じでしょうか。


4.その他の補助機能

 MQTTにはその他にも次のような機能があります。
○キープアライブ機能

  MQTTには、一定の時間内にクライアントからのメッセージ送信がない場合に、コネクションが切れていないかを監視する方法が定められています。CONNECTコマンドでKeep alive timerに監視時間を秒で設定します。この値のおよそ1.5倍の時間内にメッセージ送信がないと、コネクションは自動的に切断されます。これを避けたい場合は、時間内にPINGREQコマンドを送信する必要があります。
 キープアライブが未設定または時間間隔がゼロの場合は、この機能は無効になります。

○LWT(Last Will and Testament)

  Publisherは、MQTTブローカと接続したときに「Last Will and Testament(遺言)」という情報を追加することができます。意図しない原因でPublisherと通信できなくなった場合に、MQTTブローカはLWTに指定されたメッセージをSubscriberへ送信します。
 Subscriberはこのメッセージを受信することで、受信対象のPublisherが停止していることがわかります。CONNECTコマンドに先立って設定します。

○Retain

  MQTTはPublish/Subscribeモデルなので、Publishした時にSubscribeしているクライアントにメッセージが届きます。したがって、タイミングがずれてSubscribeを開始すると、次のPublishが行われるまでクライアントにはメッセージが届きません。
 状況によっては(Publishのインターバルが長い場合など)、無応答のような状況が発生します。これを避けるために、Retain機能を使用すると、ブローカーは最後にPublishされたメッセージを保持して、新しいSubscribeを受けるとそのメッセージを通知します。

5.プロトコルの概要

 MQTTのプロトコルは、14種類のメッセージ・タイプから構成されています。OASIS資料『MQTT Version 3.1.1 OASIS Standard』で次のように規定されています。

 Name Value Direction  Description
CONNECT  1 Client→Server クライアントがサーバーへの接続を要求
CONNACK  2 Server→Client 接続確認応答
PUBLISH  3 Client→Server メッセージのパブリッシュ
PUBACK  4 Client⇔Server パブリッシュ確認応答
PUBREC  5 Client⇔Server パブリッシュの受信 (送達保証 パート 1)
PUBREL  6 Client⇔Server パブリッシュ のリリース (送達保証 パート 2)
PUBCOMP  7 Client⇔Server パブリッシュの完了 (送達保証パート 3)
SUBSCRIBE  8 Client→Server クライアント・サブスクライブ要求
SUBACK  9 Server→Client サブスクライブ確認応答
UNSUBSCRIBE 10 Client→Server クライアント・アンサブスクライブ要求
UNSUBACK 11 Server→Client アンサブスクライブ確認応答
PINGREQ 12 Client→Server PING 要求
PINGRESP 13 Server→Client PING 応答
DISCONNECT 14 Client→Server クライアント切断中

 ブローカーを挟んで、パブリッシャーとサブスクライバーとの間でのメッセージのやり取りは、概ね次のようになっています。

 IBM資料 developerWorks『MQTT の基本知識』には、メッセージ・タイプの主なものについて機能とパラメーターが解説されています。簡単に紹介しておきましょう。
 1). CONNECTメッセージとパラメーター
  クライアントからブローカーへの接続を確立するためのもの。
   ・cleanSession: このフラグは、接続を持続させるかどうかを指定します。
   ・username: ブローカーの認証・許可資格情報
   ・password: ブローカーの認証・許可資格情報
   ・lastWillTopic: 接続が予期せずに中断された場合、ブローカーは自動的に「last will」
    メッセージをトピックにパブリッシュします。
   ・lastWillQos: 「last will」メッセージの QoS
   ・lastWillMessage: 「last will」メッセージ自体
   ・keepAlive: クライアントが接続を維持するためにブローカーに対して ping を実行する
    時間間隔を指定します。
 2). CONNACKメッセージとパラメーター
  クライアントはブローカーから CONNACK メッセージを受信します。
   ・sessionPresent: この接続ですでに持続セッションが行われているかどうかを示します。
    つまり、この接続はトピックをサブスクライブ済みであり、送受信に失敗したメッセージ
    が配信されます。
   ・returnCode: 0 は成功を意味します。その他の値は、エラーの原因を識別します。
 3). SUBSCRIBEメッセージとパラメーター
  接続の確立後、クライアントは特定のトピックに関するメッセージをブローカーから受信する
  ことを示すために、1 つ以上の SUBSCRIBE メッセージをブローカーに送信できます。
   ・qos: qos (サービス品質: QoS) フラグは、このトピックに属するメッセージを、どの程度
    の確実さでクライアントに配信するかを指定します。
      • 値 0: 確実ではありません。メッセージは最大 1 回配信され、その時点でクライアン
       トが利用できない状態であれば、メッセージは配信されません。
      • 値 1: メッセージは少なくとも 1 回配信される必要があります。
      • 値 2: メッセージは 1 回だけ配信される必要があります。
   ・topic: サブスクライブ対象のトピック。
 4). SUBACKメッセージとパラメーター
  クライアントが正常にトピックをサブスクライブすると、ブローカーは 1 つ以上の returnCode
  パラメーターを設定した SUBACK メッセージを返します。
   ・returnCode: SUBCRIBE コマンド内で指定されたトピックごとに 1 つの戻りコードが存在し
    ます。
    以下の戻りコードがあります。
      • 値 0 ~ 2: 対応する QoS レベルで成功 (QoS の説明については、3 を参照)。
      • 値 128: 失敗。
 5). UNSUBSCRIBEメッセージとパラメーター
  SUBSCRIBE メッセージに対応するメッセージとして、クライアントは UNSUBSCRIBE メッセージを
  送信して 1 つ以上のトピックからサブスクリプションを解除することもできます。
   ・topic: 複数のトピックがある場合、このパラメーターが繰り返されます。
 6). PUBLISHメッセージとパラメーター
  クライアントは、PUBLISH メッセージをブローカーに送信できます。このメッセージには、トピッ
  クとデータ・ペイロードが含まれます。ブローカーは、そのトピックをサブスクライブしているす
  べてのクライアントにメッセージを転送します。
   ・topicName: パブリッシュされるメッセージが属するトピック。
   ・qos: メッセージ配信のサービス品質レベル。
   ・retainFlag: ブローカーがメッセージをこのトピックで最後に既知となったメッセージとして
    保存するかどうかを指定します。
   ・payload: メッセージに含まれる実際のデータ。テキスト文字列またはデータのバイナリー BLOB
    のいずれかです。


 今回はMQTTについての基礎的な事柄を取りまとめました。
 次回は実験全体の内容について検討し、Raspberry Piがブローカーとして動作するよう、Mosquitto Brokerをインストールする予定です。お楽しみに!