Azure IoT Hubを久しぶりに触ってみたので個人的な備忘録（メッセージングとデバイスツイン）

# はじめに
これは、最近AzureのIoT Hubを触ってなかったので、触ってみる個人的な備忘録です。
何回かに分けてツラツラ触ってみたいと思います。
忙しくなったら途中で終わるかもです。

今回はデバイス側をメインにやってます。

# DocsのクイックスタートでIoT Hubを作成
[クイック スタート:デバイスから IoT ハブに利用統計情報を送信して Azure CLI で監視する](https://docs.microsoft.com/ja-jp/azure/iot-hub/quickstart-send-telemetry-cli)
まずはこれをこのまま実施しました。（リソースのクリーンアップを除く）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/98422163-1df2-398a-0ad3-4a90cef95412.png)


とりあえず、2つのCLIセッションを利用して
- IoT Hub(matakahaiothubjapaneast1)を作成
- IoT Hub内にデバイスID(simDevice)
- 作成したデバイスIDを使いシミュレーションデバイスを起動

ができました。
ポータルにも、こんな感じで出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/466974a0-44b7-65f2-47f9-e78717e0f600.png)

# デバイスアプリをゼロベースから作成
さきほどはシミュレーションデバイスを使いました。
今度はC#で作ってみます。
.NETは6.0.202が入った環境です。VSCodeで作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/dccc7ec0-0758-c913-7f32-c86cdf223500.png)

## Hello World!
とりあえずこちらに沿ってハローワールドだけやってみます。
[チュートリアル: Visual Studio Code を使用して .NET コンソール アプリケーションを作成する](https://docs.microsoft.com/ja-jp/dotnet/core/tutorials/with-visual-studio-code?pivots=dotnet-6-0)
フォルダ名は "device1" としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/72a9c8c2-2ed0-7eee-042d-36b3af26c517.png)
ネームスペースも "device1" です。

## パッケージインストール
NugetでIoT Hubのデバイスクライアント構築に必要なパッケージを拾います。
まずはProgram.csの1行目、namespaceの上に
> using Microsoft.Azure.Devices.Client;

を書いてエラー状態にしました。
続いてターミナル("表示"→"ターミナル", もしくは"Ctrl＋＠")を開いて
> dotnet add package Microsoft.Azure.Devices.Client

を実施しパッケージを拾います。

## サンプルを見ながら必要最低限のコードを移植
もともとのクイックスタートで実施していたのは
- d2c(デバイスからクラウド)のメッセージ送信
- c2d(クラウドからデバイス)のメッセージ送信

の２点です。
この２つだけを実装します。
必要最小限にしますので、全てセンスの欠片も無いベタ書きします。エラー対応もしませんし、送信するメッセージもカウントするだけのものにします。
まずはこちらを参考にd2cのメッセージ送信を実装します。
https://github.com/Azure-Samples/azure-iot-samples-csharp/blob/main/iot-hub/Quickstarts/SimulatedDevice/Program.cs
接続文字列はポータルから取得し、こちらもベタ書きしました。
さきほどポータル上、"デバイス"で"simDevice"の存在を確認しましたが、その"simDevice"をクリックしてデバイス情報を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/d9be67a8-f501-02c5-3b0a-be1fd3842bc1.png)
この中の"プライマリ接続文字列"の値をコピペしました。

次にc2dのメッセージ送信を実装します。こちらを基本的にはコピペしました。
[デバイスに IoT Hub でクラウドからメッセージを送信する (.NET)](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-csharp-csharp-c2d)
実行結果はこんな感じになりましたので、とりあえずシミュレーションデバイスの代わりはゼロベースから作成できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/edcac5a2-d709-5385-44bd-a778d1640064.png)
完成したコードはこちらを参照ください。
このままでは使い物にはなりませんが、理解するに必要最小限にはなっているかと思います。
https://github.com/matakaha/iotsample2022/blob/main/device1/Program.cs

{Your device connection string here}と記載のあるところにデバイスの接続文字列を入れれば動作します。
作っておいてなんですが、c2dメッセージはあまり使いどころが無いかもしれません。（たぶんこの先で触れることは無い気がする）

# デバイスツインを使ってみる
詳細な説明は本家のドキュメントにお願いするとして、軽く概要だけ記載します。
本家：[IoT Hub のデバイス ツインの理解と使用](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-device-twins)
デバイスとIoT Hubの情報連携方法はメインどころが３つあります。
- メッセージのやりとり
- プロパティのやりとり
- ダイレクトメソッド

最初に作成したのはメッセージのやりとりです。今回のデバイスツインはプロパティのやりとりです。
"IoT Hub→デバイス"の情報として、たとえばメッセージの送信頻度の設定や収集してほしいログレベルの設定などを送り、デバイスに希望する状態を通知します。
"デバイス→IoT Hub"の情報として、たとえばアプリのバージョンやバッテリー残量などを送り、デバイスの状態を通知します。
前者をDesired Properties、後者をReported Propertiesと呼びます。デバイスツインではもう１つ、IoT Hub側だけで使うTagsというものが存在します。（が、とりあえず忘れる。）
用途から類推できますが、IoT HubはDesired、デバイスはReportedだけを更新できます。
プロパティを削除したいときはNullを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/0c1c74e2-aeff-2fb1-126f-2a9da4411a96.png)

## ゼロベースから作成
もう１度ゼロベースから作成します。
とはいえ、せっかくなので、さきほどのdevice1をコピペしてdevice2として作成していきます。
先ほど同様にdevice2フォルダを作成して
> dotnet new console --framework net6.0

して、中にdevice1で作成したコードをコピペしました。
> dotnet add package Microsoft.Azure.Devices.Client

もお忘れなく。
[デバイス ツインの使用 (.NET)](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-csharp-csharp-twin-getstarted#create-the-service-app)
こちらを参考に組みこんでいきます。
ドキュメントは、
- IoT Hub作成
- IoT Hubの裏側にかまえるアプリ作成
- デバイスアプリ作成

の順に記載されていますので、最後の[デバイス アプリを作成する](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-csharp-csharp-twin-getstarted#create-the-device-app)だけを参考にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/850313b3-dd8f-e2e4-8331-8edf32acf341.png)
実行すると、プロパティが変化することが確認できました。
デバイスツインの状況をポータル側でも確認します。
先ほど接続文字列を取得したポータル画面で、"デバイスツイン"というボタンを探しクリックすると、以下のような画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/b596a7c8-882c-1feb-e88e-e9527b21528c.png)
この画面、desiredの部分は手書きで更新できます。書くとデバイス側でも反応します。Key(上図だと"sample")を削除したい場合は、ValueをNullとしてください。Keyごと削除されます。

完成したコードはこちらを参照ください。
このままでは使い物にはなりませんが、理解するに必要最小限にはなっているかと思います。
https://github.com/matakaha/iotsample2022/blob/main/device2/Program.cs

device1からの変化点としては、
- usingを１つ追加しました
- 42行目くらいでIoT Hubからプロパティを受け取っています
- 71行目以降はサンプルの完コピでIoT HubにReportedしています(通常、こんな毎秒報告したら怒られます)

# 以上
今回は、チュートリアルを見ながらデバイスを作成してみました。
基本的な情報のやりとりはこれでできています。
次回は、メッセージにプロパティを付与して、メッセージルーティングとかをやってみようかと思います。