Azure IoTHubにMQTTを使ってつないでみる。

Azure IoTHubがリリースされた当初は対応しているプロトコルはHTTPS、AMQPでした。しばらくしてAzure IoT プロトコル ゲートウェイがリリースになってMQTTプロトコルも使えるようにはなったのですが、その時はゲートウェイを自分で用意する必要がありました。
今年2月になって[IoTHubが直接MQTTプロトコルでの接続をサポート](https://azure.microsoft.com/ja-jp/documentation/articles/iot-hub-mqtt-support/)するようになりました。

今回はMQTTプロトコルでIoTHubに接続するサンプルプログラムを紹介します。
参考にしたのはAzure-IoT-SDKの[MQTTサンプルプログラム](https://github.com/Azure/azure-iot-sdks/blob/master/csharp/device/samples/DeviceClientMqttSample/Program.cs)です。（プログラム自体はほぼ一緒です。送るメッセージを変更しています。）

##準備
1. Azure IoTHubを作成。作成方法は[こちら](http://qiita.com/linyixian/items/e319c5f63f9e57459ac0)
2. VisualStudio2015で[新規作成]-[プロジェクト]-[Visual C#]-[Windows]-[コンソールアプリケーション]を選択してプロジェクトを作成。
3. ソリューションエクスプローラーの[参照]を右クリックして[Nugetパッケージの管理]を選択して、Nugetパッケージマネージャーで「devices client」と検索してください。リストに「Microsoft.Azure.Devices.Client」が表示されたらインストールします。

##プログラム
```C#:Program.cs
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;

namespace MQTT_TEST
{
    class Program
    {
        //IoTHubに接続するためのコネクション文字列
        private const string deviceCn = "[replace]";
        
        //メッセージ送信数
        private static int MESSAGE_COUNT = 5;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            try
            {
                //デバイスクライアントのインスタンス（プロトコルをMQTTに指定）
                DeviceClient client = DeviceClient.CreateFromConnectionString(deviceCn, TransportType.Mqtt);

                //セッションを開く
                client.OpenAsync().Wait();
                //IoTHubへメッセージの送信
                SendEvent(client).Wait();
                //IoTHubからメッセージを受信
                ReceiveCommands(client).Wait();

            }
            catch (AggregateException ex)
            {
                foreach (Exception exception in ex.InnerExceptions)
                {
                    Console.WriteLine();
                    Console.WriteLine("Error in sample: {0}", exception);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("Error in sample: {0}", ex.Message);
            }
            Console.WriteLine("Press enter to exit...");
            Console.ReadLine();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        static async Task SendEvent(DeviceClient client)
        {
            //送信メッセージ用
            string dataBuffer;

            //コンソール出力
            Console.WriteLine("Device sending {0} messages to IoTHub...\n", MESSAGE_COUNT);

            for (int count=0; count < MESSAGE_COUNT; count++)
            {
                //メッセージ作成
                dataBuffer = "メッセージ:" + count.ToString();

                //作成したメッセージをバイトデータに変換して、Messageオブジェクトに代入
                Message eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer));

                //コンソール出力
                Console.WriteLine("\t{0} Sending message: {1}, Data: [{2}]", DateTime.Now.ToLocalTime(), count, dataBuffer);

                //非同期でメッセージを送信
                await client.SendEventAsync(eventMessage);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        static async Task ReceiveCommands(DeviceClient client)
        {
            //コンソールに出力
            Console.WriteLine("\nDevice waiting for commands from IoTHub...\n");

            Message recievedMessage;

            string messageData;

            //メッセージを受信するためのループ
            while (true)
            {
                //一秒ごとにメッセージの受信を確認
                recievedMessage = await client.ReceiveAsync(TimeSpan.FromSeconds(1));

                if (recievedMessage != null)
                {
                    //届いたメッセージを文字列に変換
                    messageData = Encoding.ASCII.GetString(recievedMessage.GetBytes());

                    //コンソール出力
                    Console.WriteLine("\t{0}> Received message: {1}", DateTime.Now.ToLocalTime(), messageData);

                    //受信完了を待つ
                    await client.CompleteAsync(recievedMessage);
                }
            }
        }

    }
}

```
11行目の[replace]の箇所はDevice Explorerで登録したデバイスのConnectionStringと置き換えます。

Device Explorerのモニターを有効にしてプログラムを実行すると送信したメッセージが表示されます。
また、Device Explorerの「Message To Device」タブからメッセージを送信するとプログラムコンソールにIoTHubからのメッセージが表示されます。

##まとめ
DeviceClientを利用できる環境ではHTTPSやAMQPと同様の方法でデータの送受信が可能になっています。
詳しくはわからないのですが、IoTHub側にプロトコルゲートウェイを用意してあるのではないかと思います。
また、DeviceClientを利用できない環境では、決められたIoTHubのエンドポイントにアクセスることでメッセージの送受信ができるようです。
機会があればDeviceClientを使わないサンプルも作ってみたいと思います。