IoT Hub から送信されるメッセージを Windows 10 IoT Core デバイスで受信する

Azure IoT Hub の特徴の一つが、IoT Hub からデバイス個別にメッセージをデバイス個別に送信する機能です。

今回は、クラウドから送信されるメッセージを Windows 10 IoT デバイスで受信する方法。
本稿は「Windows 10 IoT Core から IoT Hub にメッセージを送信するアプリをスクラッチで書いてみる」の関連、続きの記事です。新規プロジェクトの作り方は本稿では説明していないので、まずはこちらの記事で読んでから本稿を読むことをお勧めします。


■ IoT Hub からのメッセージの受信の仕方

IoT Hub からメッセージを受信するには、DeviceClient クラスの ReceiveAsync メソッドを使います。

var message = await _client.ReceiveAsync();

こんな感じ。
※ DeviceClient は、DeviceClient.CreateFromConnectionString(ConnectionString); で事前にインスタンス化しておきます。

注意点としては、メッセージを取得した時、またはタイムアウト(デフォルトでは1分)した時(=指定の時間内にメッセージが届かなかった時)に、非同期で ReceiveAsync メソッドが返ってくるところ。タイムアウト時間を明示的に指定できますが、どちらにしてもメッセージがなければ null が返ってくるので、次の ReceiveAsync でメッセージ取得を待ちます。

もう一つ、メッセージを取得して処理に成功したら、DeviceClientCompleteAsync メソッドを呼び出すこと。
サーバー側では ReceiveAsync されてメッセージを渡すと、一時的にそのキューメッセージが不可視になり、一定時間後に改めてキュー上でメッセージが可視になり、改めて同じメッセージが取得可能になります。ということで、処理後には必ず CompleleteAsync してください。

■ サンプルコード

以上を、実際のコードで見てみると以下の通り。

using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;

namespace IoTHubSendMessageDemo
{
    internal class SensorDevice
    {
        private readonly DeviceClient _client;
        private const string ConnectionString = "HostName=[ホスト名].azure-devices.net;DeviceId=[デバイスID];SharedAccessKey=[アクセスキー]";
        private const string DeviceId = "[デバイスID]";

        private double _delaySeconds = 5;

        public SensorDevice()
        {
            _client = DeviceClient.CreateFromConnectionString(ConnectionString);
        }

        internal async Task Run()
        {
            ReceiveMessageAsync();

            while (true)
            {
                var data = new SensorData
                {
                    DeviceId = DeviceId,
                    SensorValue = new Random().NextDouble()
                };

                var dataString = JsonConvert.SerializeObject(data);
                var message = new Message(Encoding.ASCII.GetBytes(dataString));
                await _client.SendEventAsync(message);

                Debug.WriteLine(dataString);

                Task.Delay(TimeSpan.FromSeconds(_delaySeconds)).Wait();
            }
        }

        private async void ReceiveMessageAsync()
        {
            while (true)
            {
                var message = await _client.ReceiveAsync();
                if (message == null)
                    continue;

                var msgString = Encoding.ASCII.GetString(message.GetBytes());
                Debug.WriteLine("Received a message : " + msgString);
                if (double.TryParse(msgString, out _delaySeconds))
                    Debug.WriteLine("Delay Seconds : " + msgString);

                await _client.CompleteAsync(message);
            }
        }
    }
}

■ サンプルコードの動作

念のためにサンプルコードの動作を説明します。

元になるコードは、こちらの記事で作った、疑似的なセンサーデータを送信するコードです。これにクラウドからのメッセージを受信する処理を追加しました。クラウド側は今回作っていないので、Device Explorer を使ってデータを送信してください。

2016-12-31 14-27-08

受信したデータの処は簡単のために数値のみです。(double.TryParse しているのでそれ以外のデータは捨てています)
受信した数値はセンサーデータ送信の間隔(秒)として使います。大きな値を指定すると間隔をあけてゆっくりとセンサーデータをアップロードするようになります。

2016-12-31 14-27-42

■ デバイスからのデータ送信のタイミングでメッセージを受信することに注意

この方法では、IoT Hub からデバイスへのメッセージを随時受信するわけではないことに注意してください。
デバイスから IoT Hub に接続したタイミングで、デバイス専用のキューにメッセージが積まれていた場合に メッセージを1件取得できるというものです。

このためデバイスから定期的に接続を行う、一般的にはセンサーデータの送信する必要があります。センサーデータ送信間隔によっては IoT Hub からのメッセージ取得するまでに時間がかかることに注意してください。だからと言って、通信の間隔が短すぎると余計な通信が発生してしまいます。適切な間隔を指定することが大事です。

万能な通信機能ではありませんが、デバイスごとに通信する内容を管理できますし、送信失敗した場合のリトライまで IoT Hub 側で責任を持ってくれます。
動きを理解した上で、デバイスとクラウドとの双方向の通信を使ってみてください。

Windows 10 IoT Core から IoT Hub にメッセージを送信するアプリをスクラッチで書いてみる

ちょっと思うところがあり、Windows 10 IoT Core から IoT Hub にメッセージを送信するアプリケーションをスクラッチで書いてみます。
(※先日の機械学習の勉強会で、「デバイス側の話も聞きたい」という意見をいただいたので。まあ、過去の勉強会でやった内容ではあるので、その時に参加してもらえれば・・・ということではあるのですが。)

これまで Windows 10 IoT Core のコーディングの話をした際には、IoT キットハンズオンの内容をベースにしてきました。IoT 全体を俯瞰できるようスピードアップするため、Windows 10 IoT 部分の基本的なコーディングが完了した状態の資料です。
ただそれと引き換えに、新規プロジェクトで Windows 10 IoT Core から IoT Hub にメッセージを送信する手順はお話できていませんでした。
IoT Hub の情報って意外と少ない気がするのです・・・。そこで、基本に立ち返ってみます。・・・前置きが長くなりました (汗

 


■ プロジェクト新規作成

プロジェクトテンプレートは、[Windows]-[ユニバーサル] の [空白のアプリ] です。UI を持たないセンサーデバイスの場合は、空白のアプリで問題ありません。

2016-12-23 22-12-43

 

■ IoT 用拡張機能ライブラリの参照を追加

“Windows IoT Extensions for the UWP”の参照を追加します。[Universal Windows]-[拡張] にあります。複数バージョンが見つかるかもしれませんので、どれを参照するかはターゲットの Windows 10 IoT 次第。

2016-12-23 22-15-44

なお今回のアプリはセンサーモジュールを接続していない、環境データの測定などを行わない、単なる「エミュレーター」です。ということで、実は今回に限り IoT Extensions の参照追加は不要です。
なのですが、一般には必須の手順なのでここで紹介しました。

 

■ NuGet パッケージの追加

Windows 10 IoT アプリから Azure IoT Hub にメッセージを送信するために必要な NuGet パッケージは2つ。

  • Microsoft.Azure.Devices.Client
  • Newtonsoft.Json

この2つがあれば、びっくりするくらい簡単に IoT Hub にメッセージを送信できます。

2016-12-23 22-19-572016-12-23 22-20-47

 

■ 送信データの Entity クラスを作成

いよいよお楽しみのコーディング。

まずは送信データのエンティティクラスを作成します。こんな感じ。

namespace IoTHubSendMessageDemo
{
    internal class SensorData
    {
        public string DeviceId { get; set; }
        public double SensorValue { get; set; }
    }
}

 

■ MainPage.xaml.cs の編集

この部分はアプリによって変わる部分だと思いますが、例えば今回は MainPage.xaml の Page_Loaded メソッドで、データ送信クラスを操作してみます。

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace IoTHubSendMessageDemo
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void Page_Loaded(object sender, RoutedEventArgs e)
        {
            var device = new SensorDevice();
            await device.Run();
        }
    }
}

 

■ メッセージ送信クラスを作成

IoT Hub にメッセージを送信するクラスです。「本体」の部分です。

メッセージ送信を行うのは、SDK で提供されている DeviceClient です。スタティックな CreateFromConnectionString メソッドを使うのがいいです。必要な情報は IoT Hub への接続文字列ですが、この中には DeviceId も含まれているので、あらかじめデバイスが登録されていることが前提。
ではデバイスの登録はどうするかというと、

  • IoT Dashboard
  • Device Explorer
  • 自作のデバイス管理アプリ(例えば、こんなもの

2016-12-23 22-32-522016-12-24 21-43-24

のいずれかを使います。

DeviceClient が作れたら、メッセージ送信の手順は、

  1. 送信のためのエンティティを作る
  2. エンティティを JSON で永続化
  3. Message クラスを作る(エンティティを永続化したもののバイト配列をコンストラクターに渡す)
  4. DeviceClient の SendMessageAsync メソッドで IoT Hub にメッセージ送信

これだけです。

using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;

namespace IoTHubSendMessageDemo
{
    internal class SensorDevice
    {
        private readonly DeviceClient _client;
        private const string ConnectionString = "HostName=[ホスト名].azure-devices.net;DeviceId=[デバイスID];SharedAccessKey=[キー]";
        private const string DeviceId = "SendMsgDevice";

        public SensorDevice()
        {
            _client = DeviceClient.CreateFromConnectionString(ConnectionString);
        }

        internal async Task Run()
        {
            for (var i = 0; i < 10; i++)
            {
                var data = new SensorData
                {
                    DeviceId = DeviceId,
                    SensorValue = new Random().NextDouble()
                };

                var dataString = JsonConvert.SerializeObject(data);
                var message = new Message(Encoding.ASCII.GetBytes(dataString));
                await _client.SendEventAsync(message);

                Debug.WriteLine(dataString);

                Task.Delay(TimeSpan.FromSeconds(5)).Wait();
            }

            Debug.WriteLine("End of Run Method");
        }
    }
}

IoT Hub にちゃんと届いているのは、Device Explorer で確認できます。

2016-12-23 23-25-41

 

以上で、メッセージ送信は完了です。
データを集めて、集めたデータを活用するには、大量のデータをクラウドに送ることが必要。今回は、そのお話でした。

 

送信するべきデータ(センサーデータ)はどうやって取得するのか、IoT Hub に送ったデータはどうやって活用するのか(Stream Analytics)は、別のテーマなので今回は省略。別に機会にでも(または このあたり を参考に)。

「Windows 10 IoT Core + IFTTT + Skype で "お手軽" データ監視」LTしました (西東京版 IoTLT!IoTLT八王子 vol.1 (2016年7月25日(土) 開催))

最近話題の IoTLT。その西東京版が 2016年8月25日(木) に開催されました。
7月に勉強会会場を貸してくださった WakU2 での開催ということで、参加&LTしました。

テーマは「Windows 10 IoT Core + IFTTT + Skype で “お手軽” データ監視

https://docs.com/d/embed/D25193007-6264-1364-6260-000902558243%7eBfe5a7bff-fc39-9c7d-d35f-86e930988702

何を喋ろうかな~から完成まで30分という “お手軽” ぶり。
Windows 10 IoTIFTTTのおかげです。
7月だったか、IFTTT に Skype Channel が追加されたので、せっかくなら使ってみようかということで決めました。
IFTTT については去年の今ごろも LT しました。

IFTTT はビジネスにはさすがに信頼姓が・・・というところはありますが、プロトタイプやプライベートなら特に問題なく使えそうです。
IFTTT の Maker Channel に JSON なデータを投げるだけ、Skype に届くまでのタイムラグもなかなか短く、びっくりするほどお手軽に楽しめます。

「お手軽」とはいえ、一度具体的な手順を見てみたいという人もいるかも。
がんばって作業手順の動画を用意したい思います。長~い目で見守ってください。
それまでは資料をどうぞ。

Windows 10 IoT Core をセキュアにするために、IoT Core Dashboard を使って接続情報をデバイスに配置する(ただし、まだ課題あり)

■IoT Core Dashboard の “Azure に接続” タブでできること

最近(この一ヶ月以内くらい)、IoT Core DashboardIoT Hub を作れるようになりました。

IoT Core Dashboard の“Azure に接続”タブでできることは以下の3つ。

  1. IoT Hub の作成
  2. デバイス ID の作成
  3. デバイスへのプロビジョニング(ドロップダウンの項目名としては“プロビジョニング対象のデバイス”)

1, 2 でできることと操作方法は、先日の勉強会の資料 を参照。

本稿では、3つ目の「デバイスへのプロビジョニング」について取り上げます。
ちなみに本稿のネタ元は Windows Developer ブログ


■IoT Hub に接続するために必要な情報

デバイスを IoT Hub に接続するためには、

  • デバイス ID
  • 接続文字列(IoT Hub のエンドポイントやアクセスキーを含む文字列

が必要です。

一番お手軽な方法は、const で持ったり、config ファイルなどに定義しておくやり方。ただし、デバイスごとにビルドが必要な const は検証以外ではありえないし、configだとしても管理が面倒&平文だと情報が漏れてしまった時に問題が起こるという問題がある。

次に考えられる方法は、このブログではすっかりお馴染みに MS 太田さん作の こちらのハンズオン資料 で行っているように、IoT Hub への接続に必要な情報を返す Web サービスを立てるやり方。この方法は接続情報を返すサービスのエンドポイント自体はデバイスに平文で保持することになります。


■デバイスへのプロビジョニング

よりセキュアに IoT Hub への接続情報を保持するために、Windows 10 IoT と IoT Core Dashboard で提供しているのが、デバイスの TPM を利用する方法。
※Raspberry Pi は実際には TPM を載せていないので、エミュレーターを使います。つまり現時点では、本稿で紹介している方法はセキュアではないということ。今後 and/or 他のデバイスに期待しましょう。(ラズパイの価格を考えると TPM を載せるのは難しいかな・・・)

デバイスの TPM に接続情報を保存するのはとても簡単。

  1. Dashboard で IoT Hub を作成する、または既存の IoT Hub に接続する。
  2. デバイス ID を新規登録する、または既存の IoT Hub に登録済みのデバイス ID を選択する。ここまでは先日の勉強会でやった内容。
  3. Windows 10 IoT Core デバイスを動作させる。
  4. Dashboard の [Azure に接続] タブで、IoT Hub とデバイス ID を配置したいデバイスを [プロビジョニング対象のデバイス] で指定する。
  5. [プロビジョニング] ボタンをクリックする。

以上で終了。

2016-08-07 20-15-042016-08-07 20-17-05

実運用では、多数のデバイスに接続情報を保存するにも、もっと効率が良い方法を検討するほうがいいと思いますが、検証フェーズや仕組みを覚える目的には上記の手順で OK。

Device Portal でデバイスを覗いてみると、確かに指定したデバイスの TPM に登録されていることが分かります。

2016-08-07 20-18-29

ただし上でも触れたとおり、Raspberry Pi 2/3 は TPM を載せていないので、現時点ではエミュレーターを使っています。残念ながらセキュアではありません(他の方法より劣っているという意味ではありません、念のため)。


■TPM に保存した情報をアプリで利用する方法

TPMに接続情報を保存できたので、次はアプリでそれらの値を参照する方法が必要です。
Microsoft.Devices.Tpm クラスが面倒を見てくれます。わかりやすい名前ですね。

  1. Visual Studio 2015 で  UWP プロジェクト(空のプロジェクトでも OK)を作成
  2. IoT に最低限必要なライブラリを参照。具体的には “Windows IoT Extensions for the UWP”と “Microsoft.Azure.Devices.Client”の二つ。
    2016-08-07 20-24-202016-08-07 20-23-31
  3. TPM を利用するためのライブラリを NuGet からダウンロード。 “Microsoft.Devices.Tpm”がそれ。
    2016-08-07 20-22-31
  4. コード中では TpmDevice クラスを利用します。デバイスには複数の TPM を持てますが、今回は 0番目。
    GetHostName, GetDeviceId, GetSASToken の各メソッドで必要な情報を読み出せます。
    2016-08-07 20-26-35
  5. IoT Hub に接続するには DeviceClient クラスを使います。
    上のコードで取得した値を Create メソッドに渡すと IoT Hub に接続されます。あとはデータを送るのも受けるのも、先日の勉強会ハンズオン資料の通り。

実は簡単にセキュアな情報を利用できるのでした。
(上にも書いたとおり、Raspberry Pi では現時点ではエミュレーターでの動作なのですが・・・)


■DragonBoard 410c の場合

TPM が載っている Windows 10 IoT Core 対応ボードということで、DragonBoard 410c でも試してみました。

残念ながら今のところ、プロビジョニングの操作でエラーが発生して、接続情報を配置することができていません。それこそセキュリティ上の問題だと思いますが、原因はまだ分かっていません。すいません。
これについては引き続き調査してみたいと思います。

2016-08-07 20-28-182016-08-07 20-29-59

DragonBoard 410c には確かに TPM が載っているので、この操作ができれば Raspberry Pi に対するメリットになりますね。

 

以上、まだ課題が残っている状態ですが、セキュアに IoT Hub に接続する方法の紹介でした。

「IoT キットハンズオンのソースコード解説します (クラウド編 Part 1)」セッション資料を公開しました (Techfair.jp 勉強会 2016年7月30日開催)

まとめ(というより、ここでのお知らせ)がすっかり遅くなりましたが、7月30日(土) に

IoT キットハンズオンのソースコード解説します (クラウド編 Part 1)

なる勉強会を開催しました。
会場は、初めての八王子開催、WakU2 さんのスペースでした。都心ではないということで実は少し集客を心配したのですが、公開から1日経たずに定員に達しました。


IoT のハンズオンを受けて、また各種イベントなどで技術者の皆さんとお会いした時に、「ハンズオンで動きは分かったけど、仕組みや中味が分からないので解説してほしい」という声をたくさんいただきました。
IoT は構成要素がたくさんあり、全体を俯瞰できるハンズオンは相当のボリュームで 1日がかりなので、解説までできないのは当然と言えば当然。

そこで(ハンズオンは自習していただくとして)、中味の解説をしようというのが今回の勉強会。
ちなみにマイコンボード (.NET Micro Framework on GR-PEACH) に焦点を当てたのが前回の勉強会 です。
また今回のタイトルに “Part 1”と付けていることから分かるように、まだ扱っていない構成要素を解説する勉強会も今後開催したいと考えています。

今回は、IoT Hub, Stream Analytics という、IoT の中心と言っていいサービスをメインに、データ入力として Windows 10 IoT Core、出力例として Power BI, Excel を紹介しました。


休憩を挟みながら、3時間半のセッションであったので(いや、疲れたw、というより最後は声が出なかった・・・)、資料も3部構成。

https://docs.com/d/embed/D25193249-9793-6065-7830-000238822446%7eBfe5a7bff-fc39-9c7d-d35f-86e930988702

https://docs.com/d/embed/D25193249-9624-5155-0340-001664257068%7eBfe5a7bff-fc39-9c7d-d35f-86e930988702

https://docs.com/d/embed/D25193249-9523-3647-4060-001028506262%7eBfe5a7bff-fc39-9c7d-d35f-86e930988702


今回好評だったので、リピートセッション続編も検討中です。
ただし今のところ、Techfair.jp でのハンズオンは予定していません。それを実施するコミュニティの体力(スタッフ)も、資材(マイコンボードなど)も、残念ながら持っていないため。
その代わり、今回のような形態での勉強会は今後も開催します。ご理解ください。

まずは上の資料とハンズオン資料で、IoT の理解を深めてください!