Skip to main content

使用SAS Key登记、注册和初始化设备

分类:  Azure物联网 标签:  #Azure #Azure IoT Device Provisioning Service # 发布于: 2023-06-14 20:21:08

从本节开始我们开始以代码的方式来给出实例,在操作之前,请参考文章:

使用Azure Cli创建和设置Azure DPS服务

创建Azure IoT Hub服务和DPS服务,并将Azure IoT Hub连接到DPS服务中。

创建好了资源之后,并且将iot hub连接到dps之后,我们开始使用Azure cli来创建单个设备登记,并设定使用SAS Key来登记设备。

请使用如下的命令创建单个设备登记:

az iot dps enrollment create -g my-sample-resource-group --dps-name my-sample-dps --enrollment-id my-first-enrollment-device --device-id my-first-dps-device --attestation-type symmetrickey

请记住这行命令里的几个重要的值:

  • registration idmy-first-enrollment-device
  • device idmy-first-dps-device

取回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 show --dps-name my-sample-dps -g my-sample-resource-group --enrollment-id my-first-enrollment-device --show-key

如下图:


请保存好我们如图所示的primary key。

创建应用

请注意我们使用.Net 6创建的代码,请使用下图所示的命令来创建我们的应用。

dotnet new console -o SymmetricKeySample
cd SymmetricKeySample
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 SymmetricKeySample.Parameters;
global using SymmetricKeySample.Samples;

作为全局包引用。

需要注意的是本实例使用包CommandLineParser来解析命令行,因此我们需要用一个辅助类来获取命令行的参数。

在项目中创建一个文件:EnrollmentType.cs, 用于定义登记的类型:

namespace SymmetricKeySample.Samples;

public enum EnrollmentType
{
    /// <summary>
    ///  Enrollment for a single device.
    /// </summary>
    Individual,

    /// <summary>
    /// Enrollment for a group of devices.
    /// </summary>
    Group,
}

创建文件:Parameters.cs, 该文件主要用于获取命令行参数

namespace SymmetricKeySample.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 ComputeDerivedSymmetricKeySample for how to generate the derived key.")]
    public string? PrimaryKey { get; set; }

    [Option(
        'e',
        "EnrollmentType",
        Default = EnrollmentType.Individual,
        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\SymmetricKeySample>dotnet run
SymmetricKeySample 1.0.0
Copyright (C) 2021 SymmetricKeySample

ERROR(S):
  Required option 's, IdScope' is missing.
  Required option 'i, Id' is missing.
  Required option 'p, PrimaryKey' 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 ComputeDerivedSymmetricKeySample for how to generate the
                                derived key.

  -e, --EnrollmentType          (Default: Individual) 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\SymmetricKeySample>

在项目目录下创建文件:ProvisioningDeviceClientSample.cs, 该文件内容如下:

namespace SymmetricKeySample.Samples;

public class ProvisioningDeviceClientSample
{
    private readonly OptionParameters _parameters;

    public ProvisioningDeviceClientSample(OptionParameters parameters)
    {
        _parameters = parameters;
    }

    public async Task RunSampleAsync()
    {
        Console.WriteLine($"初始化Azure IoT Hub DPS客户端...");

        // For individual enrollments, the first parameter must be the registration Id, where in the enrollment
        // the device Id is already chosen. However, for group enrollments the device Id can be requested by
        // the device, as long as the key has been computed using that value.
        // Also, the secondary could be included, but was left out for the simplicity of this sample.
        using var security = new SecurityProviderSymmetricKey(
            _parameters.Id,
            _parameters.PrimaryKey,
            null);

        using var transportHandler = GetTransportHandler();

        ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(
            _parameters.GlobalDeviceEndpoint,
            _parameters.IdScope,
            security,
            transportHandler);

        Console.WriteLine($"初始化DPS登记: 注册ID为: {security.GetRegistrationID()}.");

        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("完成测试退出.");
    }

    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>

注意这里需要的信息文章前面都已经有了,请在这里替换就好了。

运行结果如下:


检查Azure IoT Hub如下:


最后不要忘记了清理资源,使用如下的命令直接删除资源组:

az group delete --name my-sample-resource-group