HTTP REST APIでAzure IoT Hubにメッセージを送信する (C#)

2018年12月4日火曜日

Azure C# IoT IoTHub

t f B! P L

HTTP REST APIでAzure IoT Hubにメッセージを送信する (C#)

Azure IoT Hubに、HTTP REST APIでメッセージを送る方法です。
Azure IoT Device Client SDKは使いません。

AZURE IOT HUBにRest APIでメッセージを送信する

HTTP RESTでメッセージを送信するまでの流れは、こんな感じになります。

  1. デバイスの登録 (Azureポータルで作業)
  2. SASトークンの作成 (C#)
  3. RESTでメッセージを送信 (C#)

やってみる

デバイスの登録

Azureポータルで、メッセージを送信するデバイスを登録します。

Iot Hubのページから、[IoT devices] -> [Add]を選択
enter image description here

下の画面で、Iotデバイスを登録します。
Device IDは任意の値、認証には Symmetric keyを選択します。
Iotデバイスの登録

デバイスが登録されると、一覧にデバイスが追加されます。
登録後のデバイス一覧

一覧から登録したデバイスを選択して、デバイスの詳細を表示します。
ここに表示される、[Device ID][Primary Key(共有アクセスキー)]を、後から使うのでメモしておきます。

デバイス詳細

SASトークンの作成 (C#)

ここからC#のコードを組んでいきます。

デバイスIDと共有アクセスキーから、SASトークンを生成するメソッドを作ります。
ここで作成するGenerateSasToken()メソッドを、後述するメッセージ送信のサンプルコードから呼びます。

using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;

/// <summary>
/// Azure IOT Hub用のSASトークンの作成
/// </summary>
/// <returns>SASトークン</returns>
/// <param name="resourceUri">リソースURL</param>
/// <param name="key">共有アクセスキー</param>
/// <param name="policyName">ポリシー名(今回使用しない)</param>
/// <param name="expiryInSeconds">有効期限(秒)</param>
public static string GenerateSasToken(string resourceUri, string key, string policyName, int expiryInSeconds = 3600) {
    TimeSpan fromEpochStart = DateTime.UtcNow - new DateTime(1970, 1, 1);
    string expiry = Convert.ToString((int)fromEpochStart.TotalSeconds + expiryInSeconds);

    string stringToSign = WebUtility.UrlEncode(resourceUri) + "\n" + expiry;

    HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));
    string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
    string token = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}", WebUtility.UrlEncode(resourceUri), WebUtility.UrlEncode(signature), expiry);

    if (!String.IsNullOrEmpty(policyName)) {
        token += "&skn=" + policyName;
    }

    return token;
}

RESTでメッセージを送信 (C#)

.NET Framework標準の HttpClientクラスを使って、RESTでメッセージを送信します。
今回は、JSONのデータを送ります。

//(1)環境設定
private const string IOT_HUB_NAME = "<iothubname>.azure-devices.net";
private const string SIGNING_KEY = "<共有アクセスキー>";
private const string DEVICE_ID = "<デバイスID>";
        
public static void Send() {

    //(2)SASトークンを作成する
    var resourceUri = $"{IOT_HUB_NAME}/devices/{DEVICE_ID}";
    var sasToken = GenerateSasToken(resourceUri, SIGNING_KEY, null);

    //(3)URLの組み立て
    var url = $"https://{IOT_HUB_NAME}/devices/{DEVICE_ID}/messages/events?api-version=2018-06-30";
    HttpResponseMessage res = null;
    
    //HTTP RESTでメッセージを送信する
    using (var client = new HttpClient()) {
        var request = new HttpRequestMessage(HttpMethod.Post, url);

        //(4)HTTPヘッダに、SASトークンを設定
        request.Headers.Add("Authorization", sasToken);

        var json = @"{""msg"":""Test Message""}";
        var content = new StringContent(json, Encoding.UTF8, @"application/json");
        request.Content = content;
        res = client.SendAsync(request).Result;

        //メッセージが正常に送信されると、IoT Hubからは、204が返ってくる
        if (res.StatusCode == HttpStatusCode.NoContent) {
            Console.WriteLine("送信しました。");
        }
    }
}

ポイントは以下の通り。

(1)Iot Hub名、デバイスの共有アクセスキーおよび、デバイスIDを指定します。

Iot Hub名は、Azure Iot Hubのトップページから確認できます。
Iot Hub名の確認

デバイスID、共有アクセスキーは、デバイスの詳細ページから確認できます。
デバイス詳細

(2)上で作成したメソッドを使って、SASトークンを作成します。
(3)送信先URLには、デバイスIDを含めます。
(4)HTTPヘッダに、作成したSASトークンを指定します。

メッセージにプロパティを設定するには

REST APIで、メッセージにプロパティ (application property) を指定する場合は、リクエストヘッダに設定します。
ヘッダに設定するプロパティ名には、iothub-app-の接頭辞を付けて設定します。

<サンプルコード>

// "myprop"というプロパティを IotHubに送信する場合
request.Headers.Add("iothub-app-myprop", value);

(おまけ) RESTでメッセージを受信(C#)

IoT Hubからメッセージ通知し、REST APIで受信する例です。
送信の例と同じように、SASトークンを発行してから、APIを叩きます。
メッセージを受信した後に、Iot Hubに完了通知を送って、メッセージを削除します。

public static void Revive() {

    //SASトークンを作成する
    var resourceUri = $"{IOT_HUB_NAME}/devices/{DEVICE_ID}";
    var sasToken = GenerateSasToken(resourceUri, SIGNING_KEY, null);

    //URLの組み立て
    var url = $"https://{IOT_HUB_NAME}/devices/{DEVICE_ID}/messages/deviceBound?api-version=2018-06-30";
    HttpResponseMessage res = null;

    using (var client = new HttpClient()) {
        var request = new HttpRequestMessage(HttpMethod.Get, url);

        //HTTPヘッダに、SASトークンを設定
        request.Headers.Add("Authorization", sasToken);
        res = client.SendAsync(request).Result;

        if (res.StatusCode == HttpStatusCode.OK) {
            Console.WriteLine(res.Content.ReadAsStringAsync().Result);
        } else {
            //通知がない場合
            Console.WriteLine("No Message!");
        }

        //受信したメッセージの完了通知をIoT Hubに送信します。
        //これにより、Iot Hubよりメッセージが削除される模様
        var etag = res.Headers.ETag?.Tag.Replace("\"", string.Empty);
        if (etag != null) {
            var restUriComplete = $"https://{IOT_HUB_NAME}/devices/{DEVICE_ID}/messages/deviceBound/{etag}?api-version=2018-06-30";
            var deleteRequest = new HttpRequestMessage(HttpMethod.Delete, restUriComplete);
            deleteRequest.Headers.Add("Authorization", sasToken);
            var resDelete = client.SendAsync(deleteRequest).Result;
        }
    }
}

上のコードを試す為に、Azureポータルからメッセージを送信してみます。
Iot Hubのデバイス詳細ページから[Message to device]を選択して、メッセージを送信します。
デバイスへメッセージを送信する

実行すると、コンソールにAzureポータルから送信したメッセージが表示されると思います。
コードを実行し、送信されたメッセージがコンソールに表示される

おわりに

<関連記事>

C# (.net) で使える MQTT クライアント (Paho M2Mqtt)

C#で 、MQTTメッセージを送受信するライブラリの、「M2Mqtt」の使い方について、解説しています。
無料のBrokerサーバを使って、簡単にお試しする事が出来ます。

参考

共有アクセスキーの、プライマリ・セカンダリについて

共有アクセスキーには、プライマリとセカンダリの2つがあり、セキュリティの観点からアクセスキーを一定期間でローテーションすることを目的としています。

運用として、アクセスに使うキーをプライマリからセカンダリに変更し、その間にプライマリのキーを再生成してから元に戻す運用を行います。

共有アクセスキーのローテイションは、Azureポータルから行います。
デバイス詳細画面の [Regenerate keys]をクリックして、共有アクセスキーの再生成を行います。
共有アクセスキーの再生成

Azure IoT Hubを生MQTTS(mosquitto)やHTTP RESTで使う方法

https://qiita.com/ma2shita/items/032370350cba282d35ff

Azure IoT Hubを使ってみた

https://qiita.com/linyixian/items/e319c5f63f9e57459ac0

IoT Hub へのアクセスの制御

https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-security#scope-iot-hub-level-credentials

Azure IoT Device Client SDK

今回は使っていませんが、Azure IoT Device Client SDKは、nuget からインストールできます。

スポンサーリンク

QooQ