📌

MQTTを自分のWindows PCとVisual Studioだけで15分で体感する(MQTTnet v5対応)

に公開

ゴール

このチュートリアルでは、Windows PC上でMQTTを利用した簡単な通信を体験します。

  • ローカルサーバ上でMQTTブローカーを起動
  • C#でパブリッシャーとサブスクライバーを実装
  • MQTTライブラリとして MQTTnet v5 を使用

環境

  • OS: Windows 10
  • 開発ツール: Visual Studio 2022
  • プログラミング言語: C#
  • コンソールアプリケーション (.NET 8)
  • MQTTブローカー: Mosquitto
  • 使用ライブラリ: MQTTnet v5.0.1.1416

作業の流れ

1. MQTTブローカーのインストールと起動

  1. Mosquitto公式サイトから以下をダウンロードしてインストール:

  2. インストールすると、MosquittoがWindowsサービスとして登録され、自動的に起動します。

  3. コマンドラインで以下を実行し、通信可能であることを確認:

    mosquitto_sub -h localhost -t test/topic
    mosquitto_pub -h localhost -t test/topic -m "Hello MQTT"
    

もう、これでMQTT通信ができたといえばできました。しかし、本記事では、上記のコマンドと似たようなものを自らの手で作ります。

2. Visual Studioでプロジェクトを準備

  1. 新しいソリューションを作成し、以下の2つのコンソールアプリケーション(.NET 8)のプロジェクトを追加:
    • MqttSubscriberApp(サブスクライバー)
    • MqttPublisherApp(パブリッシャー)

  1. 両方のプロジェクトで NuGet パッケージ「MQTTnet(v5.0.1.1416)」をインストール。

3. MQTT Subscriberを実装

Program.csを下記で書き換え。
引数でトピック名を指定可能。指定がない場合は mqttsample を購読。

using MQTTnet;
using System;
using System.Buffers;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MqttSubscriberApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var broker = "127.0.0.1";
            var port = 1883;
            var clientId = Guid.NewGuid().ToString();
            var topic = args.Length > 0 ? args[0] : "mqttsample";

            try
            {
                var factory = new MqttClientFactory();
                using (var mqttClient = factory.CreateMqttClient())
                {
                    var options = new MqttClientOptionsBuilder()
                        .WithTcpServer(broker, port)
                        .WithClientId(clientId)
                        .WithCleanSession()
                        .Build();

                    var connRet = mqttClient.ConnectAsync(options).Result;
                    if (connRet.ResultCode != MqttClientConnectResultCode.Success)
                        throw new ApplicationException("Failed to connect to Broker(" + connRet.ResultCode + ")");

                    Console.WriteLine("Succeeded to connect to Broker(" + connRet.ResultCode + ")");
                    Console.WriteLine($"Subscribing to topic: {topic}");

                    mqttClient.SubscribeAsync(topic).Wait();

                    mqttClient.ApplicationMessageReceivedAsync += e =>
                    {
                        Console.WriteLine($"Received ({e.ApplicationMessage.Topic}): {Encoding.UTF8.GetString(e.ApplicationMessage.Payload.ToArray())}");
                        return Task.CompletedTask;
                    };

                    Console.WriteLine("Waiting for messages... Press [Enter] to exit.");
                    Console.ReadLine();

                    mqttClient.UnsubscribeAsync(topic).Wait();
                    mqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder()
                        .WithReason(MqttClientDisconnectOptionsReason.NormalDisconnection).Build()).Wait();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex);
            }
        }
    }
}

4. MQTT Publisherを実装

Program.csを下記で書き換え。

引数でトピック名とメッセージを指定可能。指定がない場合は mqttsample に現在時刻付きのメッセージを送信。

using MQTTnet;
using System;
using System.Buffers;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MqttPublisherApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var broker = "127.0.0.1";
            var port = 1883;
            var clientId = Guid.NewGuid().ToString();
            var topic = args.Length > 0 ? args[0] : "mqttsample";
            var message = args.Length > 1 ? args[1] : $"This is a default message ({DateTime.Now:yyyy-MM-dd HH:mm:ss})";

            try
            {
                var factory = new MqttClientFactory();
                using (var mqttClient = factory.CreateMqttClient())
                {
                    var options = new MqttClientOptionsBuilder()
                        .WithTcpServer(broker, port)
                        .WithClientId(clientId)
                        .WithCleanSession()
                        .Build();

                    var connRet = mqttClient.ConnectAsync(options).Result;
                    if (connRet.ResultCode != MqttClientConnectResultCode.Success)
                        throw new ApplicationException("Failed to connect to Broker(" + connRet.ResultCode + ")");

                    Console.WriteLine("Succeeded to connect to Broker(" + connRet.ResultCode + ")");
                    Console.WriteLine($"Publishing to topic: {topic}");
                    Console.WriteLine($"Message: {message}");

                    mqttClient.PublishAsync(
                        new MqttApplicationMessageBuilder()
                            .WithTopic(topic)
                            .WithPayload(message)
                            .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                            .Build()
                        ).Wait();

                    mqttClient.UnsubscribeAsync(topic).Wait();
                    mqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder()
                        .WithReason(MqttClientDisconnectOptionsReason.NormalDisconnection).Build()).Wait();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }
        }
    }
}

5. 実行方法と確認

Visual Studioでビルドすると、各プロジェクトの bin\Debug\net8.0 フォルダに .exe ファイルが生成されます。

Subscriber, Publisher それぞれで、コマンドプロンプトを開いて、以下のように実行します:

Subscriber起動(購読するトピックを指定)

MqttSubscriberApp.exe [トピック名]

Publisher起動(メッセージとトピックを指定)

MqttPublisherApp.exe [トピック名] [メッセージ]

Subscriberの画面に、送信されたメッセージが表示されれば成功です。

最後に

このチュートリアルでは、次のことを体験しました:

  • MQTTnet v5 を用いたローカル通信の実装
  • Publisher / Subscriber の分離構成
  • Visual StudioとMosquittoだけでMQTT通信の基本を体験

簡単に構築できるこの構成は、IoT開発の第一歩として最適です。

お疲れ様でした!

Discussion