はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

M5Stackで.NET nanoFrameworkからAzure IoT Hubに繋いでみた

前回

hatsune.hatenablog.jp
前回は、.NET nanoFrameworkでの開発準備とM5Stack Core 2に接続したセンサーから気圧、気温、湿度などを取得しました。
今回は、M5Stack Core 2からAzure IoT Hubに取得したセンサー値を送信してみたいと思います。

事前準備

センサーについて

M5Stack Core 2のPORT.A.I2C端子に接続して使用するENV-IIIユニットを使用します。

Install the nanoFramework firmware

M5Stackに使われているESP32にはnanoFrameworkは標準インストールされていないので、nanoFrameworkをインストールします。

接続ポート番号の確認

USBでM5Stack Core 2をPCに接続したら、デバイスマネージャーで「CP210x」が接続されているポート番号を確認します。今回の環境では「COM4」が該当しました。

Flasherアプリケーションのインストール(インストール済の場合は不要)

OSの[スタート]メニューから「Developer PowerShell for VS2022」を起動します。

dotnet tool install --global nanoff

nanoFrameworkfファームウェアをインストール(インストール済の場合は不要)

今回使用するM5Stackは、M5Stack Core 2になります。
このM5Stack Core 2をターゲットにして「COM4」経由でnanoFrameworkをアップロードします。

nanoff --target M5Core2 --update --serialport COM4

Device Explorerでの接続確認

nanoFrameworkファームウェアをインストールしたあとにVisual Studioを起動してDevice Explorerをみると、「M5Core2 @ COM4」と表示されるようになります。

nanoFrameworkファームウェアは、インストールしたあとにnanoFramework以外の別イメージをM5Stack Core 2に転送(Burn)してしまうと消えてしまうので、Device Explorerに表示がないような場合は、再度、インストールをしてからVisual Studioを起動すれば表示されるようになります。

Visual Studioの準備

Visual Studioを機能拡張する

Visual Studioには.NET nanoFramework Extensionをインストールして機能拡張しておきます。
この機能拡張によりnanoFrameworkアプリのテンプレートが追加されます。
このテンプレートで作成したプロジェクトには、NuGetから自動的に「nanoFramework.CoreLibrary」ライブラリが追加されています。

「nanoFramework.M5Core2」ライブラリを追加する

今回は、M5Stack Core 2を使うので、「nanoFramework.M5Core2」ライブラリを手動でNuGetから追加します。

ここまでが、M5Stack Core 2を使うアプリ開発を行う上での共通の事前準備となります。

Azureの準備

Azrue側のサービスは、Azure IoT Hubを使います。
Azure IoT Hubを使うことで、ゼロから設計および構築をしなくても「セキュリティが担保された通信」「スケーリング」「正常性監視」「可用性」を確保しつつデバイスからのセンサー値の収集が容易にできます。
また、運用自体も利用しているAzure全体の運用の中に組み込むことで、運用負荷が著しく増加するということもありません。

IoT Hubの使用プロトコルについて

Azure IoT Hubは、MQTT (Message Queueing Telemetry Transport)、Http、AMQP (Advanced Message Queuing Protocol)など様々なプロトコルに対応しています。
今回のサンプルでは、「小さい」「大量」のデータを「低遅延」で「双方向」に通信できるMQTTを使います。

Azure IoT Hubを準備するには

Azure IoT Hubを使用するためには、まずは、Azure IoT Hub自体を作成して、そこに接続するデバイスを定義していきます。

Azure IoT Hubを作成する

Azure IoT Hubの作成は、Azure管理ポータルでリソースを作成するだけで簡単にできます。
Azure管理ポータルにサインインしたら、[リソースの作成]で「IoT Hub」を検索し、[作成]をクリックしてリソースを追加します。

プランで無料を選択する

Azure IoT Hubの料金プラン (課金額) は、作成時や作成後に指定できます。無料プランは、IoT Hubでは「F1:Freeレベル」という表記になります。

スケーリングが1だったり、「Defender for IoT」も有効にできなかったりといくつかの制限はありますが、無料プランでも基本的な機能は備えていますので、動作確認や数台を接続して試験するような場合に便利です。

Azure IoT Hubにデバイスを定義する

IoT Hubが作成できたら、その中に「IoTデバイス」を定義します。

[IoTデバイスの追加]をクリックして、「デバイスID」「認証の種類」を選んで、[自動生成キー]にチェックを入れて追加をすれば、IoTデバイスからIoT Hubに接続するための接続文字列が生成されます。

M5StackでAzure送信

M5Stack Core 2をAzure IoT Hubに接続するには「nanoFramework.Azure.Devices.Client」ライブラリを使います。

依存関係にあるライブラリを確認してみると、MQTT関連のライブラリも含まれていますね。

Azure TLS証明書をM5Stack Core 2に登録

.NET nanoFrameworkでAzure IoT Hubに接続するためには、ルートCA証明書が必要になります。

ルートCA証明書の取得

ルートCA証明書は、https://docs.microsoft.com/ja-jp/azure/security/fundamentals/tls-certificate-changesの中から「Baltimore CyberTrust Root」をダウンロードして取得します。

ルートCA証明書の登録

取得したルートCA証明書は次のいずれかの方法で利用します。

  1. ソースコードに埋め込む
  2. リソースとしてバイナリに同封
  3. バイスにあらかじめアップロード

今回は「リソースとしてバイナリに同封」方法を採用します。
まず、プロジェクトにリソースファイルを追加します。

次にリソースファイルで[リソースの追加]-[既存ファイルの追加]でダウンロードしたルートCA証明書ファイルを追加します。

WiFiと接続

WiFiとの接続には、最寄りのアクセスポイントへの接続情報が必要です。
gist.github.com
WiFiNetworkHelper.ConnectDhcpメソッドでアクセスポイントのSSIDとパスワードを指定して接続が成功すれば、IPアドレスが割り当てられて、メソッドはTrueを返却してきます。
ここではWi-Fi接続が成功するまで、0.5秒間隔で自動リトライするようにしています。
例えば、アクセスポイントの電源がはいっていないなどであれば電源がはいれば自動的に接続が確立できます。

Azure IoT Hubと接続

gist.github.com

自動リトライについて

実際に動作させてみると、IoT Hubとの接続に失敗するケースがあります。
リトライで解消はできるのでサンプルコードのように自動再接続のロジックを入れておくのがよいでしょう。

ルートCA証明書について

事前にリソースとして組み込んでいるルートCA証明書を使ってX509Certificateを生成してから接続します。IoT Hubとの接続方式はSAS(対象キー)方式ですが、このようにルートCA証明書を使っての接続になります。
AzureポータルでDeviceを登録するときには「X509CA署名済」という認証方式もありますので、SAS方式の場合はルートCA証明書などは不要かと思ってしまうかもしれませんが、対象キー方式の時はデバイス側にルートCA証明書を入れておくと覚えておくとよいでしょう。

Azure IoT Hubへデータ送信

gist.github.com

Azure Iot Hubからデータ受信

gist.github.com

実機へのデプロイが失敗したときは

Visual Studioから実機へのデプロイは失敗します。対処方法はいろいろあります。

  1. Device Explorerの再表示(COMポート再スキャンが行われるので)
  2. M5Stack Core 2の電源ボタン長押しで強制終了と、電源ボタン再度クリックによる電源再投入
  3. M5BurnerによるCore2FactoryTestイメージの再投入(nanoFrameworkなども消えます)

改良が必要なポイント

ネットワークが途中で切断されてしまった場合

WiFi再接続、IoT Hub再接続などが必要ですが、本サンプルはそのあたりの対応が抜けています。
SendMessageの戻り値がfalseのときは、Client.IsConnectedプロパティを確認してfalseだったらネットワーク再接続を再実施するようなロジックが必要です。

バイスIDをAzrue IoT Hubへデバイス側から登録

今回のサンプルでは、デイバスIDをAzure IoT Hub側で登録して、それをコードの中に記述していました。
利用デバイスが1つだけであればそれでもいいのですが、複数のデバイスをサポートし、また、どのデバイスからのデータかを判断したいような場合は、

  1. コードでデバイス自体からユニークなデバイスIDを取得
  2. 取得したデバイスIDでAzrue IoT Hubにデバイスを登録

というような流れが必要です。

データ取得間隔の安定化

今回のサンプルでは、「Azure IoT Hubにデータ送信後10秒経過したらセンサー値を取得して再度送信」という時間間隔でした。
しかし、この方法ではデータ送信などが遅延した場合などにセンサーからのデータ取得時間がずれていく可能性があります。
センサー値自体の取得間隔をきちんとしたいということであれば、

  1. タイマーなどで一定間隔でセンサー値取得
  2. 取得したセンサー値はキューに保存
  3. 別スレッドでキューを取り出してシーケンシャルにAzure IoT Hubに送信

のような処理方式が必要です。

最後に

.NET nanoFrameworkには、Azure IoT Hubのライブラリもあり比較的簡単にコードを書くことができました。
しかし、ルートCA証明書が必要な点などが明確に書かれた情報が少なく、DeviceClientのOpenをしたときのエラーをなかなかとることができませんでした。
このブログエントリで同じことに悩む人が1人でもすくなくなってくれたら嬉しいです。

次回

次回は、センサーデータを蓄積してグラフ表示してみたいと思います。
もちろん、IoT HubにBLOBやPowerBIなどを組み合わせて作っていってもいいのですが、そのあたりもサポートしているSaaS製品であるAzure IoT Centralを使って最小手順で構築してみたいと思います。
hatsune.hatenablog.jp