使用DPS enrollment Group注册大量的设备
分类: Azure物联网 ◆ 标签: #Azure #Azure IoT Device Provisioning Service # ◆ 发布于: 2023-06-14 20:24:55

我们上一篇文章学习了如何使用SAS Key
进行单个设备的登记注册,我们本篇使用enrollment group
来注册大量的设备。
在操作之前,请参考文章:<>, 创建Azure IoT Hub
服务和DPS
服务,并将Azure IoT Hub
连接到DPS
服务中。
创建好了资源之后,并且将iot hub
连接到dps
之后,我们开始使用Azure cli
来创建单个设备登记,并设定使用SAS Key
来登记设备。
请使用如下的命令创建分组设备登记:
az iot dps enrollment-group create -g my-sample-resource-group --dps-name my-sample-dps --enrollment-id my-first-enrollment-group
取回DPS
服务的idScope
:
az iot dps show --name my-sample-dps -g my-sample-resource-group | jq .properties.idScope
请注意这里需要安装工具jq, 请参考网站:https://stedolan.github.io/jq/
使用如下的取回SAS Key
az iot dps enrollment-group show --dps-name my-sample-dps -g my-sample-resource-group --enrollment-id my-first-enrollment-group --show-key
如下图:
请保存好我们如图所示的primary key。
重要提示
在分组登记中,如果使用SAS Key来注册设备,那么需要注意设备的Key该如何计算:设备的key是通过取回分组的key,然后使用算法HMACSHA256来Hash
得到设备的key,
如下所示://首先需要将key 解密 string originalPrimaryKey = _parameters.PrimaryKey!; byte[] decodeKey = Convert.FromBase64String(originalPrimaryKey); using HMACSHA256 hmac = new HMACSHA256(decodeKey); var deviceId = devicePrefix + "sn" + (i + 1); byte[] device_sign1 = hmac.ComputeHash(Encoding.ASCII.GetBytes(deviceId)); string deviceKey = Convert.ToBase64String(device_sign1); Console.WriteLine($"Device id is {deviceId}"); Console.WriteLine($"Device Key is {deviceKey}"); using var security = new SecurityProviderSymmetricKey( deviceId, deviceKey, null);
创建应用
请注意我们使用.Net 6
创建的代码,请使用下图所示的命令来创建我们的应用。
dotnet new console -o SymmetricKeyGroupSample
cd SymmetricKeyGroupSample
dotnet add package CommandLineParser
dotnet add package Microsoft.Azure.Devices.Client
dotnet add package Microsoft.Azure.Devices.Provisioning.Client
dotnet add package Microsoft.Azure.Devices.Provisioning.Transport.Amqp
dotnet add package Microsoft.Azure.Devices.Provisioning.Transport.Mqtt
dotnet add package Microsoft.Azure.Devices.Provisioning.Transport.Http
code . //请安装 VS Code
使用Vs Code
打开项目之后,在根目录下添加文件GlobalUsing.cs
, 添加如下的内容:
global using Microsoft.Azure.Devices.Client; global using Microsoft.Azure.Devices.Provisioning.Client.Transport; global using Microsoft.Azure.Devices.Provisioning.Client; global using Microsoft.Azure.Devices.Shared; global using System.Text; global using CommandLine; global using System.Security.Cryptography; global using SymmetricKeyGroupSample.Parameters; global using SymmetricKeyGroupSample.Samples;
作为全局包引用。
需要注意的是本实例使用包CommandLineParser
来解析命令行,因此我们需要应一个辅助类来获取命令行的参数。
在项目中创建一个文件:EnrollmentType.cs
, 用于定义登记的类型:
namespace SymmetricKeyGroupSample.Samples; public enum EnrollmentType { /// <summary> /// Enrollment for a single device. /// </summary> Individual, /// <summary> /// Enrollment for a group of devices. /// </summary> Group, }
创建文件:Parameters.cs
, 该文件主要用于获取命令行参数
namespace SymmetricKeyGroupSample.Parameters; public class OptionParameters { [Option( 's', "IdScope", Required = true, HelpText = "The Id Scope of the DPS instance")] public string? IdScope { get; set; } [Option( 'i', "Id", Required = true, HelpText = "The registration Id when using individual enrollment, or the desired device Id when using group enrollment.")] public string? Id { get; set; } [Option( 'p', "PrimaryKey", Required = true, HelpText = "The primary key of the individual enrollment or the derived primary key of the group enrollment. See the ComputeDerivedSymmetricKeyGroupSample for how to generate the derived key.")] public string? PrimaryKey { get; set; } [Option( 'f', "DevicePrefix", Required = true, HelpText = "The Device Prefix for all Device" )] public string? DevicePrefix {get; set;} [Option( 'n', "number", Required = true, HelpText = "How Many device you want to auto-matic generate" )] public int number {get; set;} [Option( 'e', "EnrollmentType", Default = EnrollmentType.Group, HelpText = "The type of enrollment: Individual or Group")] public EnrollmentType EnrollmentType { get; set; } [Option( 'g', "GlobalDeviceEndpoint", Default = "global.azure-devices-provisioning.cn", HelpText = "The global endpoint for devices to connect to.")] public string? GlobalDeviceEndpoint { get; set; } [Option( 't', "TransportType", Default = TransportType.Mqtt, HelpText = "The transport to use to communicate with the device provisioning instance. Possible values include Mqtt, Mqtt_WebSocket_Only, Mqtt_Tcp_Only, Amqp, Amqp_WebSocket_Only, Amqp_Tcp_only, and Http1.")] public TransportType TransportType { get; set; } }
请参考上述的类定义,我们可以使用如下的参数说明:
D:\MyProjects\azure-demo\IoT\SymmetricKeyGroupSample>dotnet run
有可用的工作负载更新。有关详细信息,请运行“dotnet 工作负载列表”。
SymmetricKeyGroupSample 1.0.0
Copyright (C) 2021 SymmetricKeyGroupSample
ERROR(S):
Required option 's, IdScope' is missing.
Required option 'i, Id' is missing.
Required option 'p, PrimaryKey' is missing.
Required option 'f, DevicePrefix' is missing.
Required option 'n, number' is missing.
-s, --IdScope Required. The Id Scope of the DPS instance
-i, --Id Required. The registration Id when using individual enrollment, or the desired device Id when using group enrollment.
-p, --PrimaryKey Required. The primary key of the individual enrollment or the derived primary key of the group enrollment. See the ComputeDerivedSymmetricKeyGroupSample for how to generate the
derived key.
-f, --DevicePrefix Required. The Device Prefix for all Device
-n, --number Required. How Many device you want to auto-matic generate
-e, --EnrollmentType (Default: Group) The type of enrollment: Individual or Group
-g, --GlobalDeviceEndpoint (Default: global.azure-devices-provisioning.cn) The global endpoint for devices to
connect to.
-t, --TransportType (Default: Mqtt) The transport to use to communicate with the device provisioning
instance. Possible values include Mqtt, Mqtt_WebSocket_Only, Mqtt_Tcp_Only, Amqp,
Amqp_WebSocket_Only, Amqp_Tcp_only, and Http1.
--help Display this help screen.
--version Display version information.
D:\MyProjects\azure-demo\IoT\SymmetricKeyGroupSample>
在项目目录下创建文件:ProvisioningDeviceClientSample.cs
, 该文件内容如下:
namespace SymmetricKeyGroupSample.Samples; public class ProvisioningDeviceClientSample { private readonly OptionParameters _parameters; public ProvisioningDeviceClientSample(OptionParameters parameters) { _parameters = parameters; } public async Task RunSampleAsync() { Console.WriteLine($"初始化Azure IoT Hub DPS客户端..."); string devicePrefix = _parameters.DevicePrefix!; int deviceNumber = _parameters.number; for (int i = 0; i <= deviceNumber; i++) { //首先需要将key 解密 string originalPrimaryKey = _parameters.PrimaryKey!; byte[] decodeKey = Convert.FromBase64String(originalPrimaryKey); using HMACSHA256 hmac = new HMACSHA256(decodeKey); var deviceId = devicePrefix + "sn" + (i + 1); byte[] device_sign1 = hmac.ComputeHash(Encoding.ASCII.GetBytes(deviceId)); string deviceKey = Convert.ToBase64String(device_sign1); Console.WriteLine($"Device id is {deviceId}"); Console.WriteLine($"Device Key is {deviceKey}"); using var security = new SecurityProviderSymmetricKey( deviceId, deviceKey, null); using var transportHandler = GetTransportHandler(); ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create( _parameters.GlobalDeviceEndpoint, _parameters.IdScope, security, transportHandler); Console.WriteLine($"初始化DPS登记: 注册ID为: {security.GetRegistrationID()}."); Console.WriteLine($"当前登记第{i + 1}个设备..."); Console.WriteLine("通过DPS服务进行注册..."); DeviceRegistrationResult result = await provClient.RegisterAsync(); Console.WriteLine($"注册状态: {result.Status}."); if (result.Status != ProvisioningRegistrationStatusType.Assigned) { Console.WriteLine($"未能分配合适的Azure IoT Hub."); return; } Console.WriteLine($"设备ID: {result.DeviceId} 成功注册到IoT Hub: {result.AssignedHub}."); Console.WriteLine("创建IoT Hub的SAS Key认证..."); IAuthenticationMethod auth = new DeviceAuthenticationWithRegistrySymmetricKey( result.DeviceId, security.GetPrimaryKey()); Console.WriteLine($"测试连接Azure IoT Hub..."); using DeviceClient iotClient = DeviceClient.Create(result.AssignedHub, auth, _parameters.TransportType); Console.WriteLine("发送测试消息..."); using var message = new Message(Encoding.UTF8.GetBytes("TestMessage")); await iotClient.SendEventAsync(message); Console.WriteLine("完成第{i+1}个设备注册和测试."); } } private ProvisioningTransportHandler GetTransportHandler() { return _parameters.TransportType switch { TransportType.Mqtt => new ProvisioningTransportHandlerMqtt(), TransportType.Mqtt_Tcp_Only => new ProvisioningTransportHandlerMqtt(TransportFallbackType.TcpOnly), TransportType.Mqtt_WebSocket_Only => new ProvisioningTransportHandlerMqtt(TransportFallbackType.WebSocketOnly), TransportType.Amqp => new ProvisioningTransportHandlerAmqp(), TransportType.Amqp_Tcp_Only => new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly), TransportType.Amqp_WebSocket_Only => new ProvisioningTransportHandlerAmqp(TransportFallbackType.WebSocketOnly), TransportType.Http1 => new ProvisioningTransportHandlerHttp(), _ => throw new NotSupportedException($"不支持的网络协议类型 {_parameters.TransportType}"), }; } }
最后更改Program.cs
文件内容如下:
OptionParameters parameters = null!; ParserResult<OptionParameters> result = Parser.Default.ParseArguments<OptionParameters>(args) .WithParsed(parsedParams => { parameters = parsedParams; }) .WithNotParsed(errors => { Environment.Exit(1); }); var sample = new ProvisioningDeviceClientSample(parameters); await sample.RunSampleAsync(); return 0;
至此该实例的所有代码都准备好了,您可以通过如下的命令来运行该实例:
dotnet run --s <id-scope> --i <registration-id> --p <primarykey> --f my-enrollment-group-device-demo --n 3
注意这里需要的信息文章前面都已经有了,请在这里替换就好了。
运行结果如下:
检查Azure IoT Hub
如下:
最后不要忘记了清理资源,使用如下的命令直接删除资源组:
az group delete --name my-sample-resource-group