Windows Azure の詳細
Windows Azure サービス バスとモノのインターネット、第 2 部
Bruno Terkaly
Ricardo Villalobos
コード サンプルのダウンロード
前回のコラム (msdn.microsoft.com/magazine/dn574801) では、マシン ツー マシン (M2M) コンピューティングに関する最新テクノロジの展望について説明しました。M2M とは、センサー形式やメーター形式のデバイス (通常は工業計測用) を相互接続するテクノロジを指します。安価でプログラミングしやすい小型コンピューターの普及により、この概念はいわゆる "モノのインターネット" (IoT) へと拡大しました。そのため、普通の家庭用電化製品さえも制御したりイベント生成元として使用したりする可能性が開けました。この可能性を利用すれば、冷蔵庫に食料品を補充する必要が生じたら通知を送信する、日が暮れたら窓のブラインドを自動で閉める、家族の習慣に基づいて温度調節装置を設定するなどの処理が難しくなくなります。
また、前回のコラムでは、アドレス指定機能、セキュリティ、およびパフォーマンスという、大量のセンサーやメーターの配置に関連した懸念事項を解決する目的で、デバイスの接続に VPN ではなく Windows Azure サービス バスを使用する例も紹介しました。Business Insider の最新の BI Intelligence 報告書によれば IoT に直接関係する接続数が 2018 年までに 90 億以上に達する (read.bi/18L5cg8、英語) ことを考えると、これはますます無視できなくなっています。
デバイスに指定のサービス バス キューやトピックを使用すると、IoT アプリケーションに回復性や随時接続を組み込む優れた方法を実現できます。今回のコラムでは、このような概念を実証する実践的な Windows Azure 実装について手順を追って説明します。具体的には、デバイスのキューを使用したサービス バスを設計し、リッスンするワーカー ロールをクラウド サービスに配置します。さらに、モバイル クライアントからリモートで送信されたコマンドを実行するよう Arduino デバイスをプログラミングします (図 1 参照)。
図 1 Windows Azure サービス バスを使用したモノのインターネット アーキテクチャ
図を見ると、Windows Azure サービス バス コンポーネントが設計の中心となっていることと、データを送信したりリモート コマンドを受信したりする複数のデバイスをサポートするために、認証、メッセージ配信、およびスケーラビリティを提供していることがわかります。サービス バスは、Windows Azure サービスを提供するすべてのマイクロソフト データセンターで利用でき、冗長性が高いストレージ インフラストラクチャにバックアップされています。また、他のすべての Windows Azure コンポーネントと同じように、サービス バスでは、わかりやすいオープンな REST インターフェイスや、その上に構築された複数の SDK (Microsoft .NET Framework、Java、PHP、Ruby など) も提供しています。
このコラムで提案するアーキテクチャでは、Windows Azure クラウド サービスで実行中の .NET アプリケーションとデバイスとの間で通信します。この .NET アプリケーションは、割り当てられたキューとの通信処理を簡略化するために、サービス バスに対するゲートウェイとして機能します。このアプローチを使用すると、前回のコラムで説明した 4 つの IoT 通信パターン (テレメトリ、問い合わせ、コマンド、および通知) をすべて利用できるようになります。今回は、モバイル デバイスから別のデバイスにコマンドを送信して操作 (この場合は、LED の点灯または消灯) を実行するシナリオを実装します。この手法のメリットの 1 つは、デバイスが一時的にオフラインになっても、インターネットに再接続すれば必ずコマンドを取得できる点です。不適切なタイミングでタスクを実行しないようにメッセージに有効期限を設定したり、将来の特定の時間にメッセージを送信するようメッセージにスケジュールを設定したりもできます。
この例では、前回説明したように、知名度が高くてドキュメントが充実している Arduino デバイスを使用します。概念実証のモバイル クライアント部分としては、Windows Phone アプリを作成します。
今回使用する簡単なシナリオは、次のとおりです。
- Arduino デバイスが起動したら、このデバイスから、Windows Azure クラウド サービスで実行中のゲートウェイ アプリケーションに ID 信号を送信します。ゲートウェイでは、デバイス用のサービス バス キューが存在しない場合はキューを作成し、TCP 接続を確立して、コマンドを送信できる状態にします。
- Windows Phone アプリから、デバイスに割り当てられた Windows Azure サービス バス キューにコマンドを送信します。
- ゲートウェイ アプリケーションがメッセージを受信して、確立済みの TCP 接続経由でコマンドを Arduino デバイスに送信するまで、そのメッセージはキューに残ります。
- Arduino デバイスで、コマンドに基づいて LED を点灯または消灯します。
では、このシナリオを実現する手順を 1 つずつ確認しましょう。
手順 1. Windows Azure サービス バスの名前空間を作成する: Windows Azure の資格情報を使用して (bit.ly/1atsgSaで評価版のアカウントを取得できます)、Web ポータルにログインし、[SERVICE BUS] セクションをクリックします (図 2参照)。[作成] オプションをクリックし、名前空間の名前を入力します。次に、[CONNECTION INFORMATION] (接続情報) をクリックし、[Connection String] (接続文字列) ボックスのテキストをコピーします。このテキストは後で必要になります。
図 2 Windows Azure サービス バスの名前空間の作成
手順 2. ゲートウェイ アプリケーションを作成して Windows Azure クラウド サービスに配置する: サービス バス キューからメッセージを取得してコマンドを Arduino デバイスにリレーするゲートウェイ アプリケーションのコードは、コード ダウンロードに含まれています (msdn.microsoft.com/magazine/msdnmag0314から入手できます)。このプロジェクトは、このコラムへの助言と専門知識の提供を快諾してくれた Clemens Vaster のプロジェクトに基づいています。元のプロジェクトについては、bit.ly/L0uK0v(英語) を参照してください。
このコードについて詳しく調べる前に、必ず Visual Studio 2013 と、Windows Azure SDK for .NET バージョン 2.2 (bit.ly/JYXx5n) をインストールしてください。ソリューションには、次の 3 つのプロジェクトが含まれています。
- ArduinoListener — メインの WorkerRole コードなど
- ConsoleListener — ローカル テストを目的としたコンソール バージョンの ArduinoListener
- MSDNArduinoListener — ArduinoListener 用の Windows Azure 配置プロジェクト
MSDNArduinoListener プロジェクトに含まれている (クラウド配置用とローカル配置用の両方の) ServiceConfiguration.cscfg ファイルを調べると、サービス バス用の接続文字列を保存する設定が見つかります。この値を、手順 1. で取得した値に置き換えます。デバイスからの受信接続用にポート 10100 を定義するなどの残りの設定は、既に構成されています。次に、ArduinoListener プロジェクトの WorkerRole.cs ファイルを開きます。主なコードはこのファイルに記述してあります。
分析が必要な主なセクションは、4 つあります。
まず、TcpListener を作成し、デバイスからの接続を受け入れます。
var deviceServer = new TcpListener(deviceEP);
deviceServer.Start(10);
try
{
do
{
TcpClient connection =
await deviceServer.AcceptTcpClientAsync();
if (connection != null)
{ ...
デバイスとの接続を確立したら、NetworkStream を定義してリッスン モードに設定します。readBuffer 変数には、各 Arduino デバイスから送信された ID 値が格納されています。
NetworkStream deviceConnectionStream = connection.GetStream();
var readBuffer = new byte[64];
if (await deviceConnectionStream.ReadAsync(readBuffer, 0, 4) == 4)
{
int deviceId =
IPAddress.NetworkToHostOrder(BitConverter.ToInt32(readBuffer, 0));
...
次に、deviceId 値に基づくキューが存在しない場合はキューを作成し、メッセージ受信者オブジェクトを定義します (図 3 参照)。メッセージ (キューからのコマンド) を取得するよう、デバイス キュー受信者を非同期モードに設定します。このキューには、モバイル デバイス (Windows Phone など) から送信されたコマンドを保存します。
図 3 キューの作成
var namespaceManager =
NamespaceManager.CreateFromConnectionString(
RoleEnvironment.GetConfigurationSettingValue("serviceBusConnectionString"));
if (!namespaceManager.QueueExists(string.Format("dev{0:X8}", deviceId)))
{
namespaceManager.CreateQueue(string.Format("dev{0:X8}", deviceId));
}
var deviceQueueReceiver = messagingFactory.CreateMessageReceiver(
string.Format("dev{0:X8}", deviceId), ReceiveMode.PeekLock);
do
{
BrokeredMessage message = null;
message = await deviceQueueReceiver.ReceiveAsync();
...
キューでメッセージを受信したら、メッセージの内容を検証します。内容が "ON" または "OFF" コマンドに一致する場合は、この情報をデバイスとの間に確立した接続ストリームに書き込みます (図 4 参照)。
図 4 接続ストリームへの書き込み
if (message != null)
{
Stream stream = message.GetBody();
StreamReader reader = new StreamReader(stream);
string command = reader.ReadToEnd();
if (command != null)
{
switch (command.ToUpperInvariant())
{
case "ON":
await deviceConnectionStream.WriteAsync(OnFrame, 0,
OnFrame.Length);
await message.CompleteAsync();
break;
case "OFF":
await deviceConnectionStream.WriteAsync(OffFrame, 0,
OffFrame.Length);
await message.CompleteAsync();
break;
}
}
}
デバイス接続ストリームへの書き込み処理が成功するまで、メッセージがキューから削除 (message.CompleteAsync) されないことに注目してください。また、接続を維持するために、デバイスから ping ハートビートを送信すると想定しています。この概念実証では、メッセージ受信時にデバイスから確認を受け取るとは想定していません。しかし実際のシステムでは、"コマンド" パターンに従うために確認を受け取る必要があります。
手順 3. ArduinoListener Windows Azure プロジェクトをクラウド サービスに配置する: Windows Azure への ArduinoListener の配置は非常に簡単です。Visual Studio 2013 で、MSDNArduinoListener プロジェクトを右クリックして、[発行] オプションをクリックするだけです。詳細については、「Windows Azure アプリケーションの発行ウィザード」(msdn.microsoft.com/ja-jp/library/windowsazure/hh535756.aspx) を参照してください。このウィザードが完了すると、クラウド サービスが xyz.cloudapp.net に配置されます。この名前は、次の手順で Arduino クライアントを作成する際に必要になるので書き留めておいてください。
手順 4. ゲートウェイ (リスナー) と通信するよう Arduino デバイスをプログラミングする: Arduino デバイスには、シンプルな Web クライアント オブジェクトを使用したネットワーク処理を実行するための、機能豊富なインターフェイスが用意されています。今回のプロトタイプには、Arduino Uno R3 モデル (bit.ly/18ZlcM8、英語) と、対応する Ethernet シールド (bit.ly/1do6eRD、英語) を使用することにしました。Windows を使用して Arduino デバイスをインストール、操作、およびプログラミングするには、bit.ly/1dNBi9R(英語) のガイドに従ってください。最終的には、Arduino アプリケーションという使いやすい IDE を利用することになるでしょう。Arduino アプリケーションでは、スケッチと呼ばれるプログラムを JavaScript を使用して記述できます (図 5 参照)。
図 5 Arduino アプリケーション
図 6 は、手順 3. で作成して現在は Windows Azure に配置している、ArduinoListener と対話するためのスケッチを示しています。
図 6 Arduino デバイス コード
#include #include #include
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network,
// and it's optional if DHCP is enabled.
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xBC, 0xAE };
static const byte deviceId[] = { 0x00, 0x00, 0x00, 0x01 };
static const uint8_t ACK = 0x01;
static const int LED_PIN = 8;
int connected = 0;
EthernetClient client;
StopWatch stopWatch;
long pingInterval = 200000;
void setup() { Serial.begin(9600);
Serial.println("Initialized");
Ethernet.begin(mac);
pinMode(LED_PIN, OUTPUT);}
void turnLedOn(){ digitalWrite(LED_PIN, HIGH);}
void turnLedOff(){ digitalWrite(LED_PIN, LOW);}
void loop() {
if ( connected == 0) {
Serial.println("Trying to connect");
char* host = "xyz.cloudapp.net";
client.setTimeout(10000);
connected = client.connect(host, 10100);
if (connected) {
Serial.println(
"Connected to port, writing deviceId and waiting for commands...");
client.write(deviceId, sizeof(deviceId));
stopWatch.start();
}
else
{
Serial.println("Connection unsuccessful");
client.stop();
stopWatch.reset();
}
}
if (connected == 1)
{
if (stopWatch.elapsed() > pingInterval)
{
Serial.println("Pinging Server to keep connection alive...");
client.write(deviceId, sizeof(deviceId));
stopWatch.reset();
stopWatch.start();
}
byte buf[16];
int readResult = client.read(buf, 1);
if (readResult == 0)
{
Serial.println("Can't find listener, disconnecting...");
connected = 0;
stopWatch.reset();
}
else if (readResult == 1)
{
Serial.println("Data acquired, processing...");
switch ( buf[0] )
{
case 1:
Serial.println("Command to turn led on received...");
turnLedOn();
break;
case 2:
Serial.println("Command to turn led off received...");
turnLedOff();
break;
}
stopWatch.reset();
stopWatch.start();
}
}
}
Arduino のスケッチには、設定とループという 2 つの主なセクションがあります。設定セクションの命令は 1 回実行し、ここで変数を初期化して接続を確立します。この例では、Ethernet クライアントとその関連する値を定義し、(デバッグ目的で) シリアル接続を確立して、LED を接続しているピンを出力ポートとして初期化します。
ループ セクションのコードは繰り返し実行します。ループ セクションのコードには、2 つの主なブロックが含まれています。各ブロックは、Arduino デバイスと Windows Azure クラウド サービスで実行しているリスナーとの間の TCP 接続の状態、つまり接続または切断に基づいています。初めて接続を確立したら、stopWatch オブジェクトで接続の経過時間を追跡し始めます。また、メッセージやコマンドの保存先キューの名前として使用するために、デバイス ID をリスナーに送信します。
接続を確立した後に Arduino の動作を制御するコード ブロックでは、接続作成時点からの経過時間を追跡し、200,000 ミリ秒ごとにリスナーに ping を送信して、コマンドを受信していないときでも接続を維持します。また、このコードでは、リスナーからのデータ読み込みも試行し、データを読み取れたら buf 配列に格納します。値 "1" を検出した場合は LED を点灯し、値 "2" を検出した場合は LED を消灯します。stopWatch オブジェクトは、各コマンドの実行後にリセットします。
デバイスにスケッチをアップロードしたら、このコードを Arduino コントローラー上で無限ループ実行し、クラウド サービスへの接続を試行します。接続したら、どのデバイスと通信しているかクラウド サービスに認識されるよう、デバイス ID を送信します。その後、クラウド サービスからの入力の読み取りを開始し、LED ライトの点灯または消灯をデバイスに命令します (今回の例では、デバイスのデジタル ポート 8 に接続しています)。
手順 5. デバイス キューへの送信を行う Windows Phone クライアントを作成する: デバイスと対話するには、デバイス キューにメッセージを送信するだけです。このコラムの冒頭で述べたように、Windows Azure サービス バスでは、複数のプログラミング言語でデバイスと対話できる REST インターフェイスを提供しています。このコラムの冒頭で述べたように、Windows Azure サービス バスでは、複数のプログラミング言語でデバイスと対話できる REST インターフェイスを提供しています。ソース コードは、コード ダウンロードの MSDNArduinoClient という Visual Studio 2013 プロジェクトにも含まれています。図 7 は、Arduino デバイスにコマンドを送信するクライアントのメイン画面を示しています。
図 7 Windows Phone クライアントのインターフェイス
他のモバイル デバイス (iOS、Android など) 用に同様のクライアントを作成することは、難しくありません。なぜなら、その多くには、HTTP 要求クライアントを使用して REST コマンドを生成するライブラリが用意されているためです。さらに、Java、PHP、Ruby などの従来の言語を使用して Windows Azure サービス バスと直接対話することもできるので、クライアント作成作業が簡単になります。このような SDK はオープン ソース ライセンスに基づいて公開されており、github.com/WindowsAzure(英語) から入手できます。
まとめ
Windows Azure サービス バスを使用したモノのインターネット アーキテクチャを構築してデバイス接続やサービス接続を管理すると、高価な VPN ソリューションを使用しなくても、クライアント単位の保護、拡張、およびアドレス指定を簡単に行うことができます。さらに、接続が不定期に切断するシナリオに、効率的に対処できるというメリットもあります。キューは、デバイスとサービスの間でメッセージを交換する専用受信箱の役割を果たし、実際によくあるさまざまな通信のユース ケースやパターンをサポートしています。Windows Azure は、相互接続した大量のセンサーやメーターに必要なサービスを配置するための、信頼性があって地理的に分散している堅牢なインフラストラクチャを提供します。この傾向は、今後数年間は強まり続けるでしょう。
Bruno Terkaly は、マイクロソフトの開発者エバンジェリストです。彼の深い知識は、多数のプラットフォーム、言語、フレームワーク、SDK、ライブラリ、および API を使用してコードを作成し、現場で長年の経験を積むことで得られたものです。コードの作成、ブログ、クラウド ベースのアプリケーション構築 (特に、Windows Azure プラットフォームの使用) に関するライブ プレゼンテーションに携わっています。ブログは、blogs.msdn.com/b/brunoterkaly(英語) で公開されています。
Ricardo Villalobos は、経験豊かなソフトウェア アーキテクトとして、多くの業界の企業用アプリケーションを 15 年以上にわたって設計および作成しています。さまざまな技術認定資格の保持者であり、ダラス大学で経営管理の修士号を取得しています。彼はマイクロソフトの DPE Globally Engaged Partners チームのクラウド アーキテクトを務め、世界中の企業の Windows Azure ソリューション実装を支援しています。ブログは blog.ricardovillalobos.com(英語) で公開されています。
Terkaly と Villalobos は、大規模な業界カンファレンスで共同講演を行っています。彼らは、Windows Azure の詳細に取り組む読者の皆さんに、可用性に関する問い合わせを奨励しています。Terkaly の連絡先は bterkaly@microsoft.com(英語のみ) で、Villalobos の連絡先は Ricardo.Villalobos@microsoft.com(英語のみ) です。
この記事のレビューに協力してくれた技術スタッフの Abhishek Lal と Clemens Vasters に心より感謝いたします。