.NET Micro Framework

Gadgeteer と Microsoft Azure BLOB ストレージを使用した IoT デバイスの作成

Benjamin Perkins

コード サンプルのダウンロード

今後 5 年間で、インターネットに接続されるデバイスの数は総人口の 3 倍以上になるでしょう。インターネットに接続されるデバイスには、現在使われているスマートフォンやタブレットだけでなく、家電製品、エレベーター、自動車、ビジネス環境、腕輪、衣料品などに埋め込まれるデバイスも含みます。このようなデバイスは、エネルギー消費量、速度、温度、さまざまなガスの有無、血圧、心拍数、プログラムやハードウェアの例外など、考え得るありとあらゆる情報をキャプチャすることになります。

デバイスがキャプチャしたデータは、拡張性や信頼性が高く、使い勝手の良い環境に格納する必要があります。使い勝手の良い環境とは、データを格納後、収集したデータの分析、収集したデータからの学習、収集したデータに基づく行動などを可能にするサービス、機能、処理能力を提供するプラットフォームを指します。今回は、Microsoft .NET Micro Framework を基盤とする高速ハードウェア開発プラットフォームの Gadgeteer を使用してデータをキャプチャするデバイスをビルドする方法、Microsoft Azure Storage にデータを格納する方法、および Microsoft Azure プラットフォームでデータを分析および利用する方法について説明します。この説明をお読みいただけば、すぐにでもモノのインターネット (IoT) の作成に取り掛かれます。

ここでは、Gadgeteer、Microsoft Azure BLOB ストレージ、および Microsoft Azure プラットフォームのデータのキャプチャと分析のコンポーネントについて詳しく説明します。また、Gadgeteer を使用して Microsoft Azure BLOB ストレージ コンテナーに画像を挿入する方法についてもコードレベルで紹介します。

Gadgeteer

GHI Electronics LLC (bit.ly/11ko85B、英語) が提供する Gadgeteer には、多種多様なデバイスを作成するためのキット、モジュール、メインボード (今回のプロジェクトで使用する FEZ Raptor、FEZ Hydra、FEZ Spider など) が含まれています。こうして作成したデバイスを使って、数多くのさまざまなデータをキャプチャできます。デバイスの作成に利用できるモジュールには、空気中のガスを検出するガス センサー モジュール、相対温度と相対湿度を測定する動作検出器や検知モジュールなどがあります。今回説明するプロジェクトの完成に必要な FEZ Spider 互換のモジュールは、カメラ、イーサネット ジャック、および電源モジュールです。まず、各モジュールの構成方法と、キャプチャした画像を準備して、Microsoft Azure BLOB ストレージ コンテナーに挿入するために必要なコードを開発する方法について説明します。

図 1 は、今回のプロジェクトの構成を示しています。カメラ、イーサネット ジャック、電源以外に、IP アドレス、日付、時刻を表示するキャラクター ディスプレイ、視覚的サインを示す LED ライト、写真の撮影と、撮影した画像をアップロードするプロセスをトリガーするボタンがあります。

写真を撮影して Microsoft Azure BLOB コンテナーに格納するための FEZ Spider の構成
図 1 写真を撮影して Microsoft Azure BLOB コンテナーに格納するための FEZ Spider の構成

.NET Micro Framework、GHI バイナリ (パッケージ 2014 R5)、および .NET Gadgeteer SDK を開発用コンピューターにインストールし、Visual Studio 2012 で新しいプロジェクトを作成して、Gadgeteer テンプレートを選択します (Visual Studio 2013 もサポートの対象ですが、広範なテストはまだ行われていません)。プロジェクトに名前を付けた後、ウィザードに従って、メインボードと Micro Framework のバージョンを選択します。次に、ツールボックスを使用してモジュールを追加し、図 1 に示すようなデバイスをビルドします。

モジュールをメインボードのソケットに物理的に接続したら、プロジェクトの目標 (ネットワークに接続して写真を撮影する) の実現に必要なコードの変更を開始します。ネットワーク接続を行うために使用するモジュールは ethernetJ11D です。このモジュールは、一般的な RJ-45 ネットワーク アダプターをサポートします。ethernetJ11D モジュールに接続を実行させ、割り当て済みの IP アドレスを取得するコードを以下に示します。

ethernetJ11D.NetworkInterface.Open();
ethernetJ11D.NetworkSettings.EnableDhcp();
ethernetJ11D.NetworkSettings.EnableDynamicDns();
ethernetJ11D.UseDHCP();

もちろん、これ以外の方法で接続を確立することもできますが、今回のコンテキストではこの方法が最も上手く機能し、シンプルです。

接続したら、図 2 に示すシンプルな System.Net.HttpWebRequest 要求を実行して、インターネットへの接続が期待どおり機能しているかどうかを確認します。

図 2 インターネット接続のテスト

void makeGenericHTTPRequest()
{
  try
  {
    string url = "https://www.contoso.com/";
    using (var req = System.Net.HttpWebRequest.Create(url))
    {
      using (var res = req.GetResponse())
      {
        Debug.Print("HTTP Response length: " 
          + res.ContentLength.ToString());  }
    }   
  }
  catch (Exception ex)
  {
    Debug.Print(ex.Message);
  }
}

HTTPS プロトコルが機能するには、いくつか構成が必要です。「型 'System.NotSupportedException' の初回例外が Microsoft.SPOT.Net.Security.dll で発生しました」などの例外が表示される場合は、デバイスの SSL Seed を更新する必要があります。これは、C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.3\Tools ディレクトリにある、.NET Micro Framework Deployment Tool (MFDeploy.exe) を使用することで実行できます。デバイスを開発用コンピューターに接続し、[Target] (ターゲット)、[Manage Device Keys] (デバイス キーの管理)、[Update SSL Seed] (SSL Seed の更新) を順にクリックします (図 3 参照)。この構成を完了すると、HTTPS が期待どおり機能します。

.NET Micro Framework Deployment Tool (MFDeploy)
図 3 .NET Micro Framework Deployment Tool (MFDeploy)

ネットワークに接続し、インターネットの設定を構成して機能するようになったら、デバイスの日付と時刻を設定しておくことが重要です。後ほど説明しますが、Microsoft Azure BLOB コンテナーに画像を挿入するために使用する PUT Blob REST API (https://msdn.microsoft.com/ja-jp/library/azure/dd179451.aspx) には日付と時刻の情報が必要です。日付と時刻を設定するには、以下に示すように、Microsoft.SPOT.Time 名前空間の TimeServiceSettings クラスを使用します。

TimeServiceSettings time = new TimeServiceSettings()
{
  ForceSyncAtWakeUp = true
};
IPAddress[] address = Dns.GetHostEntry("time.windows.com").AddressList;
time.PrimaryServer = address[0].GetAddressBytes();
TimeService.Settings = time;
TimeService.SetTimeZoneOffset(0);
TimeService.Start();

TimeService を実行すると、標準の DateTime.UtcNow プロパティまたは DateTime.Now プロパティを使用して、現在のタイムスタンプを取得できます。

GHI FEZ Spider 互換のカメラを使用して写真を撮影するのに必要なコードは、以下に示す 1 行だけです。

camera.TakePicture()

既に説明したように、デバイスに Button モジュールを追加しました。TakePicture メソッドを呼び出すのは、Button の Pressed イベントです。写真を撮影すると、camera.PictureCaptured イベントがトリガーされ、camera_PictureCaptured(Camera sender, GT.Picture e) メソッドが呼び出されます。Pressed イベントと Captured イベントを対応する各メソッドにリンクするために、標準の C# コードを使用してイベント ハンドラーとメソッドを接続します。

button.ButtonPressed += button_ButtonPressed;
camera.PictureCaptured += camera_PictureCaptured;

camera_PictureCaptured メソッドは、パラメーターとして GT.Picture を受け取ります。e.PictureData プロパティを使用して byte[] 配列に変換した後、この画像データを Microsoft Azure BLOB コンテナーに挿入するためにカスタム メソッドに渡します。説明では複雑なプロセスのように思えますが、実際はかなりシンプルです (図 4 参照)。また、付属のコード サンプルをダウンロードすれば、コード全体を確認できます。

Gadgeteer の写真撮影プロセスのフロー
図 4 Gadgeteer の写真撮影プロセスのフロー

図 5 は、Azure Blob クラスを利用するために使用するコードを示しています。Authorization ヘッダー (https://msdn.microsoft.com/ja-jp/library/azure/dd179428.aspx) を作成し、Microsoft Azure BLOB コンテナーに画像を挿入するための REST API の呼び出しを行うコードについてはこの後説明します。

図 5 Microsoft Azure BLOB ストレージへの画像の挿入

void insertImageintoAzureBlob(GT.Picture picture)
{
  AzureBlob storage = new AzureBlob()
  {
    Account = "ACCOUNT-NAME",
    BlobEndPoint = "https://ACCOUNT-NAME.blob.core.windows.net/",
    Key = "CONTAINER PRIVATE KEY"
  };
  if (ethernetJ11D.IsNetworkUp)
  {
    storage.PutBlob("CONTAINER-NAME", picture.PictureData);
  }
  else
  {
    characterDisplay.Print("NO NETWORK CONNECTION");
  }
}

デバイス側の作業はこれで完了です。デバイスを組み立ててインターネットに接続できるようになり、画像をキャプチャして適切な形式で PUT Blob REST API に送信するロジックもすべて完成しました。次は、Microsoft Azure BLOB ストレージ アカウントとコンテナーを作成し、画像を挿入するのに必要なコードを構成します。

Microsoft Azure BLOB ストレージ

Microsoft Azure BLOB ストレージは、HTTP または HTTPS を使用してどこからでも画像、ドキュメント、ビデオなどにアクセスできるようにする便利なサービスです。たとえば、home.bmp という名前の画像、contosox という名前の Microsoft Azure のパブリック ストレージ アカウント、および blob という名前のコンテナーがあるとすると、ブラウザーに http://contosox.blob.core.windows.net/blob/home.bmp と入力するか、HTML やソース コードからこの URL を参照するだけで、.bmp ファイルにアクセスできます。

標準の .NET アプリケーションから Microsoft Azure BLOB コンテナーに BLOB を挿入、一覧、ダウンロード、および削除する場合、Microsoft.WindowsAzure.Storage アセンブリから .NET 用 Microsoft Azure Storage クライアント ライブラリを使用します。残念ながら、このアセンブリは .NET Micro Framework と互換性がなく、Gadgeteer デバイスでは利用できません。さいわい、Microsoft Azure BLOB ストレージ サービスは、同様の挿入、一覧、ダウンロード、および削除の機能をサポートするために、パブリックにアクセスできる REST API を提供しています (詳細については、https://msdn.microsoft.com/ja-jp/library/azure/dd135733.aspx を参照)。そのため、IoT デバイスから標準の REST API を呼び出すだけで簡単にこのような機能を利用できます。

ここからは Microsoft Azure BLOB ストレージ アカウントとコンテナーを作成する方法、.NET Micro Framework 4.3 を使用して REST API の Authorization ヘッダーを作成する方法、および先ほどキャプチャした画像を Microsoft Azure BLOB コンテナーにアップロードする方法について説明します。

Microsoft Azure の管理コンソール内から Microsoft Azure のストレージ アカウントを作成し、[+ ADD] (+ 追加) ボタンをクリックしてコンテナーを追加します。今回の例では、ストレージ アカウント名を「contosox」、コンテナー名を「blob」としています (図 6 参照)。

IoT デバイスで撮影した画像を格納する Microsoft Azure ストレージ コンテナーの作成
図 6 IoT デバイスで撮影した画像を格納する Microsoft Azure ストレージ コンテナーの作成

図 7 の例は、PUT Blob REST API を利用するために必要な操作を示しています。図 6 に示した URL に画像の名前を連結し、System.Net.HttpWebRequest クラスの GetRequestStream メソッドを呼び出すと、System.IO.Stream オブジェクトが返されます。System.IO.Stream クラスの Write メソッドを使用すれば、Microsoft Azure BLOB コンテナーに画像を保存できます。Write メソッドの blobContent パラメーターは、GT.Picture.PictureData プロパティに含まれるバイト配列 (byte[]) のコンテンツです。

図 7 PUT Blob REST API の利用

Uri uri = new Uri("ACCOUNT-URL\CONTAINER\" + "IMAGE-NAME");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
try
{
  using (Stream requestStream = request.GetRequestStream())
  {
    requestStream.Write(blobContent, 0, blobLength);
  }
}
catch (WebException ex)
{
  Debug.Print(ex.Message);
}

それほど複雑ではありません。標準の ASP.NET アプリケーションまたは Microsoft .NET Framework アプリケーションから REST API を呼び出す方法とほぼ同じです。違いは以下に定義する Authorization ヘッダーの作成です。この違いが複雑さを増します。

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"

Microsoft Azure BLOB コンテナーを作成するときに、コンテナーをパブリックにします。つまり、だれでも前述の URL を知っていればこのコンテナーを読み取れます。ただし、Blob を追加または削除する場合は、要求に Authorization ヘッダーを提示する必要があります。ヘッダーの SharedKey 値は、共有アクセス キーが存在し、これを要求の認証に使用することをサーバーに通知します。SharedKey は、Microsoft Azure ストレージ アカウント (この例では「contosox」) に関連付けられていて、ストレージ アカウントを指定して [アクセス キーの管理] をクリックすれば取得できます。図 8 に示す [プライマリ アクセス キー] テキスト ボックスに含まれる値が、コンテナーへのアクセスに使用する SharedKey です。

Microsoft Azure ストレージの認証に必要な SharedKey の取得
図 8 Microsoft Azure ストレージの認証に必要な SharedKey の取得

また、Authorization ヘッダーの署名 (Signature) 部分には、ハッシュ ベースのメッセージ認証コード (HMAC) を指定する必要があります。このコードは、多くの要求属性を使用して構成し、System.Security.Cryptography.HashAlgorithm.ComputeHash メソッドを使用して計算して、System.Convert.ToBase64String メソッドでエンコーディングします。

もう少し詳しく説明します。最初は、Authorization ヘッダーの構成に必要なコンポーネントです。ヘッダーの構成には、x-ms-version、content-length、content-type などの属性、共有アクセス キー、およびその他多くのヘッダー値が必要です (詳細は、https://msdn.microsoft.com/ja-jp/library/azure/dd179451.aspx 参照)。重要度の高い属性の 1 つが x-ms-date です。これは、デバイスの初期化中に日付と時刻を設定する必要があるためです。x-ms-date は UTC 形式のタイムスタンプにする必要があります。デバイスのタイムスタンプは、ストレージ サービスをホストするサーバーのタイムスタンプとの誤差が 15 分以内に収まっていなければなりません。ストレージ サービスは、15 分以内に行われた要求であることを確認します。時刻に大きな誤差があると、サービスから 403 (アクセス不可) が返されます。その他の属性は変更しないで、ハードコードすることも、他のソース (構成ファイルなど) から取得することもできます。

約 35 行にわたる Authorization ヘッダーを正しくフォーマットしたら、要件に応じてハッシュ化およびエンコーディングを行います。完全版の .NET Framework を使用する場合、以下のようなコードが必要になります。

using (HashAlgorithm hashSHA256 = 
  new HashAlgorithm(HashAlgorithmType.SHA256))
{
  Byte[] dataToHmac = 
    System.Text.Encoding.UTF8.GetBytes(canonicalizedstring);
  signature = 
    Convert.ToBase64String(hashSHA256.ComputeHash(dataToHmac));
}

Authorization ヘッダーをハッシュ化するために必要な System.Security.Cryptography.HashAlgorithm.ComputeHash メソッドは、.NET Micro Framework version 4.3 (bit.ly/1wIl77O、英語) に含まれているため、署名 (Signature) をハッシュ化する場合の有効な選択肢になります。ただし、今回は WebAPI を開発することにします。この WebAPI は PUT Blob REST API 呼び出しで使用するために、構成済みのヘッダーをパラメーターとして受け取り、それをエンコーディングしてハッシュ化し、Gadgeteer に返します。このアプローチを選択した主な理由は、Gadgeteer から WebAPI の呼び出しをテストするためで、テストの結果、Gadgeteer は呼び出しを行う場所になり得ることが論理的に実証されました。以下のコードは、Gadgeteer デバイスから WebAPI を呼び出す方法を示しています。

string queryString = "constructedHeader=" + constructedHeader;
Uri uri = new Uri("https://*??.azurewebsites.net/api/HMACSHA256?" + queryString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();

周知のとおり、WebAPI からの応答は JSON オブジェクトで、その内容は responseFromServer 文字列です。WebAPI の結果を解析する場合、およびハッシュ化およびエンコード済みの Authorization ヘッダー値を取得する場合は、オープン ソースの MicroJSON ライブラリ (microjson.codeplex.com、英語参照) が便利です。

var jdom = (JObject)JsonHelpers.Parse(responseFromServer);
var hashedvalue = jdom["HashedValue"];
StringBuilder authorizationHeader = new StringBuilder("{0} {1}:{2}")
  .Replace("{0}", SharedKeyAuthorizationScheme)
  .Replace("{1}", "contosox")
  .Replace("{2}", hashedValue);

または、string.Substring メソッドと string.IndexOf メソッドを組み合わせて使用して、同じ結果を得ることもできます。

string.Format メソッドは、.NET Micro Framework では現在サポートされていません。そのため、今回は StringBuilder.Replace を使用して authorizationHeader を構成しました。前述のように、Authorization ヘッダーは、SharedKey または SharedKeyLite のいずれかを組み合わせた SharedKeyAuthorizationScheme、Microsoft Azure BLOB ストレージ名「contosox」、およびエンコードおよびハッシュ化済みの署名で構成します。Authorization ヘッダーを正しくフォーマットしたら、このヘッダーを PUT Blob REST API 要求オブジェクトに追加して実行します。画像は認証を受けた後、Blob コンテナーに追加します。

request.Headers.Add("Authorization", authorizationHeader);

今回の例では、Microsoft Azure BLOB コンテナーへの画像の挿入をトリガーするイベントはボタンの押下です。このアプローチにしたのは、この概念実証プロジェクトを作成することだけが目的のためです。実際の実装では、トリガーとしてモーション、ガス、気圧、温度、湿度などを検知するセンサーを使用してもかまいません。実際には、特定のしきい値を超えたときにイベントをトリガーするモジュールを用意して、写真の撮影や Microsoft Azure へのアップロードを行うことができます。多くの場合、IoT デバイスの要件には画像が含まれることはなく、温度、速度、ガス レベル、時間など、キャプチャしたデータを保存することが目的になります。このようなデータは、シンプルな WebAPI の呼び出しを使ってデータベースに格納できますが、今回説明した Blob や画像を格納するのでなければ、Authorization ヘッダーが必要になることはありません。

これでデータをキャプチャして Microsoft Azure プラットフォームに格納することができました。残った問題は、格納したデータをどのように扱うかと、格納したデータに対して分析や学習を行う方法です。ここからは、アイデアをいくつか紹介し、継続的なレビュー、開発、および将来に向けての議論に関する考え方をまとめます。今回の目的は、エンド ツー エンドの IoT ソリューションをすべて詳しく説明することではなく、考える材料を提供して、このような考え方を推進することです。

Microsoft Azure

多くの IT 担当者は、「ビッグ データ」が何を意味するかを十分理解していますが、それをどのように活用するかについては、あまり明確にはなっていません。ビッグ データについて学び始めると最初にハードルとなるのが、HDInsight、Power BI、Event Hubs、Machine Learning、Stream Analytics といったツールで操作できるデータ ソースを見つけることです。こうしたサービスを使い始め、機能や性能を学習しても、アルゴリズムの対象となる大きなデータ ソースがないため、すぐに興味を失ってしまいます。このような過程で行き着いたのが、インターネットに接続する IoT デバイスを使用してデータを収集し、Microsoft Azure のサービスを使って操作できる大きな情報ソースをビルドすることでした。

Event Hubs や Stream Analytics がリアルタイムに意思決定することを目的とし、HDInsight や Machine Learning が膨大な量のデータの分析を目的としていることを考えると、このようなサービスが IoT を念頭に置いて設計されていることは明らかです。たとえば、デバイスが毎秒何百万回もトリガーするイベントを取り込むために特別に設計された Event Hubs は、大規模 IoT ソリューションに必要なスケーリング機能を提供します。IoT ソリューションを既に実装している企業や、IoT 戦略の立案に着手した企業にとっては、Event Hubs が長期にわたる成長と規模拡大を成し遂げるための優れた出発点になります。さらに、Stream Analytics を Event Hubs と統合すれば、デバイスから Event Hubs に送信されるデータをリアル タイムに分析できるようになります。Stream Analytics は、Event Hubs に送信されるデータと履歴データと比較して、現在のパターンが履歴データと一致しない場合に、事前に警告を発することができます。このような可能性を想像してみてください。

大きなデータ プールを保持する組織や個人について考えてみます。このデータ プールは IoT デバイスによって収集したデータである必要はありません。このような組織や個人は、HDInsight サービスまたは Machine Learning サービスを使用してプールしたデータを分析することができます。HDInsight は Hadoop ソリューションで、データを必要に応じてテラバイトやペタバイトにスケール変換できるソリューションです。Microsoft Azure プラットフォームでは、ストレージ リソースやコンピューティング リソースをほぼ無限に提供しています。HDInsight を使用して隠れたビジネス チャンスを見つけたり、Machine Learning と連携するか、個別に使用してデータ マイニングを行い、将来の流行や動向を予測することができます。このようなサービスは IoT を新しい時代に導きます。以前は見えなかった情報を革新的な方法で明らかにすることができ、大きな可能性が広がります。さらに、Power BI を使えば、さまざまな情報をユーザーにわかりやすい方法で表示することができます。

まとめ

今回の目標は、Gadgeteer を使用して IoT デバイスを構成してインターネットに接続して、クラウドの Microsoft Azure BLOB コンテナーに画像をアップロードする方法を説明することでした。デバイスがキャプチャしたデータをインターネット経由でアクセスできるデータ ソースに挿入する場合に必要なのはシンプルな WebAPI 呼び出しだけでした。実際のデバイス ハードウェアの構成は、ツールボックスのメニューから設計テンプレートにモジュールをドラッグ アンド ドロップするだけです。今回の例で実際に複雑になるは、PUT Blob REST API の Authorization ヘッダーを作成する部分です。これには、特有のフォーマットが必要で、エンコーディングやハッシュ化が求められるためです。このような複雑な処理も、WebAPI を使って System.Security.Cryptography.HashAlgorithm.ComputeHash メソッドを呼び出すか、.NET Micro Framework のクラスを使用するだけで実現できました。

Microsoft Azure のプラットフォーム サービスについても簡単に説明し、ストレージのスケーリング機能や IoT デバイスがキャプチャしたデータの分析について検討しました。デバイスが十分な量のデータがキャプチャし始めたら、リアルタイム分析に使用できる Event Hubs や Stream Analytics、長期にわたる調査に使用できる HDInsight や Machine Learning など、Microsoft Azure プラットフォームのさまざまなサービスを使用できます。生成、格納、処理、および提示された膨大な量の情報の内部に潜む有益な情報を見つけたら、これを使ってビジネス上の意思決定や予測を行い、企業戦略を成功に導くことができます。トライしてみてください。


Benjamin Perkins は、マイクロソフトのシニア サポート エスカレーション エンジニアで、IIS、NHibernate、および Microsoft Azure に関する書籍を 3 冊執筆しました。現在は、C# 6.0 のリリースに並行して出版する C# に関する書籍を執筆中です。連絡先は benperk@microsoft.com (英語のみ) です。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Martin Grasruck と Colin Miller に心より感謝いたします。