[Azure x IoT] Azure IoTHubで受け取ったメッセージをDBに保存しよう


本記事のゴール

本記事ではIoTHubで受信したメッセージをRDBに保存できるようにします.

AzureFunctionからAzureDatabaseへのアクセスについてはVnet統合という機能を使います。

本記事の内容は筆者の次の3つの記事を組み合わせた内容になります。
IotHubは使わないけど、部分的に参考にしたいという方は以下を参考にしてください。

準備するもの

  • AzureIoTHub
  • Azure Functions(Function PremiumかApp Service のStandardプラン以上)
  • Azure Database For MySQL
  • 踏み台仮想マシン
  • vnet
  • Vnet統合に使うFunction用のsubnet

1. Azure IoTHubを作成する

AzurePortalでAzure IoTHubサービスを作成します。

プランはF1(無料)で大丈夫です。

2. Azure Database For MySQLと踏み台サーバーを用意する

  1. 以下のチュートリアルを参考にDBと踏み台サーバーの作成を行う

    Azure portal でプライベート アクセスを使用して Azure Database for MySQL フレキシブル サーバーに接続する

  2. テスト用のデータベース、テーブルを作成

    CREATE DATABASE test_database;
    
    CREATE TABLE
        test_table (
            id INTEGER AUTO_INCREMENT PRIMARY KEY,
            message VARCHAR(255),
            created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        );
    

ざっくりとした解説にとどめましたが、筆者の以下記事にもう少しだけ詳しく書いてあるのでよかったら参考にしてください

[Azure] Azure FunctionsからVnet内のRDBを操作する - Qiita

3. Function用のSunetを用意する

vnetはDB作成時に既に作成されているはずなので、そこにFunction用のsubnetを作成します。
先程DBに紐付けたvnetのページにいき、サイドメニューの”サブネット”を選択し、サブネットの追加を行います。名前は適当なもので構いません。サブネットアドレス範囲は自動で入力されるので名前さえ入力できればあとは保存して終了です!

4. FunctionAppを作成する

  1. AzurePortal上でFunctionAppを作成する
    Vnet統合が使えるのはAppServiceプランのStandard以上だけなのでそこだけ注意してください。
    参考:https://docs.microsoft.com/ja-jp/azure/app-service/overview-vnet-integration

  2. Azure Functions Core Toolsのfuncコマンドで関数を作成.

    func new --name IoTHubTriggeredFunction --template "IoT Hub (Event Hub)"
    
  3. functions.jsonを編集

    {
          "type": "eventHubTrigger",
          "name": "IoTHubMessages",
          "direction": "in",
          "eventHubName": "MyEventHub",  ←テンプレートから変更
          "connection": "myEventHubReadConnectionAppSetting",  ←テンプレートから変更
          "cardinality": "one", ←テンプレートから変更
          "consumerGroup": "$Default"
    }
    
  4. index.tsを編集

    import { AzureFunction, Context } from "@azure/functions"
    import {createConnection} from 'mysql2/promise'
    
    const IoTHubTrigger: AzureFunction = async function (context: Context, IoTHubMessage: any): Promise<void> {
    // ①接続情報オブジェクトを作成し、コネクションを確立する
        const config =
            {
                host: process.env['DB_HOST'],
                user: process.env['DB_USER_NAME'],
                password: process.env['DB_PASSWORD'],
                database: process.env['DB_DATABASE_NAME'],
                port: 3306,
                ssl : {
                    rejectUnauthorized: false
                 }
            };
    
        const conn = await createConnection(config);
    
    //②DBへinsert
        try {
            const [rows,fields] =
              await conn.query(`insert into test_table (message) values ('${IoTHubMessage.value}')`)
                .catch(e=>{throw Error(e)});
            context.log(fields)
          } catch(e) {
            context.log(e)
          } finally {
            conn.end();//接続を切る
          }
    };
    
    export default IoTHubTrigger;
    
  5. デプロイ

    ここまででコードは完成したのでデプロイします。デプロイ前にビルドするのを忘れずに

    npm run build
    func azure functionapp publish ${FunctionAppの名前}
    
  6. AzurePortalで環境変数を設定する

    作成した関数アプリのサイドメニューから「構成」を選びます。

    そこで”新しいアプリケーション設定”をクリックして以下を作成します。

    • DB_HOST
    • DB_USER_NAME
    • DB_PASSWORD
    • MyEventHub
    • myEventHubReadConnectionAppSetting

    MyEventHubmyEventHubReadConnectionAppSetting
    に設定するIoTHubの名前とEvent Hub-compatible endpointはそれぞれIoTHubから確認できます

    • IoTHubの名前

    • Event Hub-compatible endpoint

5. 動作確認

  1. IotHubに対してメッセージを送信します

    必要な環境変数を設定して以下を実行します。

    curl -i -X POST \
    -H "Content-Type:application/json" \
    -H "Authorization:$SAS" \
    -d '{"value":"hello,world via iothub"}' \
    "https://$IOTHUB_NAME.azure-devices.net/devices/$DEVICE_NAME/messages/events?api-version=2018-06-30"
    

    SASは次のコマンドで取得できます

    az iot hub generate-sas-token -n $IOTHUB_NAME --du $EXPIRATION_SECONDS
    

    詳しくは筆者のこちらの投稿をご覧ください

  2. VMからDBにログインしてレコードが挿入されているか確認する
    以下のようにIoTHubに送ったメッセージの内容がinsertされていれば成功です!

おわりに

いかがだったでしょうか。これでIoTデバイスから得られたセンシングデータをDBに格納することができるようになりました。あとはこのデータをアプリケーションに合わせて加工して、必要ならフロントエンドも足して、簡単なIoTシステムの完成です!