はい、IoTってついているので、やっぱり、ネットワークやクラウドにつながないとね。
http://aka.ms/IoTKitHoLから公開中の現状のトレーニングコンテンツは.NET Micro Frameworkデバイスをつなぐのですが、公開されているサンプルや一つ前のポストで、.NET MFの代わりにRaspberry PI2+I2Cセンサーで代替できるわけですね。
ここでは、2015年5月31日現在の手に入る環境で、IoT Kit HoLで扱っているクラウド接続+αを紹介していきます。全て、Visual Studio 2015RCのC#、Windows Universalアプリでの開発を前提です。
先ずは、HTTP REST APIにGETでアクセスする方法。Step 1接続の一番最初でやっている、ヘッダーにDeviceIdとメッセージをセットして、サーバーから戻りのメッセージを受け取るやつです。
var client = new Windows.Web.Http.HttpClient();
client.DefaultRequestHeaders.Add("device-id", deviceId.ToString());
client.DefaultRequestHeaders.Add("device-message", "Hello from RPi2");
var response = client.GetAsync(new Uri("http://egiotkitholservice.azurewebsites.net/api/DeviceConnect"), HttpCompletionOption.ResponseContentRead);
response.AsTask().Wait();
var responseResult = response.GetResults();
if (responseResult.StatusCode == Windows.Web.Http.HttpStatusCode.Ok)
{
result = true;
var received = await responseResult.Content.ReadAsStringAsync();
Debug.WriteLine("Recieved - " + received);
}
はい、Web HTTP RESTでアクセスするには、Windows.Web.Http名前空間のHttpClientを使います。ヘッダーに値を設定するには、DefalutRequestHeadersプロパティにAddすればできます。GETでアクセスするので、GetAsyncをコールします。ここで一つポイント。GetAsyncメソッドをコールする際、いつものノリで、awaitとかやっちゃうと、そこで処理がブロックされます。これ、Raspberry PI2での実行に限った話ではなく、Universal Apps系全般でそうです。なので、そのまま戻り値を受けて、AsTask().Wait()というメソッドをコールしてください。これで、GetAsyncでサーバーにアクセスしに行き、サーバー側での処理が終わって、戻りメッセージを受け取るという一連の流れが終わって復帰します。HTTP RESTアクセスの結果は、GetResultsメソッドで取出し。ステータスやサーバーからの応答メッセージは、GetResultsメソッドで取り出した変数のStatusCodeプロパティや、ContentからReadAsStringAsyncメソッドで取出し可能。
次に、HTTP REST APIのPOST。JSONでメッセージを送信する方法です。
温度とデバイスID、計測時間を送信するとしましょう。先ずは、送信データパケットのフォーマットを規定するデータモデルクラスを定義します。ソースコードの先頭の方に、System.Runtime.Serialization をusing宣言加えてください。
[DataContract]
public class SensorPacket
{
[DataMember]
public string DeviceId { get; set; }
[DataMember]
public double Temperature { get; set; }
[DataMember]
public DateTime MeasuredTime { get; set; }
}
これを使って、POSTするコードは、
var packet = new SensorPacket()
{
DeviceId = deviceId.ToString(),
Temperature = temperature,
MeasuredTime = DateTime.Now
};
var serializer = new DataContractJsonSerializer(typeof(SensorPacket));
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, packet);
ms.Position = 0;
StreamReader sr = new StreamReader(ms);
var content = new Windows.Web.Http.HttpStringContent(sr.ReadToEnd(), Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");
var client = new Windows.Web.Http.HttpClient();
client.DefaultRequestHeaders.Accept.Add(new Windows.Web.Http.Headers.HttpMediaTypeWithQualityHeaderValue("text/json"));
var response = client.PostAsync(new Uri(webApiEndPoint + "/api/Win10IoT"), content);
response.AsTask().Wait();
var responseResults = response.GetResults();
こんな感じ。DataContractJsonSerializerというクラスを使って、SensorPacketクラスのインスタンスをJSON形式にシリアライズします。シリアライズした文字列を、HttpClientインスタンスで送るため、HttpStringContent(別の名前空間にも同一名のクラスがあるので注意)インスタンスに変換します。
POSTメソッドで送るので、PostAsyncメソッドで送付。後はGetAsyncと同じようにハンドリングします。
送られるデータは、{"DeviceId":"....","Temperature":24.354, "MeasuredTime":"2015/06..."} というようなJSONです。ヘッダーのメディアタイプへの設定はデフォルトで既に用意されているので、DefaultRequestHeaders の AcceptプロパティにAddします。
簡単ですね。お、これができれば、Mobile Apps(旧Mobile Service)への接続も簡単だ!なにしろ、ヘッダーにX-ZUMO-APPLICATIONにアクセスキーセット等すればいいからね…いやそんなめんどくさいことしなくていいです。
Mobile Appsにつなぎたい場合は、ソリューションエクスプローラーで参照を右クリック⇒Nugetパッケージの管理を選択し、”Mobile Service”と検索窓に入力して、WindowsAzure.MobileServiceをInstallすればOK。後は、普通のUniversal Windows Appsと同じように、App.xaml.csのAppクラスに、
public static MobileServiceClient MobileService = new MobileServiceClient("url","accesskey");
と追加して
var table = App.MobileService.GetTable<SensorData>();
でテーブル参照取得して、登録レコードの取出しは、
var records = await table.ToEnumerableAsync();
foreach (var record in records)
{
var deviceId = recored.DeviceId;
...
}
とか、新しい行を追加したければ、
await table.InsertAsync(new SensorData() { DeviceId= deviceId.ToString(),... });
とかすればいい。
次はSignalR。これも、Nugetで、SignalRを検索して、Microsoft.AspNet.SignalR.Client をインストール。…すればいいはずなのだが、現時点では、一部、CPUアーキテクチャ依存の部分があるらしく、そのアセンブリを置き換えないと動かない。
http://dotnetbyexample.blogspot.jp/2015/05/getting-signalr-clients-to-work-on.html
https://github.com/LocalJoost/SignalRFix
この辺を参考にしてほしい。後は普通に
var hubConnection = new HubConnection("HUBが実装されたWebサイトのURL”);
var ledProxy = hubConnection.CreateHubProxy("LEDHub");
await hubConnection.Start();
var updateSubscribe = ledProxy.Subscribe("Update");
updateSubscribe.Received += UpdateSubscribe_Received;
とか書けば、SignalRのメッセージは受信できる。
じゃぁ、後は、Event Hubね…ということなのだが、残念ながら、Event HubのNugetパッケージのWindowsAzure.ServiceBusは、Windows 10未対応。このライブラリ使うのが一番簡単なのだが、現時点ではAMQPNetLiteでがまん(あれ?IoT Kit HoLで公開しているStep1のやりかたそのまま使えるね)ってことで、よろしく。