设备孪生入门指南(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。 本文中的设备示例使用通过端口 8883 进行通信的 MQTT 协议。 某些企业和教育网络环境中可能会阻止此端口。 有关解决此问题的详细信息和方法,请参阅“连接到 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-deviceazure-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 中心连接字符串中复制的 IoT 中心连接字符串替换{iot hub connection string}

         '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();
                   }
                 });
             }
         });
    

    注册表对象公开了与服务中的设备孪生交互所需的所有方法。 前面的代码首先初始化 注册表 对象,然后检索 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 工厂的设备的设备孪生,第二个代码将优化查询以仅选择通过手机网络连接的设备。

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

  6. 使用以下命令运行应用程序:

        node AddTagsAndQuery.js
    

    应该会在查询结果中看到一个设备,询问 位于 Redmond43 中的所有设备,对于将结果限制为使用手机网络的设备的查询,不应看到任何设备。

    请查看查询结果中的这台设备

本文内容:

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

后续步骤

若要了解如何操作: