设备孪生入门 (Node.js)
设备孪生是存储设备状态信息(包括元数据、配置和条件)的 JSON 文档。 IoT 中心为连接到它的每台设备保留一个设备孪生。
注意
本文所述的功能只能用于 IoT 中心的标准层。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层。
使用设备克隆可以:
存储来自解决方案后端的设备元数据。
通过设备应用报告当前状态信息,例如可用功能和条件(例如,使用的连接方法)。
同步设备应用和后端应用之间长时间运行的工作流(例如固件和配置更新)的状态。
查询设备的元数据、配置或状态。
设备孪生旨在执行同步以及查询设备的配置和条件。 有关设备孪生的详细信息(包括何时使用设备孪生),请参阅了解设备孪生。
IoT 中心存储包含以下元素的设备孪生:
标记。 只能由解决方案后端访问的设备元数据。
所需属性。 可以由解决方案后端修改以及由设备应用观察的 JSON 对象。
报告属性。 可以由设备应用修改以及由解决方案后端读取的 JSON 对象。
标记和属性不能包含数组,但可以包含嵌套对象。
下图显示了设备孪生组织:
此外,解决方案后端可以根据上述所有数据查询设备孪生。 有关设备孪生的详细信息,请参阅了解设备孪生。 有关查询的详细信息,请参阅 IoT 中心查询语言。
在本文中,将创建两个 Node.js 控制台应用:
AddTagsAndQuery.js:一个后端应用,用于添加标记并查询设备孪生。
TwinSimulatedDevice.js:一个模拟设备应用,用于连接到 IoT 中心并报告其连接状况。
备注
有关可用于生成设备和后端应用的 SDK 工具的详细信息,请参阅 Azure IoT SDK。
先决条件
若要完成本文,需要做好以下准备:
已注册的设备。 在 Azure 门户中注册一个。
Node.js 版本 10.0.x 或更高版本。
确保已在防火墙中打开端口 8883。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)。
获取 IoT 中心连接字符串
在本文中,你将创建一项后端服务,该服务将所需的属性添加到设备孪生,然后查询标识注册表,从而查找具有已相应更新的报告属性的所有设备。 服务需要“服务连接”权限才能修改设备孪生的所需属性,并且需要“注册表读取”权限才能查询标识注册表。 没有仅包含这两个权限的默认共享访问策略,因此需要创建一个。
若要创建授予“服务连接”和“注册表读取”权限的共享访问策略并获取此策略的连接字符串,请执行以下步骤:
在 Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。
在中心的左侧窗格上,选择“共享访问策略”。
在策略列表上方的顶部菜单中,选择“添加共享策略访问策略”。
在右侧的“添加共享访问策略”窗格中,为策略输入一个描述性名称,例如 serviceAndRegistryRead。 在“权限”下,选择“注册表读取”和“服务连接”,然后选择“添加”。
从策略列表中选择新策略。
选择“主连接字符串”的复制图标并保存值。
有关 IoT 中心共享访问策略和权限的详细信息,请参阅访问控制和权限。
创建更新报告属性的设备应用
在本部分中,将创建一个 Node.js 控制台应用作为 myDeviceId 连接到中心,然后更新其设备孪生的报告属性,以确认它使用手机网络进行连接。
新建名为 reportconnectivity 的空文件夹。 在 reportconnectivity 文件夹中,在命令提示符下使用以下命令创建新的 package.json 文件。
--yes
参数接受所有默认值。npm init --yes
在 reportconnectivity 文件夹中,在命令提示符下运行以下命令以安装 azure-iot-device 包和 azure-iot-device-mqtt 包 :
npm install azure-iot-device azure-iot-device-mqtt --save
使用文本编辑器,在 reportconnectivity 文件夹中创建一个新的 ReportConnectivity.js 文件。
向 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 的设备孪生,并使用连接信息更新其报告属性。
运行设备应用
node ReportConnectivity.js
应该看到消息
twin state reported
。既然设备报告其连接的信息,该信息应显示在两个查询中。 转回到 addtagsandqueryapp 文件夹,并再次运行查询:
node AddTagsAndQuery.js
这一次 myDeviceId 应显示在两个查询结果中。
创建更新所需属性和查询孪生的服务应用
在本部分中,将创建一个 Node.js 控制台应用,该应用将位置元数据添加到与 myDeviceId 关联的设备孪生。 该应用在 IoT 中心查询位于美国的设备,然后查询报告已建立移动电话网络连接的设备。
新建名为 addtagsandqueryapp 的空文件夹。 在命令提示符下的addtagsandqueryapp 文件夹中,使用以下命令创建新的 package.json 文件。
--yes
参数接受所有默认值。npm init --yes
在 addtagsandqueryapp 文件夹中,在命令提示符下运行以下命令以安装 azure-iothub 包:
npm install azure-iothub --save
使用文本编辑器,在 addtagsandqueryapp 文件夹中创建一个新的 AddTagsAndQuery.js 文件。
将以下代码添加到 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 函数。
在 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 的方法可用于非设备孪生的结果(例如聚合查询的结果)。
使用以下方法运行应用程序:
node AddTagsAndQuery.js
在查询位于 Redmond43 的所有设备的查询结果中,应该会看到一个设备,而在将结果限制为使用蜂窝网络的设备的查询结果中没有任何设备。
本文内容:
- 从后端应用添加了设备元数据作为标记
- 在设备孪生中报告了设备连接信息
- 使用类似 SQL 的 IoT 中心查询语言查询了设备孪生信息
后续步骤
若要了解操作方法:
若要了解如何从设备发送遥测数据,请参阅快速入门:将遥测数据从 IoT 即插即用设备发送到 Azure IoT 中心
若要了解如何使用设备孪生的所需属性配置设备,请参阅教程:从后端服务配置设备
若要了解如何以交互方式控制设备(例如从用户控制的应用打开风扇),请参阅快速入门:控制连接到 IoT 中心的设备