はじめに
こちらの記事でデバイスからAzure IoTHubへデータを送信する方法は紹介しました。
今回は、Azure IoTHubで受け取ったデータをAzure Functionsに連携する方法を紹介します.
準備
以下の準備はAzurePortalから関数を作成する場合は不要です。
ローカル環境でAzure Functionsの雛形作成、デプロイのためにはAzure Functions Core Tools
と呼ばれるCLIツールがAzure CLI
とは別に必要です。
以下を参考にインストールしてください。
Work with Azure Functions Core Tools
Macの場合は以下です
brew tap azure/functions
brew install azure-functions-core-tools@4
Azure Functionsを作成する
ポータルから作成する(今回は割愛)
本記事では、コマンドを使って作成する方法をメインで書くのでこちらは割愛させていただきます。
以下の記事がとても丁寧でわかりやすいです
Azure IoT Hubで受け取ったデータを利用する方法(Azure function) - Qiita
コマンドで作成する
実は、複雑なことはしなくてもAzure側でIoTHub連携用のテンプレートが用意されおり、以下のコマンド1発で連携に必要なFunctionの雛形を作成できます
func new --name IoTHubTriggeredFunc --template "IoT Hub (Event Hub)"
コマンドを実行するとプロンプトが立ち上がり、runtime,languageを聞かれます。
今回はそれぞれ 3. node 2.typescriptを選択しました
成功すると以下のようなディレクトリ構成で雛形が作成されます
.
├── IoTHubTriggeredFunc
│ ├── function.json
│ └── index.ts
├── host.json
├── local.settings.json
├── package.json
└── tsconfig.json
index.tsの中身
import { AzureFunction, Context } from "@azure/functions"
const IoTHubTrigger: AzureFunction = async function (context: Context, IoTHubMessages: any[]): Promise<void> {
context.log(`Eventhub trigger function called for message array: ${IoTHubMessages}`);
IoTHubMessages.forEach(message => {
context.log(`Processed message: ${message}`);
});
};
export default IoTHubTrigger;
余談ですが、他にも様々なテンプレートがあり以下のコマンドで確認できます
func templates list
TypeScriptの部分だけ一部抜粋するとこんな感じです
TypeScript Templates:
Azure Blob Storage trigger
Azure Cosmos DB trigger
Durable Functions activity
Durable Functions entity
Durable Functions Entity HTTP starter
Durable Functions HTTP starter
Durable Functions orchestrator
Azure Event Grid trigger
Azure Event Hub trigger
HTTP trigger
IoT Hub (Event Hub)←今回使うのはこれ
関数をデプロイする
- デプロイ対象になる関数アプリをAzurePortal上で作成する
- function.jsonを修正
ここにIoTHubとの連携に関わる情報を設定します。
まず今回はバッチではなく、1メッセージずつ受信するためにcardinality
をoneにします。(参考)
ここをmanyにしておくとメッセージをバッチで受け取れるので、例えばDBに直接データを入れたい場合にバルクインサートができたり、パフォーマンス改善につながります。
次にeventHubName
の部分にMyEventHub
を設定し、connection
部分にmyEventHubReadConnectionAppSetting
を入力します。
これらは実は任意の文字列でよく、後ほどAzurePortalから環境変数として値を設定します。
修正前
```json
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "IoTHubMessages",
"direction": "in",
"eventHubName": "samples-workitems",
"connection": "",
"cardinality": "many",
"consumerGroup": "$Default"
}
],
"scriptFile": "../dist/IoTHubTriggeredFunc/index.js"
}
```
修正後
```json
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "IoTHubMessages",
"direction": "in",
"eventHubName": "MyEventHub", ←変更
"connection": "myEventHubReadConnectionAppSetting", ←変更
"cardinality": "one", ←変更
"consumerGroup": "$Default"
}
],
"scriptFile": "../dist/IoTHubTriggeredFunc/index.js"
}
```
-
index.tsを修正
修正前はFunctionの引数がIoTHubMessages: any[]
となっていますが、今回はステップ2で1メッセージずつ受信するようにしたので以下のように引数の型を修正します。もちろん、送られてくるデータの型がわかっていればanyではなくきちんと定義するのが望ましいです。import { AzureFunction, Context } from "@azure/functions" const IoTHubTrigger: AzureFunction = async function (context: Context, IoTHubMessage: any): Promise<void> { context.log(`Eventhub trigger function called for message array: ${IoTHubMessage}`); }; export default IoTHubTrigger;
-
以下のコマンドでデプロイ
# まずアプリケーションをビルドする npm run build # 指定した関数アプリにデプロイする func azure functionapp publish $FUNCTION_APP_NAME
以下のような表示がされれば成功です。
IoTHubとFunctionの連携設定をする
仕上げに先程functions.jsonに設定したMyEventHub
とmyEventHubReadConnectionAppSetting
をAzurePortal上で環境変数として設定します。
-
AzurePortalでデプロイした関数アプリのページに行き,Configuration(構成)を開きます
-
New application settingを選択し、環境変数を設定していきます
MyEventHub
とmyEventHubReadConnectionAppSetting
に設定するIoTHubの名前とEvent Hub-compatible endpointはそれぞれIoTHubから確認できます
もしAzurePortal上で警告が出た時
-
警告全文
Microsoft.Azure.WebJobs.Script: One or more loaded extensions do not meet the minimum requirements. For more information see https://aka.ms/func-min-extension-versions. ExtensionStartupType EventHubsWebJobsStartup from assembly 'Microsoft.Azure.WebJobs.EventHubs, Version=4.1.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not meet the required minimum version of 4.3.0.0. Update your NuGet package reference for Microsoft.Azure.WebJobs.Extensions.EventHubs to 4.3.0 or later.
次のコマンドでバージョンアップしてください
func extensions install --package Microsoft.Azure.WebJobs.Extensions.EventHubs --version 5.0.0
-
Event Hub-compatible endpoint
にeventHubName
が載っているのに二重で指定してくるな!と怒ってきたとき
eventHubName
を空文字にしてデプロイし直してください。
メッセージを送ってみる
この記事に従って以下のスクリプトでメッセージを送ってみます
IOTHUB_NAME=xxxx
DEVICE_NAME=xxxx
SAS=xxxx
mosquitto_pub -d -q 1 \
-V mqttv311 \
-p 8883 \
-h "$IOTHUB_NAME.azure-devices.net" \
-i $DEVICE_NAME \
-u "$IOTHUB_NAME.azure-devices.net/$DEVICE_NAME/api-version=2016-11-14" \
-P $SAS \
-t "devices/$DEVICE_NAME/messages/events/$.ct=application%2Fjson&$.ce=utf-8" \
-m '{"value":"Hello,world with MQTT"}'
関数アプリのApp Insightsログでメッセージが確認できたら成功です!
終わりに
これでデバイス→IoTHub→Azure Functionsまでを繋ぐことが出来ました!
次はAzureFunctionsとその他のAzureリソースを連携する方法を紹介する記事も執筆予定です、お楽しみに!