快速入门:使用 ARM 模板部署 Azure IoT 中心和存储帐户

在此快速入门中,你将使用 Azure 资源管理器模板(ARM 模板)创建 IoT 中心、Azure 存储帐户和路由,从而将来自 IoT 中心的消息路由到存储区。 该中心经过配置,这样,如果发送到该中心的消息满足路由条件,会自动路由到存储帐户。 在本快速入门教程时,你可以打开该存储帐户并查看发送的消息。

资源管理器模板是定义项目基础结构和配置的 JavaScript 对象表示法 (JSON) 文件。 模板使用声明性语法。 在声明性语法中,你可以在不编写创建部署的编程命令序列的情况下,描述预期部署。

如果你的环境满足先决条件,并且你熟悉如何使用 ARM 模板,请选择“部署到 Azure”按钮。 模板将在 Azure 门户中打开。

部署到 Azure

先决条件

查看模板

本快速入门中使用的模板称为 101-iothub-auto-route-messages,来自 Azure 快速入门模板

该模板中定义了两个 Azure 资源:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.6.18.56646",
      "templateHash": "9942060226287533039"
    }
  },
  "parameters": {
    "projectName": {
      "type": "string",
      "defaultValue": "contoso",
      "maxLength": 11,
      "minLength": 1,
      "metadata": {
        "description": "Define the project name or prefix for all objects."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "The datacenter to use for the deployment."
      }
    },
    "skuName": {
      "type": "string",
      "defaultValue": "S1",
      "metadata": {
        "description": "The SKU to use for the IoT Hub."
      }
    },
    "skuUnits": {
      "type": "int",
      "defaultValue": 1,
      "metadata": {
        "description": "The number of IoT Hub units."
      }
    },
    "d2cPartitions": {
      "type": "int",
      "defaultValue": 4,
      "metadata": {
        "description": "Partitions used for the event stream."
      }
    }
  },
  "variables": {
    "iotHubName": "[format('{0}Hub{1}', parameters('projectName'), uniqueString(resourceGroup().id))]",
    "storageAccountName": "[format('{0}{1}', toLower(parameters('projectName')), uniqueString(resourceGroup().id))]",
    "storageEndpoint": "[format('{0}StorageEndpont', parameters('projectName'))]",
    "storageContainerName": "[format('{0}results', toLower(parameters('projectName')))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-08-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage"
    },
    {
      "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
      "apiVersion": "2021-08-01",
      "name": "[format('{0}/default/{1}', variables('storageAccountName'), variables('storageContainerName'))]",
      "properties": {
        "publicAccess": "None"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.Devices/IotHubs",
      "apiVersion": "2021-07-02",
      "name": "[variables('iotHubName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('skuName')]",
        "capacity": "[parameters('skuUnits')]"
      },
      "properties": {
        "eventHubEndpoints": {
          "events": {
            "retentionTimeInDays": 1,
            "partitionCount": "[parameters('d2cPartitions')]"
          }
        },
        "routing": {
          "endpoints": {
            "storageContainers": [
              {
                "connectionString": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]",
                "containerName": "[variables('storageContainerName')]",
                "fileNameFormat": "{iothub}/{partition}/{YYYY}/{MM}/{DD}/{HH}/{mm}",
                "batchFrequencyInSeconds": 100,
                "maxChunkSizeInBytes": 104857600,
                "encoding": "JSON",
                "name": "[variables('storageEndpoint')]"
              }
            ]
          },
          "routes": [
            {
              "name": "ContosoStorageRoute",
              "source": "DeviceMessages",
              "condition": "level=\"storage\"",
              "endpointNames": [
                "[variables('storageEndpoint')]"
              ],
              "isEnabled": true
            }
          ],
          "fallbackRoute": {
            "name": "$fallback",
            "source": "DeviceMessages",
            "condition": "true",
            "endpointNames": [
              "events"
            ],
            "isEnabled": true
          }
        },
        "messagingEndpoints": {
          "fileNotifications": {
            "lockDurationAsIso8601": "PT1M",
            "ttlAsIso8601": "PT1H",
            "maxDeliveryCount": 10
          }
        },
        "enableFileUploadNotifications": false,
        "cloudToDevice": {
          "maxDeliveryCount": 10,
          "defaultTtlAsIso8601": "PT1H",
          "feedback": {
            "lockDurationAsIso8601": "PT1M",
            "ttlAsIso8601": "PT1H",
            "maxDeliveryCount": 10
          }
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    }
  ]
}

部署模板

本部分提供 ARM 模板的部署步骤。

  • 通过部署 ARM 模板创建资源。

    部署到 Azure

发送设备到云的消息

在本部分中,你将在新的 IoT 中心注册设备,然后将来自该设备的消息发送到 IoT 中心。 如果消息包含消息属性 level=storage,模板在 IoT 中心配置的路由仅将消息发送到存储区。 为了测试此路由条件是否按预期工作,我们将发送一些包含此属性和一些没有此书信的消息。

提示

为了方便起见,本快速入门使用 Azure CLI 模拟设备。 有关发送具有消息属性的设备到云消息进行路由的代码示例,请参阅 Azure IoT SDK for .NET 中的 HubRoutingSample

  1. 检索模板为你创建的 IoT 中心的名称。

    如果使用了上一部分中的默认命令,则资源是在 ContosoResourceGrp 资源组中创建的。 如果使用了其他资源组,请更新以下命令来进行匹配。

    az iot hub list --resource-group ContosoResourceGrp --output table
    
  2. 从输出中复制 IoT 中心的名称。 它应格式化为 contosoHub{randomidentifier}

  3. 将设备添加到中心。

    az iot hub device-identity create --device-id contosoDevice --hub-name {YourIoTHubName} 
    
  4. 模拟设备并发送设备到云的消息。

    --data 参数让我们能够设置消息正文。

    az iot device simulate \
      --device-id contosoDevice \
      --hub-name {YourIoTHubName} \
      --data "This message won't be routed."
    

    模拟器发送 100 条消息,然后断开连接。 对于本快速入门,无需等待所有 100 条消息。

  5. 发送设备到云的消息以路由到存储区。

    --properties 参数让我们能够向默认消息添加消息、应用程序或系统属性。 在本快速入门中,IoT 中心内的路由会查找包含消息属性 level=storage 的消息。

    az iot device simulate \
      --device-id contosoDevice \
      --hub-name {YourIoTHubName} \
      --properties level=storage \
      --data "This message will be routed to storage."
    

查看已部署的资源

  1. 登录到 Azure 门户并选择“资源组”,然后选择存储帐户。

  2. 向下钻取到存储帐户,直到找到文件。

    查看存储帐户文件

  3. 选择其中一个文件并选择“下载”,将文件下载到你稍后可以找到的位置。 它有一个数值名称,例如 47。 在末尾添加“.txt”,然后双击文件打开它。

  4. 打开文件时,每一行对应一条不同的消息;每条消息的正文都进行了加密。 必须这样才能对消息正文执行查询。

    查看已发送的消息

    注意

    这些消息以 UTF-32 和 base64 编码。 如果读回消息,必须由 base64 和 utf-32 对其进行解码,以便以 ASCII 格式进行读取。 如果你感兴趣,可以使用路由教程中的 ReadOneRowFromFile 方法从其中某个消息文件对其进行读取,并将其解码为 ASCII。 ReadOneRowFromFile 位于你为此快速入门解压缩的 IoT C# SDK 存储库中。 从该文件夹顶层开始的路径为:/iot-hub/Tutorials/Routing/SimulatedDevice/Program.cs。将布尔值 readTheFile 设置为 true,并对磁盘上的文件路径进行硬编码,此操作会打开并转换文件的第一行。

在快速入门中,你部署了一个 ARM 模板来创建 IoT 中心和存储帐户,然后运行程序来向中心发送消息。 这些消息根据其消息属性进行路由,并存储在可查看它们的存储帐户中。

清理资源

若要删除此快速入门期间添加的资源,请登录到 Azure 门户。 选择“资源组”,然后查找用于此快速入门的资源组。 选择资源组,然后选择“删除”。 删除组时,会一并删除组中的所有资源。

后续步骤