Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

Azure Functions で IoT Hub のデータを Cosmos DB に保存する

0
Posted at

はじめに

Azure Functions で IoT Hub のデータを Cosmos DB に保存する備忘録です。

改訂履歴

  • 2026/09/14 : 初版公開。

本文

1. 概要

Azure Functions は、サーバーレスでプログラムを実行するクラウドサービスです。普通の Web アプリケーションでは、サーバーやコンテナを常時動かしておく必要があります。一方 Azure Functions では、関数 (Function) 単位で処理を作り、HTTP リクエストやタイマー、ファイルのアップロードなどのトリガーをきっかけとして処理を実行できます。

料金については、以下を参照してください。

記事執筆時点では、以下の条件だと無料利用が可能です。

Azure Functions には無料枠がありますが、Azure Function が必要とする Storage Account は無料枠に含まれません。罠ですね。なるべく無料で頑張る場合 IoT Hub → Message Routing → Cosmos DB の構成になるのかなと思います。

2. 手順

2-1. Azure IoT Hub の作成

過去記事を参照してください。

組み込みのエンドポイントから、イベントハブ互換名とイベントハブ互換エンドポイントをコピーしておきます。

イベントハブ互換エンドポイントは接続文字列のため、取扱注意です。

2-2. Azure Functions の作成

Azure ポータルから関数アプリ (Function App) のページに移動し、作成します。

今回は無料試用版サブスクリプションのため、フレックス従量課金がサポートされていません。従量課金を選択します。

次の基本設定画面では、以下の内容を入力しました。

設定項目 設定内容
サブスクリプション Azure subscription 1
リソース グループ rg-azure-test
関数アプリ名 func-iot-test-20260914
ランタイムスタック .NET
バージョン 8 (LTS), isolated worker model
リージョン Japan West

このリージョンはおそらくリソースグループと同一のリージョンでないとダメなようです。別のリージョンを選択すると作成時にエラーが発生します。

基本設定の入力後、次へ進みます。

仮想ネットワーク統合は、今回は不要です。オンにすると追加のネットワーク設定が必要になります。

Application Insights も使用しません。自動監視は便利そうですが、ログやテレメトリーのデータ量に応じて料金が発生するためです。

Durable Functions は関数の実行状態や結果を自動的に管理し、一連のワークフローとして複数の Functions をオーケストレーションできる仕組みだそうです。今回は単純なイベント処理のため、不要です。

継続的デプロイはしないので、不要です。

リソース認証はデフォルトのままです。2 つのストレージが自動生成されています。ホストストレージは Azure Functions の実行に必要なストレージ、Azure Files はコードやデプロイ用のパッケージを一時的に保持するためのストレージだそうです。

タグは設定しませんでした。

最後に「作成」ボタンをクリックして関数アプリを作成します。

デプロイの完了まで待ちます。

無事に完了しました。

2-3. プログラムの作成

Visual Studio 2022 で Azure Functions プロジェクトを作成します。

プロジェクト名は FunctionExample にしました。

Function は Event Hub trigger、Connection string setting name には EventHubConnectionAppSetting、Event Hub name は Azure IoT Hub でコピーしたイベントハブ互換名 iothub-ehub-iot-hub-te-56673887-0f9514615c を設定します。

プロジェクトが生成されたら local.settings.json に赤枠の部分を追加します。値は Azure IoT Hub で確認したイベントハブ互換エンドポイントを設定します。

local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "EventHubConnectionAppSetting": "イベントハブ互換エンドポイント",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}

デバイスから Azure IoT Hub に送信している状態で、ビルドしてみます。今回は公式のラズパイシミュレーターを使用しています。System.ReadOnlyMemory<Byte>[113] で中身は分かりませんが、とりあえず正常に動作していそうです。

2-4. Azure Cosmos DB の作成

過去記事を参照してください。

設定のキーから、プライマリ接続文字列をコピーしておきます。

2-5. プログラムに DB 処理を追加する

local.settings.json に赤枠の部分を追加します。値は Azure Cosmos DB でコピーしたプライマリ接続文字列を設定します。

local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "CosmosDbConnectionString": "プライマリ接続文字列",
    "EventHubConnectionAppSetting": "イベントハブ互換エンドポイント",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}

NuGet パッケージとして Microsoft.Azure.Cosmos と Newtonsoft.Json を追加します。その後 Function1.cs に DB への保存処理を追加します。

Function1.cs
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace FunctionExample;
public class Function1
{
    private readonly ILogger<Function1> _logger;
+   private readonly Container _container;

    public Function1(ILogger<Function1> logger)
    {
        _logger = logger;

+       string connectionString = Environment.GetEnvironmentVariable("CosmosDbConnectionString") ?? throw new InvalidOperationException("CosmosDbConnectionString is not configured.");
+       var cosmosClient = new CosmosClient(connectionString);
+       _container = cosmosClient.GetContainer("test-database", "test-container");
    }

-   [Function(nameof(Function1))]
-   public void Run([EventHubTrigger("iothub-ehub-iot-hub-te-56673887-0f9514615c", Connection = "EventHubConnectionAppSetting")] EventData[] events)
-   {
-       foreach (EventData @event in events)
-       {
-           _logger.LogInformation("Event Body: {body}", @event.Body);
-           _logger.LogInformation("Event Content-Type: {contentType}", @event.ContentType);
-       }
-   }

+   [Function(nameof(Function1))]
+   public async Task Run([EventHubTrigger("iothub-ehub-iot-hub-te-56673887-0f9514615c", Connection = "EventHubConnectionAppSetting")] EventData[] events)
+   {
+       foreach (EventData @event in events)
+       {
+           string message = Encoding.UTF8.GetString(@event.EventBody.ToArray());
+
+           _logger.LogInformation("IoT message: {message}", message);
+
+           var document = new
+           {
+               id = Guid.NewGuid().ToString(),
+               deviceId = "iot-hub-device-test-20260911",
+               timestamp = DateTime.UtcNow,
+               message = message
+           };
+
+           await _container.CreateItemAsync(document, new PartitionKey(document.id));
+
+           _logger.LogInformation("Cosmos DB saved. id={id}", document.id);
+       }
+   }
}

改めて実行してみます。データの DB 登録が実行されていそうです。

Azure Cosmos DB を確認すると、無事に登録されていることが確認できます。

2-6. Azure Functions にデプロイする

ローカルでの動作確認ができたので、次は Azure Functions にデプロイします。プロジェクトの右クリックメニューから発行を選択します。

Azure を選択します。

Azure 関数アプリを選択します。

デプロイ先のリソースを選択します。Visual Studio から Microsoft アカウントへのログインが必要です。

発行を選択します。

実行プロファイルの作成が完了したら、閉じます。

右上の「発行」ボタンをクリックして、Azure Functions にデプロイします。

デプロイが完了しました。

最初に試した際は以下のエラーが表示され、デプロイに失敗しました。原因はおそらくソースの配置先を含めたパスが長すぎるためです。ソースを C ドライブ直下に移動したところ、再度デプロイを実行できました。

"C:\Users\<アカウント名>.nuget\packages\system.security.cryptography.protecteddata\4.5.0\runtimes\win\lib\netstandard2.0\System.Security.Cryptography.ProtectedData.dll" を "bin\Release\net8.0\runtimes\win\lib\netstandard2.0\System.Security.Cryptography.ProtectedData.dll" にコピーできませんでした。1000 ミリ秒以内に 1 回目の再試行を開始します。パス 'bin\Release\net8.0\runtimes\win\lib\netstandard2.0\System.Security.Cryptography.ProtectedData.dll' の一部が見つかりませんでした。

Azure ポータルから関数アプリ (Function App) のページを見ると、無事にデプロイされていることが確認できます。

2-7. ストレージを設定する

デプロイ後、以下のエラーが発生していました。

Microsoft.Azure.WebJobs.Extensions.EventHubs: Storage account connection string 'AzureWebJobsStorage' does not exist. Make sure that it is a defined App Setting.

通常、Azure Functions 用のストレージやその設定情報である AzureWebJobsStorage は自動生成されるらしいですが、今回は何故か作られなかったようです。仕方ないため、以前作成した storagetest20260905 を AzureWebJobsStorage に設定して先へ進めます。ストレージの作成方法は過去記事を参照してください。

ストレージのアクセスキーから、接続文字列をコピーしておきます。

Azure Functions の環境変数から AzureWebJobsStorage を追加します。値はストレージでコピーした接続文字列を設定します。

追加後、適用を押すと反映できます。

概要に戻って再起動すると、エラーが消えました。

2-8. Azure Functions の接続設定を行う

Azure Functions の環境変数に CosmosDbConnectionString と EventHubConnectionAppSetting に追加、適用します。値はローカルでの動作確認時に設定した local.settings.json と同じ内容です。

動作確認のため、デバイスから Azure IoT Hub に送信します。Azure Cosmos DB を確認すると、無事に登録されていることが確認できます。

3. 参考

おわりに

IoT のクラウド連携よりも、保存したデータの活用の方が難しいと思います。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?