你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

设备孪生入门 (Node.js)

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

注意

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

使用设备克隆可以:

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

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

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

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

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

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

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

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

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

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

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

设备孪生概念图的屏幕截图。

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

本文介绍如何:

  • 使用模拟设备应用将其连接通道报告为设备孪生上的报告的属性。

  • 使用标记上的筛选器和之前创建的属性通过后端应用查询设备。

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

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

  • TwinSimulatedDevice.js:一个模拟设备应用,用于连接到 IoT 中心并报告其连接状况。

备注

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

先决条件

若要完成本文,需要做好以下准备:

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

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

  • Node.js 版本 10.0.x 或更高版本。

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

获取 IoT 中心连接字符串

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

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

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

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

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

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

    显示如何添加新的共享访问策略的屏幕截图。

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

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

    显示如何检索连接字符串的屏幕截图。

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

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

在本部分中,将创建一个 Node.js 控制台应用作为 myDeviceId 连接到中心,然后更新其设备孪生的报告属性,以确认它使用手机网络进行连接。

  1. 新建名为 reportconnectivity 的空文件夹。 在 reportconnectivity 文件夹中,在命令提示符下使用以下命令创建新的 package.json 文件。 --yes 参数接受所有默认值。

    npm init --yes
    
  2. 在 reportconnectivity 文件夹中,在命令提示符下运行以下命令以安装 azure-iot-device 包和 azure-iot-device-mqtt 包 :

    npm install azure-iot-device azure-iot-device-mqtt --save
    
  3. 使用文本编辑器,在 reportconnectivity 文件夹中创建一个新的 ReportConnectivity.js 文件。

  4. 向 ReportConnectivity.js 文件添加以下代码。 将 {device connection string} 替换为在 IoT 中心注册设备时看到的设备连接字符串:

        'use strict';
        var Client = require('azure-iot-device').Client;
        var Protocol = require('azure-iot-device-mqtt').Mqtt;
    
        var connectionString = '{device connection string}';
        var client = Client.fromConnectionString(connectionString, Protocol);
    
        client.open(function(err) {
        if (err) {
            console.error('could not open IotHub client');
        }  else {
            console.log('client opened');
    
            client.getTwin(function(err, twin) {
            if (err) {
                console.error('could not get twin');
            } else {
                var patch = {
                    connectivity: {
                        type: 'cellular'
                    }
                };
    
                twin.properties.reported.update(patch, function(err) {
                    if (err) {
                        console.error('could not update twin');
                    } else {
                        console.log('twin state reported');
                        process.exit();
                    }
                });
            }
            });
        }
        });
    

    Client 对象公开从该设备与设备孪生交互所需的所有方法。 上面的代码在初始化 Client 对象后会检索 myDeviceId 的设备孪生,并使用连接信息更新其报告属性。

  5. 运行设备应用

        node ReportConnectivity.js
    

    应该看到消息 twin state reported

  6. 既然设备报告其连接的信息,该信息应显示在两个查询中。 转回到 addtagsandqueryapp 文件夹,并再次运行查询:

        node AddTagsAndQuery.js
    

    这一次 myDeviceId 应显示在两个查询结果中。

    在两个查询结果中显示 myDeviceId

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

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

  1. 新建名为 addtagsandqueryapp 的空文件夹。 在命令提示符下的addtagsandqueryapp 文件夹中,使用以下命令创建新的 package.json 文件。 --yes 参数接受所有默认值。

    npm init --yes
    
  2. addtagsandqueryapp 文件夹中,在命令提示符下运行以下命令以安装 azure-iothub 包:

    npm install azure-iothub --save
    
  3. 使用文本编辑器,在 addtagsandqueryapp 文件夹中创建一个新的 AddTagsAndQuery.js 文件。

  4. 将以下代码添加到 AddTagsAndQuery.js 文件。 将 {iot hub connection string} 替换为在获取 IoT 中心连接字符串中复制的 IoT 中心连接字符串。

         'use strict';
         var iothub = require('azure-iothub');
         var connectionString = '{iot hub connection string}';
         var registry = iothub.Registry.fromConnectionString(connectionString);
    
         registry.getTwin('myDeviceId', function(err, twin){
             if (err) {
                 console.error(err.constructor.name + ': ' + err.message);
             } else {
                 var patch = {
                     tags: {
                         location: {
                             region: 'US',
                             plant: 'Redmond43'
                       }
                     }
                 };
    
                 twin.update(patch, function(err) {
                   if (err) {
                     console.error('Could not update twin: ' + err.constructor.name + ': ' + err.message);
                   } else {
                     console.log(twin.deviceId + ' twin updated successfully');
                     queryTwins();
                   }
                 });
             }
         });
    

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

    更新标记后,它将调用 queryTwins 函数。

  5. 在 AddTagsAndQuery.js 末尾添加以下代码以实现 queryTwins 函数:

         var queryTwins = function() {
             var query = registry.createQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43'", 100);
             query.nextAsTwin(function(err, results) {
                 if (err) {
                     console.error('Failed to fetch the results: ' + err.message);
                 } else {
                     console.log("Devices in Redmond43: " + results.map(function(twin) {return twin.deviceId}).join(','));
                 }
             });
    
             query = registry.createQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43' AND properties.reported.connectivity.type = 'cellular'", 100);
             query.nextAsTwin(function(err, results) {
                 if (err) {
                     console.error('Failed to fetch the results: ' + err.message);
                 } else {
                     console.log("Devices in Redmond43 using cellular network: " + results.map(function(twin) {return twin.deviceId}).join(','));
                 }
             });
         };
    

    上面的代码执行两个查询:第一个仅选择位于 Redmond43 工厂的设备孪生,第二个将查询细化为仅选择还要通过蜂窝网络连接的设备。

    当代码创建 query 对象时,它在第二个参数中指定返回的最大文档数。 query 对象包含 hasMoreResults 布尔值属性,可以使用它多次调用 nextAsTwin 方法来检索所有结果。 名为 next 的方法可用于非设备孪生的结果(例如聚合查询的结果)。

  6. 使用以下方法运行应用程序:

        node AddTagsAndQuery.js
    

    在查询位于 Redmond43 的所有设备的查询结果中,应该会看到一个设备,而在将结果限制为使用蜂窝网络的设备的查询结果中没有任何设备。

    在查询结果中看到一个设备

本文内容:

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

后续步骤

若要了解操作方法: