设备孪生入门 (Node.js)

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

注意

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

使用设备克隆可以:

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

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

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

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

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

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

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

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

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

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

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

Screenshot of a device twin concept diagram.

此外,解决方案后端可以根据上述所有数据查询设备孪生。 有关设备孪生的详细信息,请参阅了解设备孪生。 有关查询的详细信息,请参阅 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。 在“权限”下,选择“注册表读取”和“服务连接”,然后选择“添加”。

    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 中心共享访问策略和权限的详细信息,请参阅访问控制和权限

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

在本部分中,将创建一个 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 应显示在两个查询结果中。

    Show myDeviceId in both query results

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

在本部分中,将创建一个 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 的所有设备的查询结果中,应该会看到一个设备,而在将结果限制为使用蜂窝网络的设备的查询结果中没有任何设备。

    See the one device in the query results

本文内容:

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

后续步骤

若要了解操作方法: