Arduinoの基礎 - MQTT

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動

概要

MQTTは軽量なメッセージング・プロトコルで、IoTデバイスの通信に最適である。
Arduinoのような限られたリソースを持つマイコンでも、効率的に通信できるよう設計されている。

パブリッシャー (発行者) と サブスクライバ (購読者)、それらの仲介役となるBroker (ブローカー) という構成で動作する。

MQTT通信では、トピックという概念がある。
例えば、温度センサの値を送信する場合、"home/livingroom/temperature"というトピックを設定する。
パプリッシャーは、このトピックにデータを送信して、サブスクライバは興味のあるトピックを購読する。

これにより、以下に示すような通信が可能になる。

  • 1対多の通信
    1つのパプリッシャーから複数のサブスクライバにデータを配信する。
  • 多対1の通信
    複数のセンサからのデータを1つのモニタリングシステムで受信する。
  • 多対多の通信
    複数のデバイス間でデータを共有する。


また、MQTTには3段階のQoS (Quality of Service) がある。

  • 0
    最大1回配信
    信頼性は低いが最も軽量
  • 1
    最低1回配信
    メッセージの到達を確認
  • 正確に1回配信
    最も信頼性が高いが、オーバーヘッドも大きい。


ArduinoでMQTT通信を実装する場合、ArduinoMqttClientライブラリやPubSubClientライブラリ等のライブラリを使用する。<br.

  • ArduinoMqttClientライブラリ
    公式ライブラリであり、ビギナーにも簡単に使用できる。
  • PubSubClientライブラリ
    機能が豊富で広く使用されている。


例えば、家庭内のIoTシステムの場合、Arduinoは以下に示すような役割を果たすことができる。
温度センサの値を定期的に送信するパプリッシャー、LED照明を制御するサブスクライバ、あるいはその両方の機能を持つデバイスとして動作させることができる。

セキュリティ面においては、パブリックなMQTTブローカーを使用する場合は、センシティブな情報を送信しないように注意する。
もし、重要なデータを扱う場合、暗号化通信 (SSL/TLS証明書) の使用やユーザ認証の設定を行うべきである。

Arduinoを使用したMQTT通信は、適切に実装することにより、信頼性の高いIoTシステムを構築できるツールである。

Arduino UNO R4 WiFiは、ESP32-S3モジュールを内蔵しており、、Wi-Fiネットワークに接続・操作することが可能である。
HTTPS、MQTT、UDPを含むプロトコルがサポートされている。


必要な構成

  • ハードウェア
    • Arduino UNO R4 WiFi

  • ソフトウェア
    • Arduino IDE 2.0以降
    • Arduino_ConnectionHandlerライブラリ
    • ArduinoMqttClientライブラリ
      ライブラリマネージャからArduinoMqttClientライブラリをインストールすること。
      https://github.com/arduino-libraries/ArduinoMqttClient
    • WiFiS3ライブラリ
      Arduino UNO R4 Core付属のWiFiS3ライブラリで有効化される。
      そのため、Coreをインストールすることにより、自動的にWiFiS3ライブラリもインストールされる。

  • MQTTブローカー
    MQTTブローカーを構築する場合、あるいは、MQTTブローカーサービスを契約する場合は、Web - MQTTブローカーのページを参照すること。



MQTT通信

技術的な制約

Arduino UNOのようなボードでは、メモリ制約により扱えるメッセージサイズに制限がある。
また、Wi-Fiモジュールの性能によっては、安定した通信のために適切な待機時間の設定が必要になることがある。

デバッグとトラブルシューティング

開発時は、MQTTクライアントツール (例: MQTT Explorer) を使用することにより、通信の様子を視覚的に確認できる。
また、シリアルモニタを活用して、接続状態やメッセージの送受信を確認する。

使用例

以下の例では、Arduino R4 WiFiを使用して、MQTT通信でトピックの送受信を行っている。

  • Wi-Fiへの接続
    SSIDとパスワードを使用して、Wi-Fiネットワークに接続する。
    接続状態をシリアルモニタに表示する。
  • MQTTブローカーへの接続
    指定されたMQTTブローカーとポートに接続する。
  • トピックの送信
    5秒ごとにカウンター値をMQTTトピックに送信する。
    送信内容はシリアルモニタにも表示する。
  • トピックの受信
    購読しているトピックからメッセージを受信した場合に表示する。
    また、メッセージの内容をシリアルモニタに出力する。


送信 (MQTTパブリッシャー側)

以下の例では、5秒ごとにカウンタの値を送信 (パブリッシュ) している。

 #include <WiFiS3.h>
 #include <ArduinoMqttClient.h>
 
 // Wi-Fi設定
 const char ssid[] = "<Wi-FiのSSID>"
 const char pass[] = "<WiFiのパスワード>"
 
 // MQTTブローカーの設定
 const char mqtt_broker[] = "<MQTTブローカーのアドレス  例: test.mosquitto.org>";
 const int  mqtt_port     = 1883;              // MQTTのポート番号
 const char mqtt_user     = "<MQTTユーザ名>";
 const char mqtt_password = "<MQTTユーザのパスワード>";
 const char mqtt_topic[]  = "arduino/sensor";  // 投稿するトピック
 
 WiFiClient wifiClient;
 MqttClient mqttClient(wifiClient);
 
 void setup()
 {
    Serial.begin(9600);
    while (!Serial);  // シリアルポートの準備待ち
 
    // Wi-Fi接続
    Serial.print("Connecting to WiFi");
    WiFi.begin(ssid, pass);
 
    while (WiFi.status() != WL_CONNECTED) {
       Serial.print(".");
       delay(500);
    }
 
    Serial.println("\nConnected to WiFi");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
 
    // MQTTブローカーへの接続
    // クライアントIDを一意に設定
    String clientId = "arduino_client_" + String(random(0xffff), HEX);
    mqttClient.setId(clientId.c_str());
 
    // 認証情報の設定
    mqttClient.setUsernamePassword(mqtt_user, mqtt_password);
 
    Serial.print("Connecting to MQTT broker...");
    if (!mqttClient.connect(mqtt_broker, mqtt_port)) {
       Serial.print("MQTT connection failed! Error code = ");
       Serial.println(mqttClient.connectError());
 
       while (1);
    }
 
    Serial.println("Connected to MQTT broker!");
 }
 
 void loop()
 {
    // MQTT接続の維持
    mqttClient.poll();
 
    // 5秒ごとにメッセージを送信
    static unsigned long previousMillis = 0;
    unsigned long currentMillis = millis();
 
    if (currentMillis - previousMillis >= 5000) {
       previousMillis = currentMillis;
 
       // サンプルデータの作成(ここでは単純なカウンター)
       static int counter = 0;
       String message = "Count: " + String(counter++);
 
       // メッセージの送信
       Serial.print("Sending message: ");
       Serial.println(message);
       mqttClient.beginMessage(mqtt_topic);
       mqttClient.print(message);
       mqttClient.endMessage();
    }
 }


受信 (サブスクライバ側)

以下の例では、受信したトピックの購読 (サブスクライブ) している。

 #include <WiFiS3.h>
 #include <ArduinoMqttClient.h>
 
 // Wi-Fi設定
 const char ssid[] = "<Wi-FiのSSID>"
 const char pass[] = "<WiFiのパスワード>"
 
 // MQTTブローカーの設定
 const char mqtt_broker[] = "<MQTTブローカーのアドレス  例: test.mosquitto.org>";
 const int  mqtt_port     = 1883;              // MQTTのポート番号
 const char mqtt_user     = "<MQTTユーザ名>";
 const char mqtt_password = "<MQTTユーザのパスワード>";
 const char mqtt_topic[]  = "arduino/sensor";  // 投稿するトピック
 
 WiFiClient wifiClient;
 MqttClient mqttClient(wifiClient);
 
 void setup()
 {
    Serial.begin(9600);
    while (!Serial);  // シリアルポートの準備待ち
 
    // Wi-Fi接続
    Serial.print("Connecting to WiFi");
    WiFi.begin(ssid, pass);
 
    while (WiFi.status() != WL_CONNECTED) {
       Serial.print(".");
       delay(500);
    }
 
    Serial.println("\nConnected to WiFi");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
 
    // MQTTブローカーへの接続
    // クライアントIDを一意に設定
    String clientId = "arduino_client_" + String(random(0xffff), HEX);
    mqttClient.setId(clientId.c_str());
 
    // 認証情報の設定
    mqttClient.setUsernamePassword(mqtt_user, mqtt_password);
 
    Serial.print("Connecting to MQTT broker...");
    if (!mqttClient.connect(mqtt_broker, mqtt_port)) {
       Serial.print("MQTT connection failed! Error code = ");
       Serial.println(mqttClient.connectError());
 
       while (1);
    }
 
    Serial.println("Connected to MQTT broker!");
 
    // トピックの購読 (サブスクライブ)
    Serial.print("Subscribing to topic: ");
    Serial.println(mqtt_topic);
 
    mqttClient.subscribe(mqtt_topic);
 }
 
 void loop()
 {
    // MQTT接続の維持
    mqttClient.poll();
 
    // 受信したメッセージの処理
    int messageSize = mqttClient.parseMessage();
    if (messageSize) {
       Serial.print("Received a message with topic '");
       Serial.print(mqttClient.messageTopic());
       Serial.print("', length ");
       Serial.print(messageSize);
       Serial.println(" bytes:");
 
       // メッセージの内容を読み取って表示
       while (mqttClient.available()) {
          Serial.print((char)mqttClient.read());
       }
 
       Serial.println();
    }
 }