设备孪生入门 (.NET)

设备孪生是存储设备状态信息(包括元数据、配置和条件)的 JSON 文档。 IoT 中心为连接到它的每台设备保留一个设备孪生。

注意

本文所述的功能只能用于 IoT 中心的标准层。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层

使用设备克隆可以:

  • 存储来自解决方案后端的设备元数据。

  • 通过设备应用报告当前状态信息,例如可用功能和条件(例如,使用的连接方法)。

  • 同步设备应用和后端应用之间长时间运行的工作流(例如固件和配置更新)的状态。

  • 查询设备的元数据、配置或状态。

设备孪生旨在执行同步以及查询设备的配置和条件。 有关设备孪生的详细信息(包括何时使用设备孪生),请参阅了解设备孪生

IoT 中心存储包含以下元素的设备孪生:

  • 标记。 只能由解决方案后端访问的设备元数据。

  • 所需属性。 可以由解决方案后端修改以及由设备应用观察的 JSON 对象。

  • 报告属性。 可以由设备应用修改以及由解决方案后端读取的 JSON 对象。

标记和属性不能包含数组,但可以包含嵌套对象。

下图显示了设备孪生组织:

Screenshot of a device twin concept diagram.

此外,解决方案后端可以根据上述所有数据查询设备孪生。 有关设备孪生的详细信息,请参阅了解设备孪生。 有关查询的详细信息,请参阅 IoT 中心查询语言

在本文中,你将创建两个 .NET 控制台应用:

  • AddTagsAndQuery:一个后端应用,用于添加标记并查询设备孪生。

  • ReportConnectivity:一个模拟设备应用,它连接到 IoT 中心,并报告其连接状态。

注意

有关可用于生成设备和后端应用的 SDK 工具的详细信息,请参阅 Azure IoT SDK

先决条件

  • Visual Studio。

  • IoT 中心。 使用 CLIAzure 门户创建一个。

  • 已注册的设备。 在 Azure 门户中注册一个。

  • 确保已在防火墙中打开端口 8883。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)

获取 IoT 中心连接字符串

在本文中,你将创建一项后端服务,该服务将所需的属性添加到设备孪生,然后查询标识注册表,从而查找具有已相应更新的报告属性的所有设备。 服务需要“服务连接”权限才能修改设备孪生的所需属性,并且需要“注册表读取”权限才能查询标识注册表。 没有仅包含这两个权限的默认共享访问策略,因此需要创建一个。

若要创建授予“服务连接”和“注册表读取”权限的共享访问策略并获取此策略的连接字符串,请执行以下步骤:

  1. Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在中心的左侧窗格上,选择“共享访问策略”。

  3. 在策略列表上方的顶部菜单中,选择“添加共享策略访问策略”。

  4. 在右侧的“添加共享访问策略”窗格中,为策略输入一个描述性名称,例如 serviceAndRegistryRead。 在“权限”下,选择“注册表读取”和“服务连接”,然后选择“添加”。

    Screen capture that shows how to add a new shared access policy.

  5. 从策略列表中选择新策略。

  6. 选择“主连接字符串”的复制图标并保存值。

    Screen capture that shows how to retrieve the connection string.

有关 IoT 中心共享访问策略和权限的详细信息,请参阅访问控制和权限

创建更新报告的属性的设备应用

在本部分中,将创建一个 .NET 控制台应用,该应用以你的 myDeviceId 身份连接到中心,然后更新其报告属性,确认它是使用手机网络进行连接的。

  1. 打开 Visual Studio,选择“新建项目”。

  2. 选择“控制台应用(.NET Framework)”,然后选择“下一步”。

  3. 在“配置新项目”中,将项目命名为 ReportConnectivity,然后选择“下一步”。

  4. 在“解决方案资源管理器”中,右键单击“ReportConnectivity”项目,然后选择“管理 NuGet 程序包” 。

  5. 保留默认的 .NET Framework,然后选择“创建”以创建项目。

  6. 选择“浏览”,然后搜索并选择“Microsoft.Azure.Devices.Client”。 选择“安装”。

    此步骤将下载、安装 Azure IoT 设备 SDK NuGet 包及其依赖项并添加对其的引用。

  7. 在 Program.cs 文件顶部添加以下 using 语句:

    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.Devices.Shared;
    using Newtonsoft.Json;
    
  8. 将以下字段添加到 Program 类。 将 {device connection string} 替换为在 IoT 中心注册设备时看到的设备连接字符串:

    static string DeviceConnectionString = "HostName=<yourIotHubName>.azure-devices.net;DeviceId=<yourIotDeviceName>;SharedAccessKey=<yourIotDeviceAccessKey>";
    static DeviceClient Client = null;
    
  9. 将以下方法添加到 Program 类:

    public static async void InitClient()
    {
        try
        {
            Console.WriteLine("Connecting to hub");
            Client = DeviceClient.CreateFromConnectionString(DeviceConnectionString, 
              TransportType.Mqtt);
            Console.WriteLine("Retrieving twin");
            await Client.GetTwinAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
        }
    }
    

    Client 对象公开从该设备与设备孪生交互所需的所有方法。 代码如上所示,初始化 Client 对象,然后检索 myDeviceId 的设备孪生 。

  10. 将以下方法添加到 Program 类:

    public static async void ReportConnectivity()
    {
        try
        {
            Console.WriteLine("Sending connectivity data as reported property");
    
            TwinCollection reportedProperties, connectivity;
            reportedProperties = new TwinCollection();
            connectivity = new TwinCollection();
            connectivity["type"] = "cellular";
            reportedProperties["connectivity"] = connectivity;
            await Client.UpdateReportedPropertiesAsync(reportedProperties);
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
        }
    }
    

    上面的代码使用连接信息更新了 myDeviceId 的报告属性。

  11. 最后,在 Main 方法中添加以下行:

    try
    {
        InitClient();
        ReportConnectivity();
    }
    catch (Exception ex)
    {
        Console.WriteLine();
        Console.WriteLine("Error in sample: {0}", ex.Message);
    }
    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
    
  12. 在解决方案资源管理器中,右键单击解决方案并选择“设置启动项目”。

  13. 在“通用属性”>“启动项目”中,选择“多启动项目”。 对于“ReportConnectivity”,选择“启动”作为“操作”。 选择“确定”保存更改。

  14. 右键单击 ReportConnectivity 项目并选择“调试”,然后选择“启动新实例”来运行此应用 。 应会看到应用将获取孪生信息,然后将连接信息作为报告属性发送。

    Run device app to report connectivity

    设备报告了其连接信息之后,该信息应显示在两个查询中。

  15. 右键单击“AddTagsAndQuery”项目,然后选择“调试”>“启动新实例”以再次运行查询。 这一次 myDeviceId 应显示在两个查询结果中。

    Device connectivity reported successfully

创建更新所需属性和查询孪生的服务应用

在本部分中,将创建一个 .NET 控制台应用(使用 C#),该应用将位置元数据添加到与 myDeviceId 关联的设备孪生。 该应用在 IoT 中心查询位于美国的设备,然后查询报告已建立移动电话网络连接的设备。

  1. 在 Visual Studio 中,选择“文件”>“新建”>“项目”。 在“创建新项目”中,选择“控制台应用(.NET Framework)”,然后选择“下一步” 。

  2. 在“配置新项目”中,将项目命名为 AddTagsAndQuery,然后选择“下一步”。

    Screenshot of how to create a new Visual Studio project.

  3. 接受.NET Framework 的默认版本,然后选择“创建”以创建项目。

  4. 在“解决方案资源管理器”中,右键单击“AddTagsAndQuery”项目,然后选择“管理 NuGet 程序包”。

  5. 选择“浏览”,然后搜索并选择“Microsoft.Azure.Devices”。 选择“安装” 。

    NuGet Package Manager window

    此步骤将下载、安装 Azure IoT 服务 SDK NuGet 包及其依赖项并添加对其的引用。

  6. 在 Program.cs 文件顶部添加以下 using 语句:

    using Microsoft.Azure.Devices;
    
  7. 将以下字段添加到 Program 类。 将 {iot hub connection string} 替换为在获取 IoT 中心连接字符串中复制的 IoT 中心连接字符串。

    static RegistryManager registryManager;
    static string connectionString = "{iot hub connection string}";
    
  8. 将以下方法添加到 Program 类:

    public static async Task AddTagsAndQuery()
    {
        var twin = await registryManager.GetTwinAsync("myDeviceId");
        var patch =
            @"{
                tags: {
                    location: {
                        region: 'US',
                        plant: 'Redmond43'
                    }
                }
            }";
        await registryManager.UpdateTwinAsync(twin.DeviceId, patch, twin.ETag);
    
        var query = registryManager.CreateQuery(
          "SELECT * FROM devices WHERE tags.location.plant = 'Redmond43'", 100);
        var twinsInRedmond43 = await query.GetNextAsTwinAsync();
        Console.WriteLine("Devices in Redmond43: {0}", 
          string.Join(", ", twinsInRedmond43.Select(t => t.DeviceId)));
    
        query = registryManager.CreateQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43' AND properties.reported.connectivity.type = 'cellular'", 100);
        var twinsInRedmond43UsingCellular = await query.GetNextAsTwinAsync();
        Console.WriteLine("Devices in Redmond43 using cellular network: {0}", 
          string.Join(", ", twinsInRedmond43UsingCellular.Select(t => t.DeviceId)));
    }
    

    RegistryManager 类公开从该服务与设备孪生交互所需的所有方法。 上面的代码首先初始化 registryManager 对象,并检索 myDeviceId 的设备孪生,最后使用所需位置信息更新其标记。

    在更新后,它将执行两个查询:第一个仅选择位于 Redmond43 工厂的设备的设备孪生,第二个将查询细化为仅选择还要通过移动电话网络连接的设备。

    上面的代码创建 query 对象时,会指定返回的最大文档数。 query 对象包含 HasMoreResults 布尔值属性,可以使用它多次调用 GetNextAsTwinAsync 方法来检索所有结果。 名为 GetNextAsJson 的方法可用于非设备孪生的结果(例如聚合查询的结果)。

  9. 最后,在 Main 方法中添加以下行:

    registryManager = RegistryManager.CreateFromConnectionString(connectionString);
    AddTagsAndQuery().Wait();
    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
    
  10. 右键单击 AddTagsAndQuery 项目并选择“调试”,选择“启动新实例”来运行此应用程序。 在查询位于 Redmond43 的所有设备的查询结果中,应该会看到一个设备,而在将结果限制为使用蜂窝网络的设备的查询结果中没有任何设备。

    Query results in window

本文内容:

  • 从后端应用添加了设备元数据作为标记
  • 在设备孪生中报告了设备连接信息
  • 使用类似 SQL 的 IoT 中心查询语言查询了设备孪生信息

后续步骤

若要了解操作方法: