了解并在 IoT 中心内使用设备孪生
设备孪生是存储设备状态信息(例如元数据、配置和条件)的 JSON 文档。 Azure IoT 中心为连接到 IoT 中心的每台设备保留一个设备孪生。
注意
本文所述的功能只能用于 IoT 中心的标准层。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层。
本文介绍:
- 设备孪生的结构:标记、所需的属性和报告的属性。
- 可以由设备和后端应用程序在设备孪生上执行的操作。
使用设备孪生可以:
将设备特定的元数据存储在云中。 例如自动售货机的位置。
通过设备应用报告当前状态信息,例如可用功能和条件。 例如,是否通过移动电话网络或 WiFi 连接到 IoT 中心的设备。
同步设备应用与后端应用之间的长时间运行工作流的状态。 例如,当解决方案后端指定要安装的新固件版本以及设备应用报告更新过程的各个阶段时。
查询设备的元数据、配置或状态。
若要详细了解如何使用报告的属性、设备到云消息或文件上传,请参阅设备到云通信指南。
若要详细了解如何使用所需的属性、直接方法或云到设备消息,请参阅云到设备通信指南。
设备孪生
设备孪生存储具有以下用途的设备相关信息:
设备和后端可以使用这些信息来同步设备状态和配置。
解决方案后端可以使用这些信息来查询和定位长时间运行的操作。
设备孪生的生命周期链接到其相应的设备标识。 在 IoT 中心创建或删除设备标识时,将隐式创建和删除设备孪生。
设备孪生是一个 JSON 文档,其中包含:
标记。 解决方案后端可从中读取和写入数据的 JSON 文档的某个部分。 标记对设备应用不可见。
所需的属性。 与报告的属性结合使用,同步设备配置或状态。 解决方案后端可设置所需的属性,并且设备应用可进行读取。 此外,当所需的属性发生更改时,设备应用可收到通知。
报告的属性。 与所需的属性结合使用,同步设备配置或状态。 设备应用可设置报告的属性,并且解决方案后端可进行读取和查询。
设备标识属性。 设备孪生 JSON 文档的根包含标识注册表中存储的相应设备标识的只读属性。 不会包含属性
connectionStateUpdatedTime
和generationId
。
以下示例显示了一个设备孪生 JSON 文档:
{
"deviceId": "devA",
"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 中心不会对设备孪生中的所需属性和报告属性施加特定的架构。
可以使用孪生来同步长时间运行的操作,例如固件更新。 有关如何使用属性来同步和跟踪各设备中长时间运行的操作的详细信息,请参阅使用所需的属性来配置设备。
后端操作
解决方案后端使用以下通过 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 中心查询语言查询设备孪生。
使用作业针对大型设备孪生集执行操作。
设备操作
设备应用使用以下原子操作对设备孪生执行操作:
检索设备孪生。 此操作返回当前连接的设备的设备孪生文档(包括所需的系统属性和报告的系统属性)。 (标记对设备应用不可见。)
部分更新报告属性。 使用此操作可以部分更新当前连接的设备的报告属性。 此操作使用的 JSON 更新格式与解决方案后端用于部分更新所需属性的格式相同。
观察所需属性。 当前连接的设备可以选择在所需属性发生更新时接收通知。 设备收到的更新格式与解决方案后端执行的更新格式相同(部分或完全替换)。
上述所有操作都需要控制对 IoT 中心的访问中定义的 DeviceConnect 权限。
借助 Azure IoT 设备 SDK,可通过多种语言和平台轻松使用上述操作。 有关用于同步所需属性的 IoT 中心基元的详细信息,请参阅设备重新连接流。
标记和属性格式
标记、所需的属性和报告的属性是具有以下限制的 JSON 对象:
密钥:JSON 对象中的所有键都是 UTF-8 编码、区分大小写且长度不超过 1 KB。 允许的字符不包括 UNICODE 控制字符(段 C0 和 C1)以及
.
、$
和 SP。注意
消息路由中使用的 IoT 中心查询不支持在密钥名称中使用空格或以下任何字符:
()<>@,;:\"/?={}
。值: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
)。
孪生大小按如下所示计算:
对于 JSON 文档中的每个属性,IoT 中心会累积计算并添加属性的键和值的长度。
属性键将视为 UTF8 编码的字符串。
简单属性值将视为 UTF8 编码的字符串、数值(8 字节)或布尔值(4 字节)。
UTF8 编码字符串的大小通过对所有字符进行计数来计算,不包括 UNICODE 控制字符(段 C0 和 C1)。
复杂属性值(嵌套对象)根据它们所包含的属性键和属性值的聚合大小进行计算。
对于会使 tags
、properties/desired
或 properties/reported
文档的大小增大到超出上限的所有操作,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": {
"$lastUpdated": "2016-03-31T16:35:48.789Z"
},
"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 结构的叶级别)保留此信息,以便保留删除了对象键的更新。
乐观并发
标记、所需的属性和已报告的属性都支持乐观并发。 如果需要保证孪生属性更新的顺序,请考虑通过在发送下次更新前先等待已报告的属性回调,从而在应用程序级别实现同步。
根据 RFC7232,设备孪生具有 ETag etag
属性,它代表该孪生的 JSON 表示形式。 可以在来自解决方案后端的条件更新操作中使用 etag
属性,以确保一致性。 如果要确保涉及 tags
容器的操作中的一致性,此属性是唯一方案。
设备孪生所需的属性和报告的属性也包含一个保证可递增的 $version
值。 更新方可以使用类似于 ETag 的版本来强制实施更新一致性。 例如,报告的属性的设备应用,或者所需的属性的解决方案后端。
当监视代理(例如,监视所需属性的设备应用)必须协调检索操作结果与更新通知之间的资源争用时,版本也很有用。 设备重新连接流部分提供了详细信息。
设备重新连接流
IoT 中心不会保留已断开连接设备的所需属性更新通知。 它遵循的原则是:连接的设备必须检索整个所需属性文档,此外还要订阅更新通知。 如果更新通知与完全检索之间存在资源争用的可能性,则必须确保遵循以下流:
- 设备应用连接到 IoT 中心。
- 设备应用订阅所需属性更新通知。
- 设备应用检索所需属性的完整文档。
设备应用可以忽略 $version
小于或等于完全检索文档的版本的所有通知。 之所以能够使用此方法,是因为 IoT 中心保证版本始终是递增的。
后续步骤
若要尝试本文中介绍的一些概念,请参阅以下 IoT 中心文章: