你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
在 IoT 中心内了解并使用模块孪生
在 IoT 中心的每个设备标识下,最多可以创建 50 个模块标识。 每个模块标识隐式生成模块孪生。 模块孪生与设备孪生类似,是存储模块状态信息(例如元数据、配置和条件)的 JSON 文档。 Azure IoT 中心为连接到 IoT 中心的每个模块保留一个模块孪生。
本文假设读者事先已阅读了解并在 IoT 中心内使用设备孪生。
在设备端,可以使用 IoT 中心设备软件开发工具包 (SDK) 创建模块,其中每个模块都与 IoT 中心单独建立连接。 通过此功能,可对设备上的不同组件使用不同的命名空间。 例如,某个自动贩卖机包含三个不同的传感器。 公司中的不同部门控制每个传感器。 可为每个传感器创建一个模块,以便部门只能将作业或直接方法发送到他们控制的传感器,从而避免冲突和用户错误。
模块标识和模块孪生提供的功能与设备标识和设备孪生相同,但前者的粒度更细。 这种更高的粒度级可让有能力的设备(例如基于操作系统的设备,或管理多个组件的固件设备)隔离其中每个组件的配置和状态。 与包含模块化软件组件的 IoT 设备结合使用时,模块标识和模块孪生能够提供管理关注点分离。 推出模块孪生的正式版后,我们将会支持模块孪生级别的所有设备孪生功能。
注意
本文所述的功能只能用于 IoT 中心的标准层。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层。
本文介绍:
有关使用报告的属性、设备到云的消息或文件上传的指导,请参阅设备到云的通信指南。
有关使用所需的属性、直接方法或云到设备的消息的指导,请参阅云到设备的通信指南。
模块孪生
模块孪生存储具有以下用途的模块相关信息:
设备和 IoT 中心上的模块可以使用这些信息来同步模块状态和配置。
解决方案后端可以使用这些信息来查询和定位长时间运行的操作。
模块孪生的生命周期链接到相应的模块标识。 在 IoT 中心创建或删除模块标识时,将隐式创建和删除模块孪生。
模块孪生是一个 JSON 文档,其中包含:
标记。 后端应用可从中读取和写入数据的 JSON 文档的某个部分。 标记对设备上的模块不可见。 设置的标记用于查询目的。
所需的属性。 与报告的属性结合使用,同步模块配置或状态。 后端应用可设置所需的属性,并且模块应用可进行读取。 此外,当所需的属性发生更改时,模块应用可收到通知。
报告的属性。 与所需的属性结合使用,同步模块配置或状态。 模块应用可设置报告的属性,并且后端应用可进行读取和查询。
模块标识属性。 模块孪生 JSON 文档的根包含标识注册表中存储的相应模块标识的只读属性。
以下示例显示了一个模块孪生 JSON 文档:
{
"deviceId": "devA",
"moduleId": "moduleA",
"etag": "AAAAAAAAAAc=",
"status": "enabled",
"statusReason": "provisioned",
"statusUpdateTime": "0001-01-01T00:00:00",
"connectionState": "connected",
"lastActivityTime": "2015-02-30T16:24:48.789Z",
"cloudToDeviceMessageCount": 0,
"authenticationType": "sas",
"x509Thumbprint": {
"primaryThumbprint": null,
"secondaryThumbprint": null
},
"version": 2,
"tags": {
"deploymentLocation": {
"building": "43",
"floor": "1"
}
},
"properties": {
"desired": {
"telemetryConfig": {
"sendFrequency": "5m"
},
"$metadata" : {...},
"$version": 1
},
"reported": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": "success"
},
"batteryLevel": 55,
"$metadata" : {...},
"$version": 4
}
}
}
在顶层,模块孪生对象包含 tags
以及 reported
和 desired
属性的模块标识属性和容器对象。 properties
容器包含一些只读元素($metadata
和 $version
),模块孪生元数据和乐观并发部分描述了这些元素。
报告属性示例
在上面的示例中,模块孪生包含 batteryLevel
报告的属性。 使用此属性可以根据上次报告的电池电量水平查询和操作模块。 其他示例包括让模块应用报告模块功能或连接选项。
注意
报告的属性简化了对属性的最后一个已知值感兴趣的方案。 如果你需要以带时间戳事件序列(例如时间序列)的形式处理模块遥测数据,可以使用设备到云消息。
所需属性示例
在上面的示例中,后端应用和模块应用使用 telemetryConfig
模块孪生的所需和报告属性来同步此模块的遥测配置。 例如:
后端应用使用所需配置值设置所需属性。 下面是文档中包含所需属性集的那部分:
... "desired": { "telemetryConfig": { "sendFrequency": "5m" }, ... }, ...
模块连接后,模块应用会立即收到更改通知。 如果模块未连接,则模块应用会在连接时遵循模块重新连接流。 然后,模块应用报告更新的配置(或使用
status
属性报告错误状态)。 下面是报告属性的一部分:"reported": { "telemetryConfig": { "sendFrequency": "5m", "status": "success" } ... }
后端应用可以通过查询模块孪生,跟踪多个模块上的配置操作结果。
注意
为便于阅读,上述代码片段示例经过优化,演示了为模块配置及其状态进行编码的一种方式。 IoT 中心不会对模块孪生中的所需属性和报告属性施加特定的架构。
重要
IoT 即插即用定义了一个架构,该架构使用几个附加属性来将更改同步到所需属性和报告属性。 如果解决方案使用 IoT 即插即用,则更新孪生体属性时必须遵循即插即用约定。 有关详细信息和示例,请参阅 IoT 即插即用中的可写属性。
后端操作
后端应用使用以下通过 HTTPS 公开的原子操作对模块孪生执行操作:
按 ID 检索模块孪生。 此操作返回模块孪生文档,包括标记、所需的系统属性和报告的系统属性。
部分更新模块孪生。 此操作将部分更新模块孪生中的标记或所需属性。 部分更新以 JSON 文档的形式表示,可添加或更新任何属性。 将删除设置为
null
的属性。 以下示例创建值为{"newProperty": "newValue"}
的新所需属性,将现有值existingProperty
覆盖为"otherNewValue"
,并删除otherOldProperty
。 不会对现有的所需属性或标记进行其他任何更改:{ "properties": { "desired": { "newProperty": { "nestedProperty": "newValue" }, "existingProperty": "otherNewValue", "otherOldProperty": null } } }
替换所需属性。 此操作将完全覆盖所有现有的所需属性,并用新的 JSON 文档替换
properties/desired
。替换标记。 此操作将完全覆盖所有现有标记,并用新的 JSON 文档替换
tags
。接收孪生通知。 此操作会在孪生被修改时发出通知。 若要接收模块孪生更改通知,IoT 解决方案需要创建路由并将数据源设置为等于 twinChangeEvents。 默认情况下,不存在此类路由,因此不会发送孪生通知。 如果更改速率太高,或由于其他原因(例如内部故障),IoT 中心可能会只发送一个包含所有更改的通知。 因此,如果应用程序需要可靠地审核和记录所有中间状态,则应使用设备到云消息。 若要详细了解孪生通知消息中返回的属性和正文,请参阅非遥测事件架构。
上述所有操作均支持乐观并发,并且需要控制对 IoT 中心的访问文章中定义的 ServiceConnect 权限。
除了上述操作以外,后端应用还可以使用类似于 SQL 的 IoT 中心查询语言查询模块孪生。
模块操作
模块应用使用以下原子操作对模块孪生执行操作:
检索模块孪生。 此操作返回当前连接的模块的模块孪生文档(包括所需和报告的系统属性)。
部分更新报告属性。 使用此操作可以部分更新当前连接的模块的报告属性。
观察所需属性。 当前连接的模块可以选择在所需属性发生更新时接收通知。
上述所有操作都需要控制对 IoT 中心的访问一文中定义的 DeviceConnect 权限。
借助 Azure IoT 设备 SDK,可通过多种语言和平台轻松使用上述操作。
标记和属性格式
标记、所需的属性和报告的属性是具有以下限制的 JSON 对象:
密钥:JSON 对象中的所有键都是 UTF-8 编码、区分大小写且长度不超过 1 KB。 允许的字符不包括 UNICODE 控制字符(段 C0 和 C1)以及
.
、$
和 SP。值:JSON 对象中的所有值可采用以下 JSON 类型:布尔值、数字、字符串、对象。 还支持数组。
整数的最小值可以为 -4503599627370496,最大值可以为 4503599627370495。
字符串值是 UTF-8 编码的,最大长度为 4 KB。
深度:标记、所需属性和报告属性中的 JSON 对象的最大深度为 10 层。 例如,以下对象是有效的:
{ ... "tags": { "one": { "two": { "three": { "four": { "five": { "six": { "seven": { "eight": { "nine": { "ten": { "property": "value" } } } } } } } } } } }, ... }
模块孪生大小
IoT 中心对 tags
的值实施 8 KB 大小限制,对 properties/desired
和 properties/reported
的值各实施 32 KB 大小限制。 这些总计不包含只读元素(如 $version
和 $metadata/$lastUpdated
)。
孪生大小按如下所示计算:
IoT 中心会累积计算并添加每个属性的键和值的长度。
属性键将视为 UTF8 编码的字符串。
简单属性值将视为 UTF8 编码的字符串、数值(8 字节)或布尔值(4 字节)。
UTF8 编码字符串的大小通过对所有字符进行计数来计算,不包括 UNICODE 控制字符(段 C0 和 C1)。
复杂属性值(嵌套对象)根据它们所包含的属性键和属性值的聚合大小进行计算。
IoT 中心拒绝将这些文档的大小增加到超出限制的所有操作,在这种情况下还会返回错误。
模块孪生元数据
IoT 中心保留模块孪生所需属性和报告属性中每个 JSON 对象的上次更新时间戳。 时间戳采用 UTC,以 ISO8601 格式编码YYYY-MM-DDTHH:MM:SS.mmmZ
。
例如:
{
...
"properties": {
"desired": {
"telemetryConfig": {
"sendFrequency": "5m"
},
"$metadata": {
"telemetryConfig": {
"sendFrequency": {
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$lastUpdated": "2016-03-30T16:24:48.789Z"
},
"$version": 23
},
"reported": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": "success"
},
"batteryLevel": "55%",
"$metadata": {
"telemetryConfig": {
"sendFrequency": "5m",
"status": {
"$lastUpdated": "2016-03-31T16:35:48.789Z"
},
"$lastUpdated": "2016-03-31T16:35:48.789Z"
},
"batteryLevel": {
"$lastUpdated": "2016-04-01T16:35:48.789Z"
},
"$lastUpdated": "2016-04-01T16:24:48.789Z"
},
"$version": 123
}
}
...
}
会在每个级别(而不仅仅是 JSON 结构的叶级别)保留此信息,以便保留删除了对象键的更新。
乐观并发
标记、所需的属性和已报告的属性都支持乐观并发。 如果需要保证孪生属性更新的顺序,请考虑通过在发送下次更新前先等待已报告的属性回调,从而在应用程序级别实现同步。
根据 etag
RFC7232,模块孪生具有 ETag( 属性),它代表该孪生的 JSON 表示形式。 可以在来自后端应用的条件更新操作中使用 etag
属性,以确保一致性。 此选项可确保涉及 tags
容器的操作实现一致性。
模块孪生所需的属性和报告的属性也包含一个保证可递增的 $version
值。 与 ETag 类似,可以使用版本值来强制更新的一致性。 例如,报告的属性的模块应用,或者所需的属性的后端应用。
当监视代理(例如,监视所需属性的模块应用)必须协调检索操作结果与更新通知之间的资源争用时,版本也很有用。 模块重新连接流部分提供了详细信息。
模块重新连接流
IoT 中心不会保留已断开连接模块的所需属性更新通知。 它遵循的原则是:连接的模块必须检索整个所需属性文档,此外还要订阅更新通知。 如果更新通知与完全检索之间存在资源争用的可能性,则必须确保遵循以下流:
- 模块应用连接到 IoT 中心。
- 模块应用订阅所需属性更新通知。
- 模块应用检索所需属性的完整文档。
模块应用可以忽略 $version
小于或等于完全检索文档的版本的所有通知。 之所以能够使用此方法,是因为 IoT 中心保证版本始终是递增的。
后续步骤
要尝试本文中介绍的一些概念,请参阅以下 IoT 中心教程: