你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
IoT 即插即用约定
IoT 即插即用设备在与 IoT 中心交换消息时应遵循一组约定。 IoT 即插即用设备使用 MQTT 协议与 IoT 中心通信。 IoT 中心还支持某些 IoT 设备 SDK 中提供的 AMQP 协议。
设备可以包含模块,或在由 IoT Edge 运行时托管的 IoT Edge 模块中实现。
介绍 IoT 即插即用设备使用数字孪生定义语言 (DTDL) 模型实现的遥测、属性和命令。 本文中引用了两种类型的模型:
- 无组件 - 没有组件的模型。 此模型将遥测、属性和命令声明为主接口的内容部分中的顶级元素。 在 Azure IoT 资源管理器工具中,此模型显示为单个默认组件。
- 多组件 - 由两个或多个接口组成的模型。 主接口显示为默认组件,包含遥测、属性和命令。 一个或多个接口声明为包含更多遥测、属性和命令的组件。
有关详细信息,请参阅 IoT 即插即用建模指南。
识别模型
为了宣布实现的模型,IoT 即插即用设备或模块通过将 model-id
添加到 USERNAME
字段,在 MQTT 连接数据包中包含模型 ID。
若要标识设备或模块实现的模型,服务可以从以下项获取模型 ID:
- 设备孪生
modelId
字段。 - 数字孪生体
$metadata.$model
字段。 - 数字孪生体更改通知。
遥测
- 从无组件设备发送的遥测不需要任何额外的元数据。 系统添加
dt-dataschema
属性。 - 使用组件从设备发送的遥测数据必须将组件名称添加到遥测消息中。
- 使用 MQTT 时,请将组件名称的
$.sub
属性添加到遥测主题时,系统会添加dt-subject
属性。 - 使用 AMQP 时,将组件名称的
dt-subject
属性添加为消息批注。
注意
来自组件的遥测需要每个组件一条消息。
有关更多遥测示例,请参阅有效负载和遥测
只读属性
设备设置一个只读属性,该属性随后报告给后端应用程序。
无组件只读属性示例
设备或模块可以发送遵循 DTDL 规则的任何有效 JSON。
在接口上定义属性的 DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:example: Thermostat;1",
"@type": "Interface",
"contents": [
{
"@type": "Property",
"name": "temperature",
"schema": "double"
}
]
}
报告的属性有效负载示例:
"reported" :
{
"temperature" : 21.3
}
多组件只读属性示例
设备或模块必须添加 {"__t": "c"}
标记以指示元素引用组件。
引用组件的 DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:com:example:TemperatureController;1",
"@type": "Interface",
"displayName": "Temperature Controller",
"contents": [
{
"@type" : "Component",
"schema": "dtmi:com:example:Thermostat;1",
"name": "thermostat1"
}
]
}
定义组件的 DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:com:example:Thermostat;1",
"@type": "Interface",
"contents": [
{
"@type": "Property",
"name": "temperature",
"schema": "double"
}
]
}
报告的属性有效负载示例:
"reported": {
"thermostat1": {
"__t": "c",
"temperature": 21.3
}
}
有关更多只读属性示例,请参阅有效负载和属性。
可写属性
后端应用程序设置一个可写属性,IoT 中心随后会将该属性发送到设备。
设备或模块应通过发送报告的属性来确认已接收到属性。 报告的属性应包括:
value
- 属性的实际值(通常是接收到的值,但设备可能决定报告不同的值)。ac
- 使用 HTTP 状态代码的确认代码。av
- 引用所需属性的$version
的确认版本。 可在所需的属性 JSON 有效负载中找到该值。ad
- 可选确认说明。
确认响应
报告可写属性时,设备应使用上述列表中的 4 个字段撰写确认消息,以指示实际设备状态,如下表中所述:
状态 (ac) | 版本 (av) | 值 (value) | 说明 (av) |
---|---|---|---|
200 | 所需版本 | 所需值 | 接受的所需属性值 |
202 | 所需版本 | 设备接受的值 | 接受的所需属性值,更新正在进行(应该完成并返回 200 代码) |
203 | 0 | 设备设置的值 | 从设备设置的属性,不反映任何所需值 |
400 | 所需版本 | 设备使用的实际值 | 未接受的所需属性值 |
500 | 所需版本 | 设备使用的实际值 | 应用属性时发生异常 |
设备启动时,应该请求设备孪生,并检查是否有可写属性更新。 如果在设备处于脱机状态时增加了可写属性的版本,则设备应发送报告的属性响应,以确认接收到更新。
设备首次启动时,如果没有从 IoT 中心接收到初始所需属性,可以为报告的属性发送初始值。 在这种情况下,设备可将包含 av
的默认值发送到 0
,将包含 ac
的默认值发送到 203
。 例如:
"reported": {
"targetTemperature": {
"value": 20.0,
"ac": 203,
"av": 0,
"ad": "initialize"
}
}
设备可以使用报告的属性向中心提供其他信息。 例如,设备可能会使用一系列正在进行的消息进行响应,如:
"reported": {
"targetTemperature": {
"value": 35.0,
"ac": 202,
"av": 3,
"ad": "In-progress - reporting current temperature"
}
}
设备达到目标温度时,会发送以下消息:
"reported": {
"targetTemperature": {
"value": 20.0,
"ac": 200,
"av": 4,
"ad": "Reached target temperature"
}
}
设备可能会报告如下错误:
"reported": {
"targetTemperature": {
"value": 120.0,
"ac": 500,
"av": 3,
"ad": "Target temperature out of range. Valid range is 10 to 99."
}
}
对象类型
如果将可写属性定义为对象,则服务必须将完整的对象发送到设备。 设备应通过将足够的信息发送回服务来确认更新,以便服务了解设备对更新的处理方式。 此响应可能包括:
- 整个对象。
- 仅设备更新的字段。
- 字段的子集。
对于大型对象,请考虑最大程度地减小确认中包含的对象的大小。
以下示例显示了定义为 Object
(使用四个字段)的可写属性:
DTDL:
{
"@type": "Property",
"name": "samplingRange",
"schema": {
"@type": "Object",
"fields": [
{
"name": "startTime",
"schema": "dateTime"
},
{
"name": "lastTime",
"schema": "dateTime"
},
{
"name": "count",
"schema": "integer"
},
{
"name": "errorCount",
"schema": "integer"
}
]
},
"displayName": "Sampling range"
"writable": true
}
若要更新此可写属性,请从服务发送一个完整的对象,如下例所示:
{
"samplingRange": {
"startTime": "2021-08-17T12:53:00.000Z",
"lastTime": "2021-08-17T14:54:00.000Z",
"count": 100,
"errorCount": 5
}
}
设备使用一个确认进行响应,如下例所示:
{
"samplingRange": {
"ac": 200,
"av": 5,
"ad": "Weighing status updated",
"value": {
"startTime": "2021-08-17T12:53:00.000Z",
"lastTime": "2021-08-17T14:54:00.000Z",
"count": 100,
"errorCount": 5
}
}
}
无组件可写属性示例
设备在单个有效负载中接收多个所需属性时,可以跨多个有效负载发送报告的属性响应,或将多个响应合并为单个有效负载。
设备或模块可以发送遵循 DTDL 规则的任何有效 JSON。
DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:example: Thermostat;1",
"@type": "Interface",
"contents": [
{
"@type": "Property",
"name": "targetTemperature",
"schema": "double",
"writable": true
},
{
"@type": "Property",
"name": "targetHumidity",
"schema": "double",
"writable": true
}
]
}
所需的属性有效负载示例:
"desired" :
{
"targetTemperature" : 21.3,
"targetHumidity" : 80,
"$version" : 3
}
报告的属性第一个有效负载示例:
"reported": {
"targetTemperature": {
"value": 21.3,
"ac": 200,
"av": 3,
"ad": "complete"
}
}
报告的属性第二个有效负载示例:
"reported": {
"targetHumidity": {
"value": 80,
"ac": 200,
"av": 3,
"ad": "complete"
}
}
注意
可以选择将这两个报告的属性有效负载组合成单个有效负载。
多组件可写属性示例
设备或模块必须添加 {"__t": "c"}
标记以指示元素引用组件。
发送标记仅用于更新组件中定义的属性。 对默认组件中定义的属性的更新不包括标记,请参阅无组件可写属性示例。
设备在单个有效负载中接收多个报告的属性时,可以跨多个有效负载发送报告的属性响应,或将多个响应合并为单个有效负载。
设备或模块应通过发送报告的属性来确认已接收到属性:
引用组件的 DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:com:example:TemperatureController;1",
"@type": "Interface",
"displayName": "Temperature Controller",
"contents": [
{
"@type" : "Component",
"schema": "dtmi:com:example:Thermostat;1",
"name": "thermostat1"
}
]
}
定义组件的 DTDL:
{
"@context": "dtmi:dtdl:context;2",
"@id": "dtmi:com:example:Thermostat;1",
"@type": "Interface",
"contents": [
{
"@type": "Property",
"name": "targetTemperature",
"schema": "double",
"writable": true
}
]
}
所需的属性有效负载示例:
"desired": {
"thermostat1": {
"__t": "c",
"targetTemperature": 21.3,
"targetHumidity": 80,
"$version" : 3
}
}
报告的属性第一个有效负载示例:
"reported": {
"thermostat1": {
"__t": "c",
"targetTemperature": {
"value": 23,
"ac": 200,
"av": 3,
"ad": "complete"
}
}
}
报告的属性第二个有效负载示例:
"reported": {
"thermostat1": {
"__t": "c",
"targetHumidity": {
"value": 80,
"ac": 200,
"av": 3,
"ad": "complete"
}
}
}
注意
可以选择将这两个报告的属性有效负载组合成单个有效负载。
有关更多可写属性示例,请参阅有效负载和属性。
命令
无组件接口使用不带前缀的命令名称。
在设备或模块上,多组件接口使用以下格式的命令名称:componentName*commandName
。
有关更多命令示例,请参阅有效负载和命令。
后续步骤
现在,你已了解了 IoT 即插即用约定,以下是一些其他资源: