Azure IoT Hub を使用してデバイスからクラウドにファイルをアップロードする (Node.js)

この記事では、Node.js を使って、IoT Hub のファイル アップロード機能でファイルを Azure BLOB ストレージにアップロードする方法を説明します。

デバイスから IoT ハブへのテレメトリの送信のクイックスタートと IoT Hub を使用したクラウドからデバイスへのメッセージの送信に関するアーティクルには、IoT Hub のデバイスからクラウドへのメッセージングとクラウドからデバイスへのメッセージングの基本的な機能が示されています。 「IoT Hub を使用してメッセージ ルーティングを構成する」チュートリアルでは、device-to-cloud メッセージを Microsoft Azure BLOB ストレージに確実に格納する方法を示します。 ただし、一部のシナリオでは、デバイスが送信するデータを、IoT Hub が受け入れる比較的小さな device-to-cloud メッセージに簡単にはマップできません。 次に例を示します。

  • ビデオ
  • イメージを含む大きなファイル
  • 高頻度でサンプリングされる振動データ
  • 何らかの形式の前処理済みデータ。

これらのファイルは通常、Azure Data FactoryHadoop スタックなどのツールを使ってクラウドでバッチ処理されます。 デバイスからファイルをアップロードする必要がある場合も、IoT Hub のセキュリティを信頼性を使用できます。 この記事では、その方法について説明します。

この記事の最後に、次の 2 つの Node.js コンソール アプリを実行します。

  • FileUpload.js: IoT ハブによって提供された SAS URI を使用して、ストレージにファイルをアップロードします。

  • ReadFileUploadNotification.js: IoT ハブからファイル アップロード通知を受信します。

注意

IoT Hub は、Azure IoT device SDK を介して、多数のデバイス プラットフォームと言語 (C、Java、Python、JavaScript を含む) をサポートしています。 デバイスを Azure IoT Hub に接続する方法については、Azure IoT デベロッパー センターを参照してください。

重要

X.509 証明機関 (CA) 認証を使用するデバイスのファイル アップロード機能はパブリック プレビュー段階であり、プレビュー モードを有効にする必要があります。 これは、Azure デバイス プロビジョニング サービスで x.509 拇印認証または x.509 証明書の構成証明を使用するデバイスで一般提供されています。 IoT Hub での X.509 認証の詳細については、「サポートされている X.509 証明書」を参照してください。

前提条件

  • IoT Hub。 CLI または Azure portal を使って作成します。

  • 登録済みのデバイス。 Azure portal に登録してください。

  • Node.js バージョン 10.0.x 以降。 LTS バージョンが推奨されます。 Node.js は nodejs.org からダウンロードできます。

  • ポート 8883 は、ファイアウォールで開放されている必要があります。 この記事のデバイス サンプルでは、ポート 8883 を介して通信する MQTT プロトコルを使用しています。 このポートは、企業や教育用のネットワーク環境によってはブロックされている場合があります。 この問題の詳細と対処方法については、「IoT Hub への接続 (MQTT)」を参照してください。

IoT Hub への Azure Storage アカウントの関連付け

デバイスからファイルをアップロードするには、IoT ハブに関連付けられている Azure Storage アカウントと Azure Blob Storage コンテナーが必要です。 ストレージ アカウントとコンテナーを IoT ハブに関連付けると、デバイスから要求されたときに、その IoT ハブで SAS URI の要素を提供できます。 デバイスではその後、これらの要素を使用して SAS URI を構築でき、この URI を使用して Azure Storage との間で認証を行い、BLOB コンテナーにファイルをアップロードします。

Azure Storage アカウントを IoT ハブに関連付けるには:

  1. IoT ハブの左側のペインにある [Hub settings](ハブの設定) で、 [ファイルのアップロード] を選びます。

    ポータルから [ファイルのアップロード] 設定の選択を示すスクリーン キャプチャ。

  2. [ファイルのアップロード] ペインで、 [Azure Storage コンテナー] を選択します。 この記事の場合は、ストレージ アカウントと IoT Hub を同じリージョンに配置することをお勧めします。

    • 使おうとしているストレージ アカウントが既にある場合は、一覧からそれを選択します。

    • 新しいストレージ アカウントを作成するには、 [+ストレージ アカウント] を選択します。 ストレージ アカウントの名前を指定し、 [場所] が、お使いの IoT ハブと同じリージョンに設定されていることを確認し、 [OK] を選択します。 IoT ハブと同じリソース グループに新しいアカウントが作成されます。 デプロイが完了したら、一覧からそのストレージ アカウントを選択します。

    ストレージ アカウントを選択すると、 [コンテナー] ペインが開きます。

  3. [コンテナー] ペインで、BLOB コンテナーを選択します。

    • 使おうとしている BLOB コンテナーが既にある場合は、一覧からそれを選択し、 [選択] をクリックします。

    • 新しい BLOB コンテナーを作成するには、 [+ コンテナー] を選択します。 新しいコンテナーの名前を指定します。 この記事の目的上、他のフィールドはすべて既定のままにすることができます。 [作成] を選択します デプロイが完了したら、一覧からコンテナーを選択し、 [選択] をクリックします。

  4. [ファイルのアップロード] ペインに戻り、ファイル通知が [オン] に設定されていることを確認します。 他の設定はすべて既定値のままにすることができます。 [保存] を選択し、設定が完了するのを待ってから次のセクションに進みます。

    ポータルの [ファイルのアップロード] 設定の確認を示すスクリーン キャプチャ。

Azure Storage アカウントを作成する方法の詳細な手順については、「ストレージ アカウントを作成する」を参照してください。 ストレージ アカウントと BLOB コンテナーを IoT ハブに関連付ける方法の詳細な手順については、Azure portal を使用してファイルのアップロードを構成することに関するページを参照してください。

デバイス アプリからのファイルのアップロード

このセクションでは、IoT ハブにファイルをアップロードするデバイス アプリを作成します。 このコードは、Azure IoT Node.js SDK デバイス サンプルの upload_to_blob_advanced.js サンプルにあるコードに基づいています。

  1. fileupload という名前の空のフォルダーを作成します。 コマンド プロンプトで次のコマンドを使用して、fileupload フォルダー内に新しい package.json ファイルを作成します。 次の既定値をすべてそのまま使用します。

    npm init
    
  2. コマンド プロンプトで、fileupload フォルダーに移動し、次のコマンドを実行して、azure-iot-device Device SDK、azure-iot-device-mqtt@azure/storage-blob の各パッケージをインストールします。

    npm install azure-iot-device azure-iot-device-mqtt @azure/storage-blob --save
    
  3. テキスト エディターを使用して fileupload フォルダーに FileUpload.js ファイルを作成し、そこに次のコードをコピーします。

    'use strict';
    
    const Client = require('azure-iot-device').Client;
    const Protocol = require('azure-iot-device-mqtt').Mqtt;
    const errors = require('azure-iot-common').errors;
    const path = require('path');
    
    const {
      AnonymousCredential,
      BlockBlobClient,
      newPipeline
    } = require('@azure/storage-blob');
    
    // make sure you set these environment variables prior to running the sample.
    const deviceConnectionString = process.env.DEVICE_CONNECTION_STRING;
    const localFilePath = process.env.PATH_TO_FILE;
    const storageBlobName = path.basename(localFilePath);
    
    async function uploadToBlob(localFilePath, client) {
      const blobInfo = await client.getBlobSharedAccessSignature(storageBlobName);
      if (!blobInfo) {
        throw new errors.ArgumentError('Invalid upload parameters');
      }
    
      const pipeline = newPipeline(new AnonymousCredential(), {
        retryOptions: { maxTries: 4 },
        telemetry: { value: 'HighLevelSample V1.0.0' }, // Customized telemetry string
        keepAliveOptions: { enable: false }
      });
    
      // Construct the blob URL to construct the blob client for file uploads
      const { hostName, containerName, blobName, sasToken } = blobInfo;
      const blobUrl = `https://${hostName}/${containerName}/${blobName}${sasToken}`;
    
      // Create the BlockBlobClient for file upload to the Blob Storage Blob
      const blobClient = new BlockBlobClient(blobUrl, pipeline);
    
      // Setup blank status notification arguments to be filled in on success/failure
      let isSuccess;
      let statusCode;
      let statusDescription;
    
      try {
        const uploadStatus = await blobClient.uploadFile(localFilePath);
        console.log('uploadStreamToBlockBlob success');
    
        // Save successful status notification arguments
        isSuccess = true;
        statusCode = uploadStatus._response.status;
        statusDescription = uploadStatus._response.bodyAsText;
    
        // Notify IoT Hub of upload to blob status (success)
        console.log('notifyBlobUploadStatus success');
      }
      catch (err) {
        isSuccess = false;
        statusCode = err.code;
        statusDescription = err.message;
    
        console.log('notifyBlobUploadStatus failed');
        console.log(err);
      }
    
      await client.notifyBlobUploadStatus(blobInfo.correlationId, isSuccess, statusCode, statusDescription);
    }
    
    // Create a client device from the connection string and upload the local file to blob storage.
    const deviceClient = Client.fromConnectionString(deviceConnectionString, Protocol);
    uploadToBlob(localFilePath, deviceClient)
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        process.exit();
      });
    
  4. FileUpload.js ファイルを保存して閉じます。

  5. イメージ ファイルを fileupload フォルダーにコピーし、myimage.png などの名前を付けます。

  6. お使いのデバイスの接続文字列と、アップロードするファイルへのパスの環境変数を追加します。 デバイスを IoT ハブに登録した際に、デバイスの接続文字列が取得されています。

    • Windows の場合:

      set DEVICE_CONNECTION_STRING={your device connection string}
      set PATH_TO_FILE={your image filepath}
      
    • Linux/Bash の場合:

      export DEVICE_CONNECTION_STRING="{your device connection string}"
      export PATH_TO_FILE="{your image filepath}"
      

IoT ハブ接続文字列を取得する

この記事では、作成した IoT ハブからファイル アップロード通知メッセージを受け取るバックエンド サービスを作成します。 ファイル アップロード通知メッセージを受信するサービスには、サービス接続のアクセス許可が必要となります。 既定では、どの IoT Hub も、このアクセス許可を付与する service という名前の共有アクセス ポリシーがある状態で作成されます。

サービス ポリシーの IoT Hub 接続文字列を取得するには、次の手順を実行します。

  1. Azure portal で、 [リソース グループ] を選択します。 ハブが配置されているリソース グループを選択し、リソースの一覧からハブを選択します。

  2. IoT ハブの左側のウィンドウで、 [共有アクセス ポリシー] を選択します。

  3. ポリシーの一覧から、サービス ポリシーを選択します。

  4. [プライマリ接続文字列] をコピーし、値を保存します。

Azure portal で IoT ハブから接続文字列を取得する方法を示すスクリーンショット。

IoT Hub の共有アクセス ポリシーとアクセス許可の詳細については、「アクセス制御とアクセス許可」を参照してください。

ファイル アップロードの通知の受信

このセクションでは、IoT Hub からファイル アップロードの通知メッセージを受信する Node.js コンソール アプリケーションを作成します。

  1. fileuploadnotification という名前の空のフォルダーを作成します。 コマンド プロンプトで次のコマンドを使用して、fileuploadnotification フォルダー内に新しい package.json ファイルを作成します。 次の既定値をすべてそのまま使用します。

    npm init
    
  2. コマンド プロンプトで fileuploadnotification フォルダーに移動し、次のコマンドを実行して azure-iothub SDK パッケージをインストールします。

    npm install azure-iothub --save
    
  3. テキスト エディターを使用して、fileuploadnotification フォルダーに FileUploadNotification.js ファイルを作成します。

  4. FileUploadNotification.js ファイルの冒頭に次の require ステートメントを追加します。

    'use strict';
    
    const Client = require('azure-iothub').Client;
    
  5. 環境から IoT ハブの接続文字列を読み取ります。

    const connectionString = process.env.IOT_HUB_CONNECTION_STRING;
    
  6. 次のコードを追加して、接続文字列からサービス クライアントを作成します。

    const serviceClient = Client.fromConnectionString(connectionString);
    
  7. クライアントを開き、getFileNotificationReceiver 関数を使用してステータスの更新を受け取ります。

    serviceClient.open(function (err) {
      if (err) {
        console.error('Could not connect: ' + err.message);
      } else {
        console.log('Service client connected');
        serviceClient.getFileNotificationReceiver(function receiveFileUploadNotification(err, receiver){
          if (err) {
            console.error('error getting the file notification receiver: ' + err.toString());
          } else {
            receiver.on('message', function (msg) {
              console.log('File upload from device:')
              console.log(msg.getData().toString('utf-8'));
              receiver.complete(msg, function (err) {
                if (err) {
                  console.error('Could not finish the upload: ' + err.message);
                } else {
                  console.log('Upload complete');
                }
              });
            });
          }
        });
      }
    });
    

    注意

    ファイル アップロード通知をリッスンしているときに切断通知を受信する場合、receiver.on を使用して 'error' を登録する必要があります。 ファイル アップロード通知を引き続き受信するには、serviceClient.open メソッドを利用し、IoT Hub に再接続する必要があります。

  8. FileUploadNotification.js ファイルを保存して閉じます。

  9. IoT ハブ接続文字列の環境変数を追加します。 この文字列は、先ほど「IoT ハブ接続文字列を取得する」でコピーしたものです。

    • Windows の場合:

      set IOT_HUB_CONNECTION_STRING={your iot hub connection string}
      
    • Linux/Bash の場合:

      export IOT_HUB_CONNECTION_STRING="{your iot hub connection string}"
      

アプリケーションの実行

これで、アプリケーションを実行する準備が整いました。

fileuploadnotification フォルダーのコマンド プロンプトで、次のコマンドを実行します。

node FileUploadNotification.js

fileupload フォルダーのコマンド プロンプトで、次のコマンドを実行します。

node FileUpload.js

アップロードが完了した後の FileUpload アプリからの出力を次に示します。

uploadStreamToBlockBlob success
notifyBlobUploadStatus success

アップロードが完了した後の FileUploadNotification アプリからのサンプル出力を次に示します。

Service client connected
File upload from device:
{"deviceId":"myDeviceId","blobUri":"https://{your storage account name}.blob.core.windows.net/device-upload-container/myDeviceId/image.png","blobName":"myDeviceId/image.png","lastUpdatedTime":"2021-07-23T23:27:06+00:00","blobSizeInBytes":26214,"enqueuedTimeUtc":"2021-07-23T23:27:07.2580791Z"}

ファイルのアップロードを確認する

ポータルを使用して、構成したストレージ コンテナーにアップロードされたファイルを表示できます。

  1. Azure portal のストレージ アカウントに移動します。

  2. ストレージ アカウントの左ペインで、 [コンテナー] を選択します。

  3. ファイルをアップロードしたコンテナーを選択します。

  4. デバイスにちなんだ名前のフォルダーを選択します。

  5. ファイルをアップロードした BLOB を選択します。 この記事では、ファイルと同じ名前の BLOB です。

    アップロードされたファイルが表示されている Azure portal のスクリーンショット。

  6. 開いたページで BLOB のプロパティを表示します。 [ダウンロード] を選択 してファイルをダウンロードし、その内容をローカルで表示できます。

次の手順

この記事では、IoT Hub のファイル アップロード機能を使用して、デバイスからのファイルのアップロードを簡素化する方法を学習しました。 この機能をさらに詳しく知るには、以下の記事を参考にしてください。