教程:使用 Azure 资源管理器模板配置 IoT 中心消息路由
消息路由能够将遥测数据从 IoT 设备发送到内置的与事件中心兼容的终结点或自定义终结点,例如,Blob 存储、服务总线队列、服务总线主题和事件中心。 若要配置自定义消息路由,请创建路由查询来自定义与特定条件匹配的路由。 设置完成后,引入的数据将通过 IoT 中心自动路由到终结点。 如果某条消息与任何定义的路由查询不匹配,它会被路由到默认终结点。
本教程包括 2 个部分,介绍如何通过 IoT 中心设置和使用这些自定义路由查询。 将消息从 IoT 设备路由到多个终结点中的一个,包括 Blob 存储和服务总线队列。 路由到服务总线队列的消息将由逻辑应用拾取,并通过电子邮件发送。 未定义自定义消息路由的消息将发送到默认终结点,然后由 Azure 流分析拾取,可在 Power BI 中直观查看。
若要完成本教程的第 1 和第 2 部分,请执行以下任务:
第 I 部分:创建资源并设置消息路由
- 创建资源 - IoT 中心、存储帐户、服务总线队列和模拟设备。 使用 Azure 门户、Azure 资源管理器模板、Azure CLI 或 Azure PowerShell 即可完成此操作。
- 在 IoT 中心为存储帐户和服务总线队列配置终结点和消息路由。
第 II 部分:将消息发送到中心并查看路由的结果
- 创建一个逻辑应用,该应用将在消息添加到服务总线队列时触发,并发送电子邮件。
- 下载并运行应用,该应用模拟 IoT 设备将消息发送到中心,以获得不同的路由选择。
- 为发送至默认终结点的数据创建 Power BI 可视化。
- 查看结果...
- ...在服务总线队列和电子邮件中。
- ...在存储帐户中。
- ...在 Power BI 可视化中。
先决条件
对于本教程的第 1 部分:
- 必须拥有 Azure 订阅。 如果没有 Azure 订阅,请在开始前创建一个试用版订阅。
对于本教程的第 2 部分:
必须事先完成本教程的第 1 部分,并保留一些可用的资源。
安装 Visual Studio。
有权访问用于分析默认终结点的流分析的 Power BI 帐户。 (免费试用 Power BI。)
提供一个用于发送通知电子邮件的工作或学校帐户。
确保已在防火墙中打开端口 8883。 本教程中的示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)。
创建基础资源
在配置消息路由之前,需创建 IoT 中心、存储帐户和服务总线队列。 可以参阅适用于本教程第 1 部分的四篇文章中的一篇来创建这些资源:Azure门户、Azure 资源管理器模板、Azure CLI 或 Azure PowerShell。
为所有资源使用相同的资源组和位置。 在本教程结束后,可以通过删除资源组一次性删除所有资源。
下面是将在以下部分中执行的步骤摘要:
创建资源组。
在 S1 层级中创建 IoT 中心。 将使用者组添加到 IoT 中心。 检索数据时,Azure 流分析使用使用者组。
注意
必须使用付费层中的 IoT 中心来完成本教程。 免费层只允许设置一个终结点,但本教程需要多个终结点。
使用 Standard_LRS 副本创建标准 V1 存储帐户。
创建服务总线命名空间和队列。
为发送消息到中心的模拟设备创建设备标识。 保存测试阶段的密钥。 (如果创建资源管理器模板,则会在部署模板后执行此操作。)
消息路由
根据模拟设备附加到消息的属性将消息路由到不同资源。 未自定义路由的消息将发送到默认终结点(消息/事件)。 在下一教程中,我们会将消息发送到 IoT 中心,看其如何路由到不同的目标。
值 | 结果 |
---|---|
级别=“storage” | 写入到 Azure 存储。 |
级别=“critical” | 写入服务总线队列。 逻辑应用从队列检索消息并使用 Office 365 通过电子邮件发送该消息。 |
default | 使用 Power BI 显示此数据。 |
第一步是设置终结点,以便将数据路由到其中。 第二步是设置使用该终结点的消息路由。 设置路由后,即可在门户中查看终结点和消息路由。
下载模板和参数文件
在本教程的第二部分,我们将下载并运行一个 Visual Studio 应用程序,以将消息发送到 IoT 中心。 该下载内容的某个文件夹中包含 Azure 资源管理器模板和参数文件,以及 Azure CLI 和 PowerShell 脚本。
现在请继续下载 Azure IoT C# 示例。 解压缩 master.zip 文件。 资源管理器模板和参数文件位于 /iot-hub/Tutorials/Routing/SimulatedDevice/resources/ 中,其文件名分别为 template_iothub.json 和 template_iothub_parameters.json。
创建资源
我们将使用 Azure 资源管理器 (RM) 模板来创建所有资源。 每次可以运行几行 Azure CLI 和 PowerShell 脚本。 RM 模板是通过一个步骤部署的。 本文通过单独的部分来介绍每种方法。 然后,介绍如何部署模板,以及创建虚拟设备用于测试。 部署模板后,可以在门户中查看消息路由配置。
有几个资源名称必须全局唯一,例如 IoT 中心名称和存储帐户名称。 为了简化资源的命名,将在设置的这些资源名称后面追加一个基于当前日期/时间随机生成的字母数字值。
查看模板时,将会看到为这些资源设置的变量的位置。这些变量采用传入的参数,并将 randomValue 连接到该参数。
以下部分将解释所用的参数。
参数
其中的大部分参数都具有默认值。 以 _in 结尾的参数将与 randomValue 相连接,使参数名称全局唯一。
randomValue:此值是基于部署模板时的日期/时间生成的。 此字段不包含在参数文件中,因为它是在模板本身中生成的。
subscriptionId:此字段用于标识要在其中部署模板的订阅。 此字段不包含在参数文件中,因为它是由系统设置的。
IoTHubName_in:此字段是基本 IoT 中心名称,其中连接了 randomValue,以便使名称全局唯一。
location:此字段是要部署到的 Azure 区域,例如“chinaeast”。
consumer_group:此字段是为通过路由终结点传入的消息设置的使用者组。 它用于筛选 Azure 流分析中的结果。 例如,如果我们想要获取整个流中的所有内容,或者数据通过设置为 Contoso 的 consumer_group 传入,则我们可将 Azure 流分析流(和 Power BI 报表)设置为仅显示这些条目。 本教程的第 2 部分将使用此字段。
sku_name:此字段是 IoT 中心的规模。 此值必须为 S1 或更高;免费层不适用于本教程,因为它不允许多个终结点。
sku_units:此字段类似于 sku_name,表示可以使用的 IoT 中心单位数。
d2c_partitions:此字段表示用于事件流的分区数。
storageAccountName_in:此字段是要创建的存储帐户的名称。 消息将路由到存储帐户中的容器。 此字段与 randomValue 相连接,使名称全局唯一。
storageContainerName:此字段是路由到存储帐户的消息的存储容器。
storage_endpoint:此字段是消息路由使用的存储帐户终结点的名称。
service_bus_namespace_in:此字段是要创建的服务总线命名空间的名称。 此值与 randomValue 相连接,使名称全局唯一。
service_bus_queue_in:此字段是用于路由消息的服务总线队列的名称。 此值与 randomValue 相连接,使名称全局唯一。
AuthRules_sb_queue:此字段是服务总线队列的授权规则,用于检索队列的连接字符串。
变量
这些值将在模板中使用,往往派生自参数。
queueAuthorizationRuleResourceId:此字段是服务总线队列的授权规则的 ResourceId。 而 ResourceId 用于检索队列的连接字符串。
iotHubName:此字段是连接 randomValue 后的 IoT 中心名称。
storageAccountName:此字段是连接 randomValue 后的存储帐户名称。
service_bus_namespace:此字段是连接 randomValue 后的命名空间。
service_bus_queue:此字段是连接 randomValue 后的服务总线队列名称。
sbVersion:要使用的服务总线 API 版本。 在本例中为“2017-04-01”。
资源:存储帐户和容器
创建的第一个资源是存储帐户,以及消息要路由到的容器。 容器是存储帐户下的资源。 容器具有存储帐户的 dependsOn
子句,因此,必须先创建存储帐户,再创建容器。
下面是此节的外观:
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2018-07-01",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {},
"resources": [
{
"type": "blobServices/containers",
"apiVersion": "2018-07-01",
"name": "[concat('default/', parameters('storageContainerName'))]",
"properties": {
"publicAccess": "None"
} ,
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
}
]
}
资源:服务总线命名空间和队列
创建的第二个资源是服务总线命名空间,以及消息要路由到的服务总线队列。 SKU 设置为“标准”。 从变量中检索 API 版本。 此资源设置为在部署此节时激活服务总线命名空间 (status:Active)。
{
"type": "Microsoft.ServiceBus/namespaces",
"comments": "The Sku should be 'Standard' for this tutorial.",
"sku": {
"name": "Standard",
"tier": "Standard"
},
"name": "[variables('service_bus_namespace')]",
"apiVersion": "[variables('sbVersion')]",
"location": "[parameters('location')]",
"properties": {
"provisioningState": "Succeeded",
"metricId": "[concat('a4295411-5eff-4f81-b77e-276ab1ccda12:', variables('service_bus_namespace'))]",
"serviceBusEndpoint": "[concat('https://', variables('service_bus_namespace'),'.servicebus.windows.net:443/')]",
"status": "Active"
},
"dependsOn": []
}
此节创建服务总线队列。 此脚本部分包含 dependsOn
子句,用于确保先创建命名空间,再创建队列。
{
"type": "Microsoft.ServiceBus/namespaces/queues",
"name": "[concat(variables('service_bus_namespace'), '/', variables('service_bus_queue'))]",
"apiVersion": "[variables('sbVersion')]",
"location": "[parameters('location')]",
"scale": null,
"properties": {},
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', variables('service_bus_namespace'))]"
]
}
资源:IoT 中心和消息路由
创建存储帐户和服务总线队列后,可以创建要将消息路由到的 IoT 中心。 RM 模板使用 dependsOn
子句,因此,它不会在创建服务总线资源和存储帐户之前尝试创建中心。
下面是 IoT 中心节的第一个部分。 此模板部分设置依赖项,以属性开头。
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Devices/IotHubs",
"name": "[variables('IoTHubName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"[resourceId('Microsoft.ServiceBus/namespaces', variables('service_bus_namespace'))]",
"[resourceId('Microsoft.ServiceBus/namespaces/queues', variables('service_bus_namespace'), variables('service_bus_queue'))]"
],
"properties": {
"eventHubEndpoints": {}
"events": {
"retentionTimeInDays": 1,
"partitionCount": "[parameters('d2c_partitions')]"
}
},
下一节是 Iot 中心的消息路由配置节。 首先是终结点节。 此模板部分设置服务总线队列和存储帐户的路由终结点,包括连接字符串。
若要创建队列的连接字符串,需要使用内联检索的 queueAuthorizationRulesResourcedId。 若要创建存储帐户的连接字符串,需要检索主存储密钥,然后在连接字符串的格式中使用该密钥。
也需要在终结点配置中将 Blob 格式设置为 AVRO
或 JSON
。
注意
可将数据以 Apache Avro 格式(默认)或 JSON 格式写入 Blob 存储。
编码格式只能在配置 Blob 存储终结点时设置。 不能更改已设置的终结点的格式。 使用 JSON 编码时,必须在消息系统属性中将 contentType 设置为 JSON,将 contentEncoding 设置为 UTF-8。
若要更详细地了解如何使用 Blob 存储终结点,请参阅有关如何路由到存储的指南。
"routing": {
"endpoints": {
"serviceBusQueues": [
{
"connectionString": "[Concat('Endpoint=sb://',variables('service_bus_namespace'),'.servicebus.windows.net/;SharedAccessKeyName=',parameters('AuthRules_sb_queue'),';SharedAccessKey=',listkeys(variables('queueAuthorizationRuleResourceId'),variables('sbVersion')).primaryKey,';EntityPath=',variables('service_bus_queue'))]",
"name": "[parameters('service_bus_queue_endpoint')]",
"subscriptionId": "[parameters('subscriptionId')]",
"resourceGroup": "[resourceGroup().Name]"
}
],
"serviceBusTopics": [],
"eventHubs": [],
"storageContainers": [
{
"connectionString":
"[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]",
"containerName": "[parameters('storageContainerName')]",
"fileNameFormat": "{iothub}/{partition}/{YYYY}/{MM}/{DD}/{HH}/{mm}",
"batchFrequencyInSeconds": 100,
"maxChunkSizeInBytes": 104857600,
"encoding": "avro",
"name": "[parameters('storage_endpoint')]",
"subscriptionId": "[parameters('subscriptionId')]",
"resourceGroup": "[resourceGroup().Name]"
}
]
},
下一节是用于将消息路由到终结点。 每个终结点存在一项设置,因此,服务总线队列和存储帐户容器各有一项设置。
请记住,路由到存储的消息的查询条件是 level="storage"
,路由到服务总线队列的消息的查询条件是 level="critical"
。
"routes": [
{
"name": "contosoStorageRoute",
"source": "DeviceMessages",
"condition": "level=\"storage\"",
"endpointNames": [
"[parameters('storage_endpoint')]"
],
"isEnabled": true
},
{
"name": "contosoSBQueueRoute",
"source": "DeviceMessages",
"condition": "level=\"critical\"",
"endpointNames": [
"[parameters('service_bus_queue_endpoint')]"
],
"isEnabled": true
}
],
此 JSON 演示了 IoT 中心节的余下内容,其中包含默认信息和中心的 SKU。
"fallbackRoute": {
"name": "$fallback",
"source": "DeviceMessages",
"condition": "true",
"endpointNames": [
"events"
],
"isEnabled": true
}
},
"storageEndpoints": {
"$default": {
"sasTtlAsIso8601": "PT1H",
"connectionString": "",
"containerName": ""
}
},
"messagingEndpoints": {
"fileNotifications": {
"lockDurationAsIso8601": "PT1M",
"ttlAsIso8601": "PT1H",
"maxDeliveryCount": 10
}
},
"enableFileUploadNotifications": false,
"cloudToDevice": {
"maxDeliveryCount": 10,
"defaultTtlAsIso8601": "PT1H",
"feedback": {
"lockDurationAsIso8601": "PT1M",
"ttlAsIso8601": "PT1H",
"maxDeliveryCount": 10
}
}
},
"sku": {
"name": "[parameters('sku_name')]",
"capacity": "[parameters('sku_units')]"
}
}
资源:服务总线队列授权规则
服务总线队列授权规则用于检索服务总线队列的连接字符串。 它使用 dependsOn
子句来确保先创建服务总线命名空间和服务总线队列,然后再创建授权规则。
{
"type": "Microsoft.ServiceBus/namespaces/queues/authorizationRules",
"name": "[concat(variables('service_bus_namespace'), '/', variables('service_bus_queue'), '/', parameters('AuthRules_sb_queue'))]",
"apiVersion": "[variables('sbVersion')]",
"location": "[parameters('location')]",
"scale": null,
"properties": {
"rights": [
"Send"
]
},
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', variables('service_bus_namespace'))]",
"[resourceId('Microsoft.ServiceBus/namespaces/queues', variables('service_bus_namespace'), variables('service_bus_queue'))]"
]
},
资源:使用者组
在此节中,创建 Azure 流分析在本教程第二部分使用的 IoT 中心数据的使用者组。
{
"type": "Microsoft.Devices/IotHubs/eventHubEndpoints/ConsumerGroups",
"name": "[concat(variables('iotHubName'), '/events/',parameters('consumer_group'))]",
"apiVersion": "2018-04-01",
"dependsOn": [
"[concat('Microsoft.Devices/IotHubs/', variables('iotHubName'))]"
]
}
资源:Outputs
若要将值发回到部署脚本以供显示,请使用 output 节。 此模板部分返回服务总线队列的连接字符串。 不一定要返回值;包含值的目的是通过示例演示如何向调用方脚本返回结果。
"outputs": {
"sbq_connectionString": {
"type": "string",
"value": "[Concat('Endpoint=sb://',variables('service_bus_namespace'),'.servicebus.windows.net/;SharedAccessKeyName=',parameters('AuthRules_sb_queue'),';SharedAccessKey=',listkeys(variables('queueAuthorizationRuleResourceId'),variables('sbVersion')).primaryKey,';EntityPath=',variables('service_bus_queue'))]"
}
}
部署 RM 模板
若要将模板部署到 Azure,请将模板和参数文件上传到 Azure Cloud Shell,然后执行某个脚本来部署模板。 打开 Azure Cloud Shell 并登录。 本示例使用 PowerShell。
若要上传文件,请在菜单栏中选择“上传/下载文件”图标,然后选择“上传”。
使用弹出的文件资源管理器找到本地磁盘上的文件并将其选中,然后选择“打开”。
上传文件后,结果对话框将显示下图所示的内容。
文件将上传到 Cloud Shell 实例使用的共享。
运行脚本以执行部署。 此脚本的最后一行检索设置返回的变量 - 服务总线队列连接字符串。
该脚本设置并使用以下变量:
$RGName 是模板要部署到的资源组名称。 此字段是在部署模板之前创建的。
$location 是将要用于模板的 Azure 位置,例如“chinaeast”。
deploymentname 是分配给部署的名称,用于检索返回变量值。
下面是 PowerShell 脚本。 请复制此 PowerShell 脚本并将其粘贴到 Cloud Shell 窗口中,然后按 Enter 运行它。
$RGName="ContosoResources"
$location = "chinaeast"
$deploymentname="contoso-routing"
# Remove the resource group if it already exists.
#Remove-AzResourceGroup -name $RGName
# Create the resource group.
New-AzResourceGroup -name $RGName -Location $location
# Set a path to the parameter file.
$parameterFile = "$HOME/template_iothub_parameters.json"
$templateFile = "$HOME/template_iothub.json"
# Deploy the template.
New-AzResourceGroupDeployment `
-Name $deploymentname `
-ResourceGroupName $RGName `
-TemplateParameterFile $parameterFile `
-TemplateFile $templateFile `
-verbose
# Get the returning value of the connection string.
(Get-AzResourceGroupDeployment -ResourceGroupName $RGName -Name $deploymentname).Outputs.sbq_connectionString.value
如果遇到脚本错误,可在本地编辑脚本,再次将其上传到 Cloud Shell,然后再次运行该脚本。 脚本成功完成运行后,请继续下一步。
创建模拟设备
接下来,创建设备标识并保存其密钥供之后使用。 此设备标识由模拟应用程序用来发送消息到 IoT 中心。 此功能在 PowerShell 中不可用,在使用 Azure 资源管理器模板时也不可用。 以下步骤介绍如何使用 Azure 门户创建模拟设备。
打开 Azure 门户并登录到 Azure 帐户。
选择“资源组”,然后选择你的资源组。 本教程使用 ContosoResources 。
在资源列表中,选择 IoT 中心。 本教程使用 ContosoTestHub 。 从中心窗格选择“IoT 设备”。
在“IoT 设备”窗格中选择“+ 添加设备” 。 在添加设备窗格中,填写设备 ID。 本教程使用 Contoso-Test-Device。 将密钥留空,勾选“自动生成密钥”。 确保已启用“将设备连接到 IoT 中心”。 选择“保存” 。
创建设备后,即可选择它来查看生成的密钥。 选择主密钥上的“复制”图标,将其保存在某个位置(如记事本)供本教程的测试阶段使用。
在门户中查看消息路由
设置终结点和消息路由以后,即可在门户中查看其配置。 登录 Azure 门户,转到“资源组”。 接下来选择你的资源组,然后选择中心(在本教程中,中心名称以 ContosoTestHub
开头)。 此时会看到“IoT 中心”窗格。
在适用于 IoT 中心的选项中,选择“消息路由”。 此时会显示已成功设置的路由。
在“消息路由”屏幕上选择“自定义终结点”,查看为路由定义的终结点。
后续步骤
设置所有资源并配置消息路由后,请继续学习下一篇教程,了解如何处理和显示有关路由的消息的信息。