教程:通过设备预配服务 (DPS) 使用自定义分配策略
自定义分配策略让你能够更好地控制将设备分配到 IoT 中心的方式。 当 Azure IoT 中心设备预配服务 (DPS) 提供的策略不能满足你的方案的要求时,可使用自定义分配策略定义你自己的分配策略。 自定义分配策略在 Azure Functions中托管的 Webhook 中实现,并在一个或多个单独的注册和/或注册组上配置。 当设备使用配置的注册项向 DPS 注册时,DPS 会调用 Webhook 来找出设备应注册到的 IoT 中心,以及(可选)其初始状态。 若要了解详细信息,请参阅了解自定义分配策略。
本教程演示使用 C# 编写的 Azure 函数的自定义分配策略。 设备分配到两个 IoT 中心之一,分别表示 Contoso 烤箱分区和 Contoso 热泵分区。 请求预配的设备必须具有含以下后缀之一的注册 ID 才能被接受进行预配:
- -contoso-tstrsd-007,适用于 Contoso 烤箱分区
- -contoso-hpsd-088,适用于 Contoso 热泵分区
使用 Azure IoT C SDK 中包含的预配示例对设备进行模拟。
在本教程中,你将执行以下操作:
- 使用 Azure CLI 创建一个 DPS 实例,同时创建两个 Contoso 部门 IoT 中心(Contoso 烤箱部门和 Contoso 热泵部门)并将其链接到该实例。
- 创建一个实现自定义分配策略的 Azure 函数。
- 使用 Azure 函数为自定义分配策略创建新的注册组。
- 为两个模拟设备创建设备对称密钥。
- 为 Azure IoT C SDK 设置开发环境。
- 模拟设备,并验证是否根据自定义分配策略中的示例代码对其进行预配。
如果没有 Azure 试用版订阅,请在开始前创建一个试用版订阅。
先决条件
以下先决条件适用于 Windows 开发环境。 对于 Linux 或 macOS,请参阅 SDK 文档的准备开发环境中的相应部分。
Visual Studio 2022,已启用“使用 C++ 的桌面开发”工作负载。 Visual Studio 2015 和 Visual Studio 2017 也受支持。
已安装最新版本的 Git。
如需在本地运行 CLI 参考命令,请安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI。
如果使用的是本地安装,请使用 az login 命令登录到 Azure CLI。 若要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅使用 Azure CLI 登录。
出现提示时,请在首次使用时安装 Azure CLI 扩展。 有关扩展详细信息,请参阅使用 Azure CLI 的扩展。
运行 az version 以查找安装的版本和依赖库。 若要升级到最新版本,请运行 az upgrade。
创建预配服务和两个部门 IoT 中心
在本部分,我们使用 Azure CLI 创建一个预配服务和两个表示“Contoso 烤箱部门”和“Contoso 热泵部门”的 IoT 中心。
提示
本教程中使用的命令会在“中国北部”位置创建预配服务和其他资源。 我们建议在与你最靠近的区域中创建支持设备预配服务的资源。 若要查看可用位置的列表,可以运行 az provider show --namespace Microsoft.Devices --query "resourceTypes[?resourceType=='ProvisioningServices'].locations | [0]" --out table
命令,也可以转到Azure 状态页,在其中搜索“设备预配服务”。 在命令中,可以使用一个单词或多个单词的格式来指定位置,例如 chinanorth、China North、WEST US 等。该值不区分大小写。 如果使用多个单词的格式来指定位置,请将值置于引号中,例如 -- location "China North"
。
在 Azure CLI 中,使用 az group create 命令创建资源组。 Azure 资源组是在其中部署和管理 Azure 资源的逻辑容器。
以下示例创建了一个资源组。 建议对本教程中创建的所有资源使用一个组。 此方法使你能够在完成后更为轻松地进行清理。
az group create --name $RESOURCE_GROUP --location $LOCATION
使用 az iot dps create 命令创建设备预配服务 (DPS) 的实例。 该预配服务将添加到 contoso-us-resource-group。
az iot dps create --name $DPS --resource-group $RESOURCE_GROUP --location $LOCATION
该命令可能需要几分钟时间才能完成。
使用 az iot hub create 命令创建“Contoso 烤箱部门”IoT 中心。 IoT 中心将添加到 contoso-us-resource-group。
az iot hub create --name $TOASTER_HUB --resource-group $RESOURCE_GROUP --location $LOCATION --sku S1
该命令可能需要几分钟时间才能完成。
使用 az iot hub create 命令创建“Contoso 热泵部门”IoT 中心。 此 IoT 中心还会添加到 contoso-us-resource-group。
az iot hub create --name $HEATPUMP_HUB --resource-group $RESOURCE_GROUP --location $LOCATION --sku S1
该命令可能需要几分钟时间才能完成。
运行下面的两个命令来获取已创建的中心的连接字符串。
az iot hub connection-string show --hub-name $TOASTER_HUB --key primary --query connectionString -o tsv az iot hub connection-string show --hub-name $HEATPUMP_HUB --key primary --query connectionString -o tsv
运行以下命令来将中心链接到 DPS 资源。 将占位符替换为上一步中的中心连接字符串。
az iot dps linked-hub create --dps-name $DPS --resource-group $RESOURCE_GROUP --location $LOCATION --connection-string <toaster_hub_connection_string> az iot dps linked-hub create --dps-name $DPS --resource-group $RESOURCE_GROUP --location $LOCATION --connection-string <heatpump_hub_connection_string>
创建自定义分配函数
在本部分,你将创建一个实现自定义分配策略的 Azure 函数。 此函数根据设备的注册 ID 是包含字符串 -contoso-tstrsd-007 还是 -contoso-hpsd-088,来确定要将该设备注册到哪个部门 IoT 中心。 它还根据设备是烤箱还是热泵,来设置设备孪生的初始状态。
登录 Azure 门户。
在搜索框中,搜索并选择“函数应用”。
选择“创建”或“创建函数应用”。
在“函数应用”创建页上的“基本信息”选项卡下,输入新函数应用的以下设置,然后选择“查看 + 创建”:
参数 值 订阅 确保已选择为本教程创建资源时所在的订阅。 资源组 选择你在上一部分中创建的资源组。 上一部分中提供的默认值为 contoso-us-resource-group。 函数应用名称 为函数应用提供名称。 是否要部署代码或容器映像? 代码 运行时堆栈 .NET 版本 选择任何一个“进程内模型”版本。 区域 选择附近的区域。 注意
默认已启用 Application Insights。 本教程不需要 Application Insights,但它可以帮助你了解和调查处理自定义分配时遇到的任何问题。 如果需要,可以禁用 Application Insights,方法是选择“监视”选项卡,然后对“启用 Application Insights”选择“否”。
在“查看 + 创建”选项卡上,选择“创建”以创建函数应用。
部署可能需要几分钟时间。 完成后,选择“转到资源”。
在函数应用“概述”页的左窗格中,选择“创建函数”。
在“创建函数”页上,选择“HTTP 触发器”模板,然后选择“下一步”。
在“模板详细信息”选项卡上,选择“匿名”作为授权级别,然后选择“创建”。
提示
如果将授权级别保留为“函数”,则需要使用函数 API 密钥配置 DPS 注册。 有关详细信息,请参阅 Azure Functions HTTP 触发器。
当 HttpTrigger1 函数打开时,选择左窗格中的“代码 + 测试”。 这允许你编辑函数的代码。 run.csx 代码文件应该会打开供编辑。
引用所需的 NuGet 包。 为了创建初始设备孪生,自定义分配函数将使用必须载入托管环境的两个 NuGet 包中定义的类。 在 Azure Functions 中,NuGet 包是使用 function.proj 文件引用的。 在此步骤中,你将保存并上传所需程序集的 function.proj 文件。 有关详细信息,请参阅通过 Azure Functions 使用 NuGet 包。
将以下行复制到你喜欢使用的编辑器中,并在你的计算机上将该文件保存为“function.proj”。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Azure.Devices.Provisioning.Service" Version="1.18.1" /> <PackageReference Include="Microsoft.Azure.Devices.Shared" Version="1.30.1" /> </ItemGroup> </Project>
选择位于代码编辑器上方的“上传”按钮,以上传“function.proj”文件。 上传后,在代码编辑器中使用下拉框选择该文件来验证内容。
在代码编辑器中选择 function.proj 文件并验证其内容。 如果 function.proj 文件为空,请将上面的行复制到文件中并保存。 (有时上传会在不上传内容的情况下创建文件。)
请确保在代码编辑器中为 HttpTrigger1 选择“run.csx”。 将 HttpTrigger1 函数的代码替换为以下代码,然后选择“保存”:
#r "Newtonsoft.Json" using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Newtonsoft.Json; using Microsoft.Azure.Devices.Shared; // For TwinCollection using Microsoft.Azure.Devices.Provisioning.Service; // For TwinState public static async Task<IActionResult> Run(HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); // Get request body string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody); log.LogInformation("Request.Body:..."); log.LogInformation(requestBody); // Get registration ID of the device string regId = data?.deviceRuntimeContext?.registrationId; string message = "Uncaught error"; bool fail = false; ResponseObj obj = new ResponseObj(); if (regId == null) { message = "Registration ID not provided for the device."; log.LogInformation("Registration ID : NULL"); fail = true; } else { string[] hubs = data?.linkedHubs?.ToObject<string[]>(); // Must have hubs selected on the enrollment if (hubs == null) { message = "No hub group defined for the enrollment."; log.LogInformation("linkedHubs : NULL"); fail = true; } else { // This is a Contoso Toaster Model 007 if (regId.Contains("-contoso-tstrsd-007")) { //Find the "-toasters-" IoT hub configured on the enrollment foreach(string hubString in hubs) { if (hubString.Contains("-toasters-")) obj.iotHubHostName = hubString; } if (obj.iotHubHostName == null) { message = "No toasters hub found for the enrollment."; log.LogInformation(message); fail = true; } else { // Specify the initial tags for the device. TwinCollection tags = new TwinCollection(); tags["deviceType"] = "toaster"; // Specify the initial desired properties for the device. TwinCollection properties = new TwinCollection(); properties["state"] = "ready"; properties["darknessSetting"] = "medium"; // Add the initial twin state to the response. TwinState twinState = new TwinState(tags, properties); obj.initialTwin = twinState; } } // This is a Contoso Heat pump Model 008 else if (regId.Contains("-contoso-hpsd-088")) { //Find the "-heatpumps-" IoT hub configured on the enrollment foreach(string hubString in hubs) { if (hubString.Contains("-heatpumps-")) obj.iotHubHostName = hubString; } if (obj.iotHubHostName == null) { message = "No heat pumps hub found for the enrollment."; log.LogInformation(message); fail = true; } else { // Specify the initial tags for the device. TwinCollection tags = new TwinCollection(); tags["deviceType"] = "heatpump"; // Specify the initial desired properties for the device. TwinCollection properties = new TwinCollection(); properties["state"] = "on"; properties["temperatureSetting"] = "65"; // Add the initial twin state to the response. TwinState twinState = new TwinState(tags, properties); obj.initialTwin = twinState; } } // Unrecognized device. else { fail = true; message = "Unrecognized device registration."; log.LogInformation("Unknown device registration"); } } } log.LogInformation("\nResponse"); log.LogInformation((obj.iotHubHostName != null) ? JsonConvert.SerializeObject(obj) : message); return (fail) ? new BadRequestObjectResult(message) : (ActionResult)new OkObjectResult(obj); } public class ResponseObj { public string iotHubHostName {get; set;} public TwinState initialTwin {get; set;} }
创建注册
在本部分,你将创建一个使用自定义分配策略的新注册组。 为简单起见,本教程将在注册中使用对称密钥证明。 对于更安全的解决方案,请考虑使用具有信任链的 X.509 证书证明。
登录到 Azure 门户,并导航到设备预配服务实例。
从导航菜单的“设置”部分选择“管理注册”。
选择“添加注册组”。
在“添加注册组”页的“注册 + 预配”选项卡上,提供以下信息以配置注册组详细信息:
字段 说明 证明 选择“对称密钥”作为证明类型。 对称密钥设置 选中“自动生成对称密钥”复选框。 组名 输入“contoso-custom-allocated-devices”作为组名称。 预配状态 选中“启用此注册”复选框。 选择“下一步:IoT 中心”。
在“添加注册组”页的“IoT 中心”选项卡上,提供以下信息以确定注册组可以预配设备的目标 IoT 中心:
字段 说明 目标 IoT 中心 选择一个或多个链接的 IoT 中心,或向 IoT 中心添加新链接。 分配策略 选择“自定义(使用 Azure 函数)”。 选择“选择 Azure 函数”,然后根据提示选择为本教程创建的函数。 选择“查看 + 创建”。
在“审阅 + 创建”选项卡上,验证你的全部值,然后选择“创建”。
保存注册后,重新打开它,并记录“主密钥”。 必须先保存注册,才能生成密钥。 此密钥在下一部分中用于为模拟设备生成唯一的设备密钥。
派生唯一设备密钥
设备不直接使用注册组的主对称密钥。 你可以改为使用主密钥来派生每个设备的设备密钥。 在本部分,你将创建两个唯一的设备密钥。 一个密钥用于模拟的烤箱设备。 另一个密钥用于模拟的热泵设备。
若要派生设备密钥,请使用前面记下的注册组主密钥来计算每个设备的设备注册 ID 的 HMAC-SHA256,并将结果转换为 Base64 格式。 有关使用注册组创建派生设备密钥的详细信息,请参阅对称密钥证明的组注册部分。
对于本教程中的示例,使用以下两个设备注册 ID 并计算这两个设备的设备密钥。 这两个注册 ID 都具有有效的后缀,以与自定义分配策略的示例代码结合使用:
- breakroom499-contoso-tstrsd-007
- mainbuilding167-contoso-hpsd-088
Azure CLI 的 IoT 扩展提供了用于生成派生设备密钥的 iot dps enrollment-group compute-device-key
命令。 可在基于 Windows 或 Linux 的系统上通过 PowerShell 或 Bash shell 使用此命令。
将 --key
参数值替换为注册组中的主密钥。
az iot dps enrollment-group compute-device-key --key <ENROLLMENT_GROUP_KEY> --registration-id breakroom499-contoso-tstrsd-007
az iot dps compute-device-key --key <ENROLLMENT_GROUP_KEY> --registration-id mainbuilding167-contoso-hpsd-088
注意
还可以向 iot dps enrollment-group compute-device-key
命令提供注册组 ID,而不是对称密钥。 例如:
az iot dps enrollment-group compute-device-key -g contoso-us-resource-group --dps-name contoso-provisioning-service-1098 --enrollment-id contoso-custom-allocated-devices --registration-id breakroom499-contoso-tstrsd-007
模拟设备使用含有每个注册 ID 的派生的设备密钥,以执行对称密钥证明。
准备 Azure IoT C SDK 开发环境
在本部分,你将准备一个用于生成 Azure IoT C SDK 的开发环境。 SDK 包含模拟设备的示例代码。 该模拟设备将尝试在设备启动顺序期间进行预配。
本部分面向基于 Windows 的工作站。 有关 Linux 示例,请参阅教程:预配地理延迟中的 VM 设置。
下载 CMake 生成系统。
在进行
CMake
安装之前,必须在计算机上安装 Visual Studio 必备组件(Visual Studio 和“使用 C++ 的桌面开发”工作负载)。 满足先决条件并验证下载内容后,安装 CMake 生成系统。找到最新版 SDK 的标记名称。
打开命令提示符或 Git Bash shell。 运行以下命令,以克隆最新版本的适用于 C 的 Azure IoT 设备 SDK GitHub 存储库。 将在上一步中找到的标记用作
-b
参数的值,例如:lts_01_2023
。git clone -b <release-tag> https://github.com/Azure/azure-iot-sdk-c.git cd azure-iot-sdk-c git submodule update --init
应该预料到此操作需要几分钟才能完成。
在 git 存储库的根目录中创建
cmake
子目录,并导航到该文件夹。 从azure-iot-sdk-c
目录运行以下命令:mkdir cmake cd cmake
运行以下命令,生成特定于你的开发客户端平台的 SDK 版本。 将在
cmake
目录中生成模拟设备的 Visual Studio 解决方案。cmake -Dhsm_type_symm_key:BOOL=ON -Duse_prov_client:BOOL=ON ..
如果
cmake
找不到 C++ 编译器,则在运行该命令时可能会出现生成错误。 如果出现这种情况,请尝试在 Visual Studio 命令提示符窗口中运行该命令。生成成功后,最后的几个输出行如下所示:
$ cmake -Dhsm_type_symm_key:BOOL=ON -Duse_prov_client:BOOL=ON .. -- Building for: Visual Studio 15 2017 -- Selecting Windows SDK version 10.0.16299.0 to target Windows 10.0.17134. -- The C compiler identification is MSVC 19.12.25835.0 -- The CXX compiler identification is MSVC 19.12.25835.0 ... -- Configuring done -- Generating done -- Build files have been written to: E:/IoT Testing/azure-iot-sdk-c/cmake
模拟设备
在本部分,你将更新前面设置的、位于 Azure IoT C SDK 中的名为“prov_dev_client_sample”的预配示例。
此示例代码模拟将预配请求发送到你的设备预配服务实例的设备启动序列。 启动序列会导致烤箱设备被识别,且使用自定义分配策略将其分配到 IoT 中心。
在 Azure 门户中,选择设备预配服务的“概述”选项卡,记下“ID 范围”的值 。
在 Visual Studio 中,打开较早前通过运行 CMake 生成的 azure_iot_sdks.sln 解决方案文件。 解决方案文件应位于以下位置:
azure-iot-sdk-c\cmake\azure_iot_sdks.sln
在 Visual Studio 的“解决方案资源管理器”窗口中,导航到“Provision_Samples”文件夹。 展开名为“prov_dev_client_sample”的示例项目。 展开“源文件”,打开“prov_dev_client_sample.c”。
找到
id_scope
常量,将值替换为前面复制的“ID 范围”值。static const char* id_scope = "0ne00002193";
在同一文件中找到
main()
函数的定义。 确保hsm_type
变量设置为SECURE_DEVICE_TYPE_SYMMETRIC_KEY
,如下所示:SECURE_DEVICE_TYPE hsm_type; //hsm_type = SECURE_DEVICE_TYPE_TPM; //hsm_type = SECURE_DEVICE_TYPE_X509; hsm_type = SECURE_DEVICE_TYPE_SYMMETRIC_KEY;
在
main()
函数中,找到对Prov_Device_Register_Device()
的调用。 在调用之前,添加以下几行代码,这些代码在预配期间使用Prov_Device_Set_Provisioning_Payload()
传递自定义 JSON 有效负载。 可通过这种方式为自定义分配函数提供详细信息。 也可通过这种方式传递设备类型,而不检查注册 ID。 有关通过 DPS 发送和接收自定义数据有效负载的详细信息,请参阅如何在设备和 DPS 之间传输有效负载。// An example custom payload const char* custom_json_payload = "{\"MyDeviceFirmwareVersion\":\"12.0.2.5\",\"MyDeviceProvisioningVersion\":\"1.0.0.0\"}"; prov_device_result = Prov_Device_Set_Provisioning_Payload(prov_device_handle, custom_json_payload); if (prov_device_result != PROV_DEVICE_RESULT_OK) { (void)printf("\r\nFailure setting provisioning payload: %s\r\n", MU_ENUM_TO_STRING(PROV_DEVICE_RESULT, prov_device_result)); }
右键单击“prov_dev_client_sample”项目,然后选择“设为启动项目”。
模拟 Contoso 烤箱设备
若要模拟烤箱设备,请在 prov_dev_client_sample.c 中找到已注释掉的对
prov_dev_set_symmetric_key_info()
的调用。// Set the symmetric key if using they auth type //prov_dev_set_symmetric_key_info("<symm_registration_id>", "<symmetric_Key>");
取消注释该函数调用,并将占位符值(包括尖括号)替换为烤箱注册 ID 以及前面生成的派生设备密钥。 下面显示的密钥值 JC8F96eayuQwwz+PkE7IzjH2lIAjCUnAa61tDigBnSs= 仅作为示例提供。
// Set the symmetric key if using they auth type prov_dev_set_symmetric_key_info("breakroom499-contoso-tstrsd-007", "JC8F96eayuQwwz+PkE7IzjH2lIAjCUnAa61tDigBnSs=");
保存文件。
在 Visual Studio 菜单中,选择“调试”>“开始执行(不调试)”以运行该解决方案。 出现重新生成项目的提示时,请选择“是”,以便在运行项目之前重新生成项目 。
以下输出是模拟烤箱设备成功启动并连接到预配服务实例以通过自定义分配策略分配到烤箱 IoT 中心的一个示例:
Provisioning API Version: 1.8.0 Registering Device Provisioning Status: PROV_DEVICE_REG_STATUS_CONNECTED Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Registration Information received from service: contoso-toasters-hub-1098.azure-devices.cn, deviceId: breakroom499-contoso-tstrsd-007 Press enter key to exit:
以下输出是为烤箱设备运行的自定义分配函数代码的示例日志记录输出。 请注意,已成功为烤箱设备选择了一个中心。 还要注意
payload
属性,它包含你添加到代码中的自定义 JSON 内容。 这可供你的代码在deviceRuntimeContext
中使用。在门户中的函数代码下单击“日志”可以获得此日志记录:
2022-08-03T20:34:41.178 [Information] Executing 'Functions.HttpTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=12950752-6d75-4f41-844b-c253a6653d4f) 2022-08-03T20:34:41.340 [Information] C# HTTP trigger function processed a request. 2022-08-03T20:34:41.341 [Information] Request.Body:... 2022-08-03T20:34:41.341 [Information] {"enrollmentGroup":{"enrollmentGroupId":"contoso-custom-allocated-devices","attestation":{"type":"symmetricKey"},"capabilities":{"iotEdge":false},"etag":"\"0000f176-0000-0700-0000-62eaad1e0000\"","provisioningStatus":"enabled","reprovisionPolicy":{"updateHubAssignment":true,"migrateDeviceData":true},"createdDateTimeUtc":"2022-08-03T17:15:10.8464255Z","lastUpdatedDateTimeUtc":"2022-08-03T17:15:10.8464255Z","allocationPolicy":"custom","iotHubs":["contoso-toasters-hub-1098.azure-devices.cn","contoso-heatpumps-hub-1098.azure-devices.cn"],"customAllocationDefinition":{"webhookUrl":"https://contoso-function-app-1098.chinacloudsites.cn/api/HttpTrigger1?****","apiVersion":"2021-10-01"}},"deviceRuntimeContext":{"registrationId":"breakroom499-contoso-tstrsd-007","currentIotHubHostName":"contoso-toasters-hub-1098.azure-devices.cn","currentDeviceId":"breakroom499-contoso-tstrsd-007","symmetricKey":{},"payload":{"MyDeviceFirmwareVersion":"12.0.2.5","MyDeviceProvisioningVersion":"1.0.0.0"}},"linkedHubs":["contoso-toasters-hub-1098.azure-devices.cn","contoso-heatpumps-hub-1098.azure-devices.cn"]} 2022-08-03T20:34:41.382 [Information] Response 2022-08-03T20:34:41.398 [Information] {"iotHubHostName":"contoso-toasters-hub-1098.azure-devices.cn","initialTwin":{"properties":{"desired":{"state":"ready","darknessSetting":"medium"}},"tags":{"deviceType":"toaster"}}} 2022-08-03T20:34:41.399 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=12950752-6d75-4f41-844b-c253a6653d4f, Duration=227ms)
模拟 Contoso 热泵设备
若要模拟热泵设备,请使用热泵注册 ID 和之前生成的派生设备密钥更新 prov_dev_client_sample.c 中的
prov_dev_set_symmetric_key_info()
调用。 下面显示的密钥值 6uejA9PfkQgmYylj8Zerp3kcbeVrGZ172YLa7VSnJzg= 也仅作为示例提供。// Set the symmetric key if using they auth type prov_dev_set_symmetric_key_info("mainbuilding167-contoso-hpsd-088", "6uejA9PfkQgmYylj8Zerp3kcbeVrGZ172YLa7VSnJzg=");
保存文件。
在 Visual Studio 菜单中,选择“调试”>“开始执行(不调试)”以运行该解决方案。 出现重新生成项目的提示时,请选择“是”,以便在运行项目之前重新生成项目 。
以下输出是模拟热泵设备成功启动并连接到预配服务实例以通过自定义分配策略分配到 Contoso 热泵 IoT 中心的一个示例:
Provisioning API Version: 1.8.0 Registering Device Provisioning Status: PROV_DEVICE_REG_STATUS_CONNECTED Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Registration Information received from service: contoso-heatpumps-hub-1098.azure-devices.cn, deviceId: mainbuilding167-contoso-hpsd-088 Press enter key to exit:
对自定义分配策略进行故障排除
下表显示了预期场景以及可能遇到的结果错误代码。 使用此表来帮助你解决使用 Azure 函数时自定义分配策略失败的问题。
方案 | 预配服务的注册结果 | 预配 SDK 结果 |
---|---|---|
Webhook 返回“200 正常”,其中“iotHubHostName”设置为有效的 IoT 中心主机名 | 结果状态:已分配 | SDK 返回 PROV_DEVICE_RESULT_OK 和中心信息 |
Webhook 返回“200 正常”,响应中存在“iotHubHostName”,但设置为空字符串或 null | 结果状态:已失败 错误代码:CustomAllocationIotHubNotSpecified (400208) |
SDK 返回 PROV_DEVICE_RESULT_HUB_NOT_SPECIFIED |
Webhook 返回 401 未授权 | 结果状态:已失败 错误代码:CustomAllocationUnauthorizedAccess (400209) |
SDK 返回 PROV_DEVICE_RESULT_UNAUTHORIZED |
创建了个人注册,以禁用设备 | 结果状态:已禁用 | SDK 返回 PROV_DEVICE_RESULT_DISABLED |
Webhook 返回错误代码 >= 429 | DPS 的业务流程将会多次重试。 重试策略当前: - 重试计数:10 个 - 初始间隔:1 秒 - 增量:9 秒 |
SDK 将忽略错误并在指定时间提交另一个获取状态消息 |
Webhook 返回任何其他状态代码 | 结果状态:已失败 错误代码:CustomAllocationFailed (400207) |
SDK 返回 PROV_DEVICE_RESULT_DEV_AUTH_ERROR |
清理资源
如果打算继续使用本教程中创建的资源,则可以保留它们。 如果你不打算继续使用这些资源,请使用以下步骤删除本教程创建的所有资源,以避免不必要的费用。
此处的步骤假定你按照名为 contoso-us-resource-group 的同一资源组的指示创建了本教程中的所有资源。
重要
删除资源组的操作不可逆。 资源组以及包含在其中的所有资源将被永久删除。 请确保不要意外删除错误的资源组或资源。 如果在现有的包含要保留资源的资源组中创建了 IoT 中心,则只删除 IoT 中心资源本身,而不要删除资源组。
若要按名称删除资源组:
登录到 Azure 门户,然后选择“资源组”。
在“按名称筛选...”文本框中,键入包含资源的资源组名称“contoso-us-resource-group”。
在结果列表中的资源组右侧,选择“...”,然后选择“删除资源组” 。
系统会要求确认是否删除该资源组。 再次键入资源组的名称进行确认,然后选择“删除” 。 片刻之后,将会删除该资源组及其包含的所有资源。
后续步骤
若要了解有关自定义分配策略的详细信息,请参阅