设备孪生入门 (Node.js)

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

备注

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

使用设备克隆可以:

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

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

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

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

设备孪生旨在执行同步以及查询设备的配置和条件。 了解设备孪生中提供了有关何时使用设备孪生的详细信息。

设备孪生存储在 IoT 中心内,并包含以下元素:

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

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

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

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

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

显示功能的设备孪生图像

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

本教程演示如何:

  • 创建将标记添加到设备孪生的后端应用,以及将其连接通道作为设备孪生上的报告属性进行报告的模拟设备应用。

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

在本教程结束时,你将拥有两个 Node.js 控制台应用:

  • AddTagsAndQuery.js(Node.js 后端应用),用于添加标记和查询设备孪生。

  • TwinSimulatedDevice.js(Node.js 应用),用于模拟使用早先创建的设备标识连接到 IoT 中心的设备,并报告其连接状况。

备注

Azure IoT SDK 一文介绍了可用于构建设备和后端应用的 Azure IoT SDK。

先决条件

要完成本教程,需要:

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

  • 有效的 Azure 帐户。 (如果没有帐户,只需几分钟即可创建一个免费帐户。)

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

创建 IoT 中心

此部分介绍如何使用 Azure 门户创建 IoT 中心。

  1. 登录 Azure 门户

  2. 从 Azure 主页中选择“+ 创建资源”按钮,然后在“搜索市场”字段中输入“IoT 中心”。

  3. 在搜索结果中选择“IoT 中心”,然后选择“创建” 。

  4. 在“基本信息”选项卡上,按如下所示填写字段:

    • 订阅:选择要用于中心的订阅。

    • 资源组:选择一个资源组或新建一个资源组。 若要新建资源组,请选择“新建”并填写要使用的名称。 若要使用现有的资源组,请选择它。 有关详细信息,请参阅管理 Azure 资源管理器资源组

    • 区域:选择中心所在的区域。 选择最靠近你的位置。

    • IoT 中心名称:输入中心的名称。 该名称必须全局唯一。 如果输入的名称可用,会显示一个绿色复选标记。

    重要

    IoT 中心将公开为 DNS 终结点,因此,命名时请务必避免包含任何敏感信息。

    在 Azure 门户中创建中心

  5. 在完成时选择“下一步:大小和规模”,以继续创建中心。

    使用 Azure 门户为新的中心设置大小和规模

    可在此处接受默认设置。 如果需要,可以修改以下任何字段:

    • 定价和缩放层:选择的层。 可以根据你需要的功能数以及每天通过解决方案发送的消息数从多个层级中进行选择。 免费层适用于测试和评估。 允许 500 台设备连接到中心,每天最多可传输 8,000 条消息。 每个 Azure 订阅可以在免费层中创建一个 IoT 中心。

      如果正在完成 IoT 中心设备流的快速入门,请选择免费层。

    • IoT 中心单元:每日每单位允许的消息数取决于中心的定价层。 例如,如果希望中心支持 700,000 条消息引入,请选择两个 S1 层单位。 有关其他层选项的详细信息,请参阅选择合适的 IoT 中心层

    • 高级设置 > 设备到云的分区:此属性将设备到云消息与这些消息的同步读取器数目相关联。 大多数中心只需要 4 个分区。

  6. 在完成时选择“下一步:标记”继续到下一屏幕。

    标记是名称/值对。 可以为多个资源和资源组分配相同的标记,以便对资源进行分类并合并计费。 有关详细信息,请参阅使用标记来组织 Azure 资源

使用 Azure 门户为新的中心设置大小和规模

  1. 在完成时选择“下一步:查看+创建”可查看选择。 你会看到类似于此屏幕的内容,但其中包含创建中心时选择的值。

查看用于创建新中心的信息

  1. 选择“创建”以创建新的中心。 创建中心需要几分钟时间。

在 IoT 中心内注册新设备

在本部分中,将使用 Azure CLI 为本文创建设备标识。 设备 ID 区分大小写。

  1. 运行以下命令以安装适用于 Azure CLI 的 Microsoft Azure IoT 扩展:

    az extension add --name azure-iot
    
  2. 使用以下命令创建一个名为 myDeviceId 的新设备标识并检索设备连接字符串:

    az iot hub device-identity create --device-id myDeviceId --hub-name {Your IoT Hub name}
    az iot hub device-identity show-connection-string --device-id myDeviceId --hub-name {Your IoT Hub name} -o table
    

    重要

    收集的日志中可能会显示设备 ID 用于客户支持和故障排除,因此,在为日志命名时,请务必避免包含任何敏感信息。

记下结果中的设备连接字符串。 设备应用使用此设备连接字符串以设备身份连接到 IoT 中心。

获取 IoT 中心连接字符串

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

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

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

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

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

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

    演示如何添加新的共享访问策略

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

  6. 在“共享访问密钥”下,选择“连接字符串 - 主密钥”的复制图标并保存值。

    显示如何检索连接字符串

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

创建服务应用

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

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

在下一部分中,创建的设备应用会报告连接信息,并更改上一部分中查询的结果。

创建设备应用

在此部分,会创建一个 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 中心注册新设备中创建 myDeviceId 设备标识时复制的设备连接字符串。

        '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

后续步骤

本教程中,在 Azure 门户中配置了新的 IoT 中心,并在 IoT 中心的标识注册表中创建了设备标识。 已从后端应用以标记形式添加了设备元数据,并编写了模拟的设备应用,用于报告设备孪生中的设备连接信息。 还学习了如何使用类似 SQL 的 IoT 中心查询语言来查询此信息。

充分利用以下资源: