環境センサーを使ってAzure IoT Hub Device Provisioning Serviceを試してみる

# はじめに

IoT Hub Device Provisioning Service（以下DPS）というのがありまして、IoTHubへの接続情報をデバイス側にハードコードしないで済みそうなサービスがあったので試してみました。

以下のような構成ではIoTHubのEndpointがデバイス側にべた書きになるので、IoTHubのEndpointを変更する場合はデバイス側にも手を入れなければならなかったり、動的にEndpointを取得する仕組みが必要でした。

![IoTHub.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/fdeb0977-043d-3c6c-1bf0-be80377a4ea4.png)

DPSはデバイスの検証・IoTHubへのデバイスの登録など一連のプロセスを行ってくれるので、デバイス側はDPSのEndpointや認証情報だけ知っておけばよいことになります。DPSのエンドポイントは全世界共通というのがポイントなわけです。
このエンドポイントをグローバル デバイス エンドポイントと呼び、global.azure-devices-provisioning.netになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/5e8096e6-215e-73d8-bb15-f09025e7bc5d.png)

大量のデバイスを扱う場合はもちろん便利ですが、少ないデバイスでも接続先のIoTHubを簡単に切り替えられる状況は色々と考えられるので利用しない手はなさそうです。


# 前準備

## デバイスの準備

M5StickCPlusと気温、湿度、気圧が取れるHATを使いました。5000円くらいかかりました。

https://www.switch-science.com/catalog/6470/

https://www.switch-science.com/catalog/7367/

## デバイス側のコーディング

- [UIFlow](https://flow.m5stack.com/)を使いました。
- ビジュアルプログラミング言語Blocklyというのを使って、簡単にデバイス側のプログラミングができます。子供と一緒にscratchをやったことがあったので特にハードルはなくすんなりとは入れました。
- こいつがすごいのはAWSやAzureに接続するブロックがあらかじめ用意されていることです。DPSに接続するにはAzure IoTHub SDKを使うわけですがもちろん組み込み済です。ありがたい・・・・。


## IoTHubとDPSを用意しておく

IoTHubとDPSを作ります。名前以外は迷う部分がないので省略。

## IoT Explorerのインストール・設定

IoT ExplorerでTelemetryを確認したいので、インストールしておきます。私はChocolateyでインストールしました。

https://docs.microsoft.com/ja-jp/azure/iot-fundamentals/howto-use-iot-explorer

IoT Explorerに設定する接続文字列は共有アクセスポリシーからiothubownerとか選択すれば接続文字列が拾えますので設定しておきましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/bf55b92e-4512-b35e-29ca-7d3eb3b5c91d.png)


# DPS経由でデバイスを接続してIoTHubにTelemetryを流す

## DPSの設定（IoTHub & デバイス)

DPSにIoTHubを紐づけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/9c1ba1d4-c460-e2d5-5431-824a496cb5f4.png)

DSP経由でデバイスを登録します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/a25c3ebe-09c3-7e1a-e385-5ca148b46ed0.png)

## デバイス側の設定

DPS接続に必要なIDスコープ, デバイスID, 主キーを取得します。

IDスコープをコピー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/9a793f80-1268-1e0c-0a15-91312a8f9b09.png)

デバイスIDと主キーをコピーする
先ほどデバイスIDは明示しませんでしたので、m5stickcplus-uzresk-001が使われます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/7a37dc3d-8b72-1102-b760-4b14572f5bad.png)

UIFlowに設定していきます。IoTCentralはDPS接続なのでIoTCentralの部品をそのまま使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/b48a7fbf-be2b-eccb-830b-2d809c080660.png)

10秒間隔で室温、湿度、気圧をmapにしてjsonに変換してIoTHubに送ります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/807d36da-c0ad-8301-aafe-d93cd4e17360.png)

これをjsonにするとこんな感じ

```
{
    "humidity": 36.43397,
    "pressure": 100459.4,
    "temperature": 35.63592
}
```

## IotHub Explorerで覗いてみる

RefreshするとIoTHubExplorerでデバイスが出てきた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/84e26bd0-1d47-37cb-7947-c71c41a6cdf0.png)

左メニューから「Telemetry」を選択してイベントを拾ってみます。ちゃんと送信されてきてますね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/4c208ca3-8419-eb35-a079-fede3aa3e848.png)

# DPSに複数のIoTHubを紐づけてみる

2つ目のIoTHubを作ります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/e42f2769-ef5b-abee-8cbb-28e2b2b8ef2c.png)

DPSに先ほど作ったIoTHubを紐づけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/45e24df8-136c-60af-9082-a29d002764ac.png)

デバイスにIoTHubを紐づけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/39d0e7d1-5a1f-3ac2-e3b4-7381d1320e88.png)

デバイスをIoTHubに割り当てる方法は色々あります

- 「加重が均等に分布」とうのはデバイスとIoTHubの分布が均等という意味です。はじめ通常のHTTPロードバランサと同じで、デバイスから送られてくるリクエストごとに接続先のIoTHubが変わるのかと勘違いしてました・・・。
- 「静的な構成」というのは接続先のIoTHubを固定化するという意味です。
- 「最短待機時間」というのは近いIoTHubに繋ぐ。という意味になるのでリージョンごとにIoTHubをデプロイしておいた場合、距離の近いほうに優先して接続する方法です

このほかFunctionに振り分けをお願いする方法もあるようです。ここは色々と妄想が膨らみそうですね



## フェイルオーバー？

IoTHub Aがなんらかの理由で利用できなくなり、「静的な構成」でIoTHub Bに設定しなおしたら自動的にそちらにテレメトリが送信されるのかな？と気になって試してみました。

- 結果、IoTHubBに自動でテレメトリが送信されるということはありませんでした（そりゃそうだ）。デバイスとDPSの検証時にどのIoTHubに接続されるかが決められるので、デバイスを再起動（IoTHubSDKで初回接続したとき）しないと接続先は変わりませんでした。

# おわりに

- デバイス側でSDKが使えることっていうのが前提としてありますが、デバイスの管理・接続先の管理をDPSにお任せできるのはすごく魅力的ですね。

# 参考

https://docs.microsoft.com/ja-jp/azure/iot-dps/about-iot-dps