PowerAppsからIoT Hub経由でIoTデバイスにメッセージを送信する

# 概要
- Azure IoT Hubを使ってIoTデバイスとクラウド間でのメッセージのやり取りに挑戦しています。

- 今回は、Power Appsから**カスタムコネクタ**を使ってIoT HubのAPIに接続し、IoTデバイス(M5Stack)側にメッセージを送信します。
- これができると、スマホから手軽にIoTデバイスに命令を送ってデバイスを操作したり、現在のセンサーデータを取得したりできるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/79046930-674c-4225-348a-68937ff2cb5d.png)

# Azureならコネクタは用意されていないの？
**Azure IoT Central**であれば標準で用意されています。
※IoT HubをバックエンドとしたSaaSで、標準で管理用GUIやテンプレート機能などが利用できるサービス。

本記事の**Azure IoT Hub**のコネクタは残念ながら標準では用意されていないようです。
ただし、いくつかの機能でREST APIが公開されていますので、カスタムコネクタを作成することで利用可能です。

# 事前知識
## Azure IoT Hubについて
名前の通り、IoT HubはIoTデバイスとクラウドサービス間のメッセージングハブとなるサービスです。  
ハブを経由して、デバイスからクラウドへのメッセージ(以下：D2C)を送ったり、クラウド(Power Appsなど)からデバイスへのメッセージ(以下：C2D)をリアルタイムに送ることができます。

Iot Hubの機能は、大きく以下の3つがあるようです。  
## ①メッセージのやり取り
→D2C、C2Dの双方向のメッセージ通信を行う。

## ②プロパティのやり取り(デバイスツイン)
→クラウド側、デバイス側でプロパティを操作し、相手側で参照したり、変更通知を受け取ったりする。
→バッテリー残量、設置場所などの任意のプロパティ。

## ③メソッドの実行(ダイレクトメソッド)
→クラウド側からメソッド(任意な識別子)を実行し、デバイス側で受信し、登録された処理を行って応答する。
→Rebootなどの命令を想定しているが、プログラミング次第でなんでもできる。



大規模にやるならAzure IoT Centralがよさそうですが、
IoTの仕組みを理解するためにも今回はIoT Hubを選択しました。
IoT HubはStandard Freeプランを使用します。


# IoT HubのREST APIについて
Power AppsからIoTデバイスへのメッセージ送信には、IoT HubのAPIを使用します。
APIがあればカスタムコネクタから呼び出せますね。


Azure IoT HubのAPIのいくつかは、HTTPSでも利用することが可能です。
今回は、C2D(クラウドからデバイス)メッセージの送信と、デバイスの一覧取得の機能を使います。
※デバイスの温度などをリアルタイムタイムに読み取る用途で使用するD2Cメッセージは後述の理由で使えません。

## ベースUri
IoT Hubのリソース名がホストの一部になります。
```
https://your-resource-name.azure-devices.net/
```
<br>

## C2Dメッセージの送信
以下のエンドポイントにPOSTすると、デバイスに対して任意のメッセージを送信できます。
BODYの形式は自由ですがJSON等で設定し、デバイス側のプログラムで解釈します。
?api-versionはつけた方が良いみたいです。

```
POST /devices/{DeviceId}/messages/devicebound?api-version=2021-04-12
```
 こちらはドキュメントが少なく方法を見つけるのに苦労しました
<br>

## デバイスの一覧取得
{DeviceId}は以下のエンドポイントにGETすると取得できます。
IoT Hubに登録されているデバイスを一覧化します。
```
GET /devices?api-version=2021-04-12
```
<br>

## ダイレクトメソッド実行
デバイスに対して任意のメソッド名でリクエストします。
デバイス側での応答メッセージはそのままAPIのレスポンスになります。

デバイスへのプログラミング次第でLチカなど色々できます。

```
POST /devices?api-version=2021-04-12
{
  "connectTimeoutInSeconds": 2,
  "methodName": "Reboot",
  "payload": {
    "Message": "Default"
  },
  "responseTimeoutInSeconds": 5
}
```
<br>

## 認証
Authorizationヘッダに後述のSASトークンを設定することで認証可能になります。
カスタムコネクタではAPI Keyで認証できます。
Keyは後述のVSCode拡張機能から取得するのが簡単です。

<br>

## その他のAPIのドキュメントはこちらに記載されています。

https://learn.microsoft.com/ja-jp/rest/api/iothub/device/send-device-event?view=rest-iothub-2020-03-13

## 残念なところ
IoTの主目的であろう、現在の温度などのセンサーデータをリアルタイムに取得するための
D2Cメッセージの読みとりについては、REST APIがありません。
Web SokcetやAMQPといった一部のプロトコルでしかサポートされていないようです。

Power Appsから呼び出した時点のセンサーデータを取得するだけであれば、ダイレクトメソッドメッセージで代用可能です。

どうしてもセンサーデータなどを読み取りたい場合は、メッセージルーティングで別のサービスに保管させて読み取る必要がありそうです。
https://learn.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-messages-read-builtin#read-from-the-built-in-endpoint

## IoTデバイスは何を使ったか
今回はIoTデバイスとしてM5Stackを使用しています。
IoT HubにMQTT接続することにより、IoT Hubにメッセージを送信したり、リアルタイムにメッセージを送受信できるようになります。
Arduinoのコードは別記事で掲載します。
https://qiita.com/Rambosan/items/87b529082a52398b67c8

また、検証レベルであればデバイスが無くてもVSCodeの拡張機能からメッセージの送受信が可能です。


# Power Appsからメッセージを送信する方法

## 必要なもの
- Azure IoT Hub(Standard Free)
- VSCodeとAzure IoT Hub拡張機能
- Power Apps(開発者環境又はプレミアム)
- カスタムコネクタ(PowerApps)
- IoTデバイス(検証なら無くてもOK)

## Azure IoT Hubとデバイスの作成
まずはAzure側でリソースとデバイスを作成しておきます。
このあたりを参考にします。

https://learn.microsoft.com/ja-jp/azure/iot-hub/iot-hub-create-through-portal

https://cptechweb.teldevice.co.jp/hc/ja/articles/900007073623--%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91-Azure-IoT-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E6%A7%8B%E7%AF%89-2-Azure-IoT-Hub%E3%81%AE%E4%BD%9C%E6%88%90

## VS Code拡張で接続情報の取得

カスタムコネクタの作成にあたり、以下の3つの情報が必要になります。
特にSASTokenの生成にひと手間かかるのですが、拡張機能を使うと右クリックで作成可能です。

- HostName
- DeviceId
- SAS Token

### 拡張機能の入手
以下のVSCode拡張機能を取得します。
これ一つでデバイスの作成、メッセージの確認、トークンの作成など基本的な操作ができます。
使い方はインストール後に作成される画面の「…」にあるShow Welcome Pageが分かりやすいです。
https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-toolkit


### ホスト名とデバイスIDの取得
IoT Hubの拡張機能から、デバイスを右クリックして取得できる文字列から取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/afcf052b-ee42-b03d-0930-c5967b985190.png)
<br>
### SAS Tokenの生成
こちらは拡張機能のリソースの…から「Generate SAS Token for IoT Hub」で生成します。
デバイスの方から生成したトークンでは権限不足となるので注意です。
有効期限を時間単位で設定する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/91400a05-511d-4908-e9b7-be1dd39b8828.png)


## カスタムコネクタの作成
PowerApps/Automateには、IoT Hub用コネクタが用意されていないため、
自分でカスタムコネクタを用意します。

以下にカスタムコネクタ作成用のファイルをアップしました。

https://github.com/Rambosan/M5IoTClient_withAzIoTHub/blob/main/CustomConnector_for_PowerApps/Azure-IoT-Hub-Connector.swagger.json

jsonファイルからカスタムコネクタを作成して編集します。
ホストは上記で取得したものを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/de34e2ae-0a2a-da9f-e298-79852efa713d.png)


## APIキーの登録
テスト画面の接続の作成で、VSCodeからコピーしたSAS Tokenを貼り付け、接続を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/18246f94-a378-9dcf-6f81-ca101def8bfc.png)

念のためテストが成功することを確かめておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/4ceaa8e3-0b26-0f5b-6112-5244d35b96c0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/a379bd91-c474-2795-f0c3-52432d0738ad.png)

# Power Appsの作成

こんな感じのキャンバスアプリを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9cc171a9-7740-0369-680a-18375b128450.png)

データの追加でコネクタを追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/0cbe54f8-a0b8-f680-0e06-eb56ebc39e52.png)

送信ボタンのOnSelectにdeviceboundを呼び出す関数を記述。
第一引数はデバイスIdです。
事前にデバイスの一覧をギャラリーコントロールに取得しているので、選択された行のデバイスIdがはいります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9f6cfbc8-c71e-190c-a62f-3ca91caa9202.png)

再生を押して送信してみましょう。

# C2Dメッセージの確認

## VSCode拡張で確認
拡張機能のデバイスを右クリックし、Start Recieving C2D Messageを実行。
すると、OUTPUTウィンドウに以下のようにメッセージが送信されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/dafdef65-3a58-58b3-268b-25ad2aaf57b8.png)

## IoTデバイスで確認
実装の詳細については別記事に掲載しますが、以下のような感じで取得できました。
ArduinoのコードでIoT HubにMQTT接続を行い、デバイスへのメッセージをサブスクライブしています。
httpsのポーリングとは異なり、ほぼ遅延なくメッセージを受信できますね。

※VSCodeから接続したままだと接続が切れるので、VSCodeからのモニタリングはStopしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/b82283ff-887f-3013-bf6a-4baa9302d234.png)


# 終わりに
今回はIoT Hubの機能のメッセージ通信を使ってみました。
デバイスツインやダイレクトメソッドの機能についても試してみたいと思います。

Azure IoT Hubでは、デバイスから受信したセンサーデータを設定により他サービスに格納することは一般的ですが、クラウドからデバイスへのメッセージは、APIを使って自分で実装する必要があります。
デバイス側の処理はMQTTClientやSDKで実装するとして、
クラウド側の処理をローコードで実装できると楽ですね。