通过 IoT 中心将设备中的文件上传到云 (Node.js)

本教程介绍如何:

  • 安全提供具有 Azure blob URI 的设备,用于上传文件。

  • 使用 IoT 中心文件上传通知触发处理应用后端中的文件。

从设备将遥测数据发送到 IoT 中心快速入门演示了 IoT 中心基本的设备到云的消息传送功能。 但是,在某些情况下,无法轻松地将设备发送的数据映射为 IoT 中心接受的相对较小的设备到云消息。 例如:

  • 包含图像的大型文件
  • 视频
  • 以高频率采样的振动数据
  • 某种形式的预处理数据。

通常使用 Azure 数据工厂Hadoop 堆栈等工具在云中批处理这些文件。 需要从设备上传文件时,仍可以使用 IoT 中心的安全性和可靠性。

在本文结束时,会运行两个 Node.js 控制台应用:

  • FileUpload.js,它使用 IoT 中心提供的 SAS URI 将文件上传到存储。

  • ReadFileUploadNotification.js,它可以接收来自 IoT 中心的文件上传通知。

注意

IoT 中心通过 Azure IoT 设备 SDK 来支持许多设备平台和语言(包括 C、Java、Python 和 JavaScript)。 有关如何将设备连接到 Azure IoT 中心的分步说明,请参阅 Azure IoT 开发人员中心

重要

使用 X.509 证书颁发机构 (CA) 身份验证的设备上的文件上传功能为公共预览版,并且必须启用预览模式。 它在使用 x.509 指纹身份验证的设备上已正式发布。 若要了解有关使用 IoT 中心进行 x.509 身份验证的详细信息,请参阅支持的 x.509 证书

先决条件

  • Node.js 版本 10.0.x 或更高版本。 建议使用 LTS 版本。 可以从 nodejs.org 下载 Node.js。

  • 有效的 Azure 帐户。 (如果没有帐户,只需几分钟即可创建一个试用帐户。)

  • 确保已在防火墙中打开端口 8883。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)

创建 IoT 中心

此部分介绍如何使用 Azure 门户创建 IoT 中心。

  1. 登录 Azure 门户

  2. 从 Azure 主页中选择“+ 创建资源”按钮,然后在“搜索市场”字段中输入“IoT 中心”。

  3. 在搜索结果中选择“IoT 中心”,然后选择“创建” 。

  4. 在“基本信息”选项卡上,按如下所示填写字段:

    • 订阅:选择要用于中心的订阅。

    • 资源组:选择一个资源组或新建一个资源组。 若要新建资源组,请选择“新建”并填写要使用的名称。 若要使用现有的资源组,请选择它。 有关详细信息,请参阅管理 Azure 资源管理器资源组

    • 区域:选择中心所在的区域。 选择最靠近你的位置。

    • IoT 中心名称:输入中心的名称。 此名称必须全局唯一。 如果输入的名称可用,会显示一个绿色复选标记。

    重要

    IoT 中心将公开为 DNS 终结点,因此,命名时请务必避免包含任何敏感信息。

    在 Azure 门户

  5. 在完成时选择“下一步:大小和规模”,以继续创建中心。

    使用新中心设置新中心的大小和Azure 门户

    可在此处接受默认设置。 如果需要,可以修改以下任何字段:

    • 定价和缩放层:选择的层。 可以根据你需要的功能数以及每天通过解决方案发送的消息数从多个层级中进行选择。 免费层适用于测试和评估。 允许 500 台设备连接到中心,每天最多可传输 8,000 条消息。 每个 Azure 订阅可以在免费层中创建一个 IoT 中心。

      如果正在完成 IoT 中心设备流的快速入门,请选择免费层。

    • IoT 中心单元:每日每单位允许的消息数取决于中心的定价层。 例如,如果希望中心支持 700,000 条消息引入,请选择两个 S1 层单位。 有关其他层选项的详细信息,请参阅选择合适的 IoT 中心层

    • 高级设置设备到云分区:此属性将设备到云的消息与消息同时读取 者的数量关联。 大多数中心只需要 4 个分区。

  6. 在完成时选择“下一步:标记”继续到下一屏幕。

    标记是名称/值对。 可以为多个资源和资源组分配相同的标记,以便对资源进行分类并合并计费。 有关详细信息,请参阅使用标记来组织 Azure 资源

使用新中心设置新中心的大小和Azure 门户

  1. 在完成时选择“下一步:查看+创建”可查看选择。 你会看到类似于此屏幕的内容,但其中包含创建中心时选择的值。

查看创建新中心的信息

  1. 选择“创建”以创建新的中心。 创建中心需要几分钟时间。

在 IoT 中心内注册新设备

本部分在 IoT 中心的标识注册表中创建设备标识。 设备无法连接到中心,除非它在标识注册表中具有条目。 有关详细信息,请参阅 IoT 中心开发人员指南

  1. 在 IoT 中心导航菜单中,打开“IoT 设备”,然后选择“新建”,在 IoT 中心添加设备 。

    在门户中创建设备标识

  2. 在“创建设备”中,提供新设备的名称(例如 myDeviceId),然后选择“保存”。 此操作会为 IoT 中心创建设备标识。

    添加新设备

    重要

    收集的日志中可能会显示设备 ID 用于客户支持和故障排除,因此,在为日志命名时,请务必避免包含任何敏感信息。

  3. 创建设备后,在“IoT 设备”窗格的列表中打开该设备。 复制“主连接字符串”以供稍后使用。

    设备连接字符串

注意

IoT 中心标识注册表只存储设备标识,以启用对 IoT 中心的安全访问。 它存储设备 ID 和密钥用作安全凭据,以及可用于禁用单个设备访问的启用/禁用标志。 如果应用程序需要存储其他特定于设备的元数据,则应使用特定于应用程序的存储。 有关详细信息,请参阅 IoT 中心开发人员指南

将 Azure 存储帐户关联到 IoT 中心

若要从设备上传文件,必须拥有与 IoT 中心关联的 Azure 存储帐户和 Azure Blob 存储容器。 将存储帐户和容器与 IoT 中心关联后,IoT 中心可以在设备请求时提供 SAS URI 的元素。 然后,设备可以使用这些元素来构造 SAS URI,并将其用于向 Azure 存储进行身份验证,以及上传文件到 blob 容器。

将 Azure 存储帐户与 IoT 中心关联:

  1. 在“消息”下方,IoT 中心的左窗格中选择“文件上传” 。

    门户中选择“文件上传设置”。

  2. 在“文件上传”窗格中,选择“Azure 存储容器” 。 对于本文,建议你的存储帐户和 IoT 中心位于同一区域。

    • 如果你已有要使用的存储帐户,请从列表中选择它。

    • 若要创建新的存储帐户,请选择“+存储帐户”。 为该存储帐户命名,并确保其位置设置为 IoT 中心的同一区域,然后选择“确定” 。 将在 IoT 中心的同一资源组中创建新帐户。 部署完成后,从列表中选择“存储帐户”。

    选择“存储帐户”后,将打开“容器”窗格。

  3. 在“容器”窗格中,选择“blob 容器”。

    • 如果已有要使用的 blob 容器,请从列表中选择它,然后单击“选择”。

    • 然后选择“新建容器”以创建新的 blob 容器。 为新容器命名。 出于本文的目的,可以将其他所有字段保留为默认值。 选择“创建”。 部署完成后,从列表中选择“容器”,然后单击“选择”。

  4. 回到“文件上传”窗格,确保文件通知设置为“开启” 。 可将其他所有设置保留默认值。 选择“保存”并等待设置完成,然后进入下一部分。

    门户中确认文件上传设置。

有关如何创建 Azure 存储帐户的详细说明,请参阅创建存储帐户。 若要了解如何将存储帐户以及 blob 容器与 IoT 中心关联的详细信息,请参阅使用 Azure 门户配置文件上传

从设备应用上传文件

在本部分,我们创建将文件上传到 IoT 中心的设备应用。 该代码基于 Azure IoT node.js SDK 设备示例中的 upload_to_blob_advanced.js 示例中提供的代码。

  1. 创建名为 fileupload 的空文件夹。 在 fileupload 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. 在文件夹中的命令提示符下 fileupload ,运行以下命令以安装 fileupload SDK、 azure iot-设备 mqtt@azure/storage-blob 包:

    npm install azure-iot-device azure-iot-device-mqtt @azure/storage-blob --save
    
  3. 使用文本编辑器,在文件夹中创建 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 中心都使用名为“服务”的共享访问策略创建,该策略会授予此权限。

若要获取 service策略的 IoT 中心连接字符串,请执行以下步骤:

  1. Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在 IoT 中心的左侧窗格上,选择“共享访问策略”。

  3. 在策略列表中,选择“service”策略。

  4. 在“共享访问密钥”下,选择“连接字符串 - 主密钥”的复制图标并保存值。

    显示如何检索连接字符串

有关 IoT 中心共享访问策略和权限的详细信息,请参阅访问控制和权限

接收文件上传通知

本部分中的操作将会创建一个 Node.js 控制台应用,用于接收来自 IoT 中心的文件上传通知消息。

  1. 创建名为 fileuploadnotification 的空文件夹。 在 fileuploadnotification 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. 在文件夹中的命令提示符下 fileuploadnotification ,运行以下命令以安装 fileuploadnotification SDK 包:

    npm install azure-iothub --save
    
  3. 使用文本编辑器,在文件夹中创建 FileUploadNotification.js 文件

  4. requirerequire文件的开头添加以下语句:

    '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'));
            });
          }
        });
      }
    });
    
  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.chinacloudapi.cn/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 门户中导航到存储帐户。

  2. 在存储帐户的左侧窗格中,选择“容器”。

  3. 选择已将文件上传到其中的容器。

  4. 选择与设备同名的文件夹。

  5. 选择已将文件上传到其中的 Blob。 在本文中,它是与你的文件同名的 Blob。

    在 Azure 门户中查看上传的文件的屏幕截图。

  6. 在打开的页面上查看 Blob 属性。 可以选择“下载”,以将该文件下载到本地并查看其内容。

后续步骤

在本教程中,你已学习了如何使用 IoT 中心的文件上传功能来简化从设备进行的文件上传。 可以使用以下文章继续探索 IoT 中心功能和方案: