# C# SDK を使った接続

[C#](https://docs.microsoft.com/en-us/dotnet/csharp/) は、Microsoft が提供する**オブジェクト指向**プログラミング言語で、**.NET Framework** 上で動作します。

本記事では、C# プロジェクトで **paho.mqtt.m2mqtt** クライアントライブラリを使用して、クライアントから MQTT サーバーへの接続、サブスクライブ、パブリッシュ、メッセージ受信を行う方法を主に紹介します。

## 前提条件

>1. デプロイメントが作成されていること。接続に関する情報はデプロイメント概要で確認できます。デプロイメントのステータスが実行中であることを必ずご確認ください。また、WebSocket を使って MQTT サーバーへの接続テストも可能です。
>2. 接続認証のために、`Access Control` > `Authentication` にてユーザー名とパスワードを設定していること。

本プロジェクトは .NET 5.0 を使って開発およびテストしています。以下のコマンドで .NET のバージョンを確認できます。
```bash
~ dotnet --version            
5.0.301
```

### MQTT クライアントの選択
[paho.mqtt.m2mqtt](https://github.com/eclipse-paho/paho.mqtt.m2mqtt) は、MQTT v3.1 および v3.1.1 をサポートし、すべての .NET プラットフォームで利用可能な MQTT クライアントです。

### .NET CLI での M2Mqtt インストール
プロジェクトのルートで以下のコマンドを実行し、M2Mqtt をインストールします。
```bash
dotnet add package M2Mqtt --version 4.3.0
```

## 接続

>コンソールのデプロイメント概要で該当するアドレスとポート情報を確認してください。ベーシックエディションの場合、ポートは 1883 または 8883 ではない可能性がありますので、必ずポート番号をご確認ください。

### MQTT ブローカーへの接続
本記事では、EMQX が提供する[無料のパブリック MQTT ブローカー](https://www.emqx.com/en/mqtt/public-mqtt5-broker)を使用します。このサービスは[MQTT IoT クラウドプラットフォーム](https://www.emqx.com/en)をベースに作成されています。ブローカーの接続情報は以下の通りです：
- ブローカー: **broker.emqx.io**
- TCP ポート: **1883**
- WebSocket ポート: **8083**

### M2Mqtt のインポート
```csharp
using uPLibrary.Networking.M2Mqtt;
```

### MQTT ブローカー接続のパラメータ設定
MQTT ブローカーのアドレス、ポート、トピックを設定します。同時に、C# の `Guid.NewGuid()` を使ってランダムな uid を MQTT クライアント ID として生成します。
```csharp
string broker = "broker.emqx.io";
int port = 1883;
string topic = "Csharp/mqtt";
string clientId = Guid.NewGuid().ToString();
// ブローカーが認証を要求する場合は、ユーザー名とパスワードを設定
string username = "emqx";
string password = "public";
```

### MQTT 接続メソッドの作成
静的クラスメソッド `ConnectMQTT` を作成し、MQTT クライアントを生成して指定したブローカーに接続します。クライアントの `IsConnected` プロパティで接続成功を判定できます。最後にクライアントを返します。
```csharp
static MqttClient ConnectMQTT(string broker, int port, string clientId, string username, string password)
{
    MqttClient client = new MqttClient(broker, port, false, MqttSslProtocols.None, null, null);
    client.Connect(clientId, username, password);
    if (client.IsConnected)
    {
        Console.WriteLine("Connected to MQTT Broker");
    }
    else
    {
        Console.WriteLine("Failed to connect");
    }
    return client;
}
```

### メッセージのパブリッシュ
while ループを定義し、その中で MQTT クライアントの `Publish` メソッドを使って、指定したトピックに 1 秒ごとにメッセージをパブリッシュします。
```csharp
static void Publish(MqttClient client, string topic)
{
    int msg_count = 0;
    while (true)
    {
        System.Threading.Thread.Sleep(1*1000);
        string msg = "messages: " + msg_count.ToString();
        client.Publish(topic, System.Text.Encoding.UTF8.GetBytes(msg));
        Console.WriteLine("Send `{0}` to topic `{1}`", msg, topic);
        msg_count++;
    }
}
```

### トピックのサブスクライブ
静的メソッド `client_MqttMsgPublishReceived` を作成します。このメソッドはクライアントが MQTT ブローカーからメッセージを受信した際に呼ばれます。受信したメッセージのトピックとペイロードを表示します。
```csharp
static void Subscribe(MqttClient client, string topic)
{
    client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
    client.Subscribe(new string[] { topic }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE });
}
static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
    string payload = System.Text.Encoding.Default.GetString(e.Message);
    Console.WriteLine("Received `{0}` from `{1}` topic", payload, e.Topic.ToString());
}
```

### 完全なコード
```csharp
using System;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;

namespace csharpMQTT
{
    class Program
    {
        static MqttClient ConnectMQTT(string broker, int port, string clientId, string username, string password)
        {
            MqttClient client = new MqttClient(broker, port, false, MqttSslProtocols.None, null, null);
            client.Connect(clientId, username, password);
            if (client.IsConnected)
            {
                Console.WriteLine("Connected to MQTT Broker");
            }
            else
            {
                Console.WriteLine("Failed to connect");
            }
            return client;
        }

        static void Publish(MqttClient client, string topic)
        {
            int msg_count = 0;
            while (true)
            {
                System.Threading.Thread.Sleep(1*1000);
                string msg = "messages: " + msg_count.ToString();
                client.Publish(topic, System.Text.Encoding.UTF8.GetBytes(msg));
                Console.WriteLine("Send `{0}` to topic `{1}`", msg, topic);
                msg_count++;
            }
        }

        static void Subscribe(MqttClient client, string topic)
        {
            client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
            client.Subscribe(new string[] { topic }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE });
        }
        static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            string payload = System.Text.Encoding.Default.GetString(e.Message);
            Console.WriteLine("Received `{0}` from `{1}` topic", payload, e.Topic.ToString());
        }

        static void Main(string[] args)
        {
            string broker = "broker.emqx.io";
            int port = 1883;
            string topic = "Csharp/mqtt";
            string clientId = Guid.NewGuid().ToString();
            string username = "emqx";
            string password = "public";
            MqttClient client = ConnectMQTT(broker, port, clientId, username, password);
            Subscribe(client, topic);
            Publish(client, topic);
        }
    }
}
```

## 動作確認
コードを実行すると、コンソールに以下のように出力されます。 ![c_sharp_connect](./_assets/c_sharp_connect.png)
