你当前正在访问 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
组件名称的属性添加为消息批注。
注意
来自组件的遥测需要每个组件一条消息。
有关更多遥测示例,请参阅 Payloads > Telemetry
只读属性
设备设置一个只读属性,然后向后端应用程序报告该属性。
无组件只读属性示例
设备或模块可以发送遵循 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
}
}
有关更多只读属性示例,请参阅 Payloads > 属性。
可写属性
后端应用程序设置一个可写属性,该属性IoT 中心然后发送到设备。
设备或模块应通过发送报告的属性来确认已接收到属性。 报告的属性应包括:
value
- 属性的实际值(通常是接收到的值,但设备可能决定报告不同的值)。ac
- 使用 HTTP 状态代码的确认代码。av
- 引用所需属性的$version
的确认版本。 可在所需的属性 JSON 有效负载中找到该值。ad
- 可选确认说明。
确认响应
报告可写属性时,设备应通过使用上一列表中的四个字段来撰写确认消息,以指示实际设备状态,如下表所述:
状态 (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"
}
}
}
注意
可以选择将这两个报告的属性有效负载组合成单个有效负载。
有关更多可写属性示例,请参阅 Payloads > 属性。
命令
无组件接口使用不带前缀的命令名称。
在设备或模块上,多组件接口使用以下格式的命令名称:componentName*commandName
。
有关更多命令示例,请参阅 Payloads > 命令。
后续步骤
现在,你已了解了 IoT 即插即用约定,以下是一些其他资源: