IoT 隨插即用慣例
IoT 隨插即用裝置與 IoT 中樞交換訊息時,應該遵循一組慣例。 IoT 隨插即用裝置會使用 MQTT 通訊協定與「IoT 中樞」進行通訊。 IoT 中樞也支援某些 IoT 裝置 SDK 中提供的 AMQP 通訊協定。
裝置可以包含模組,或在 IoT Edge 執行階段裝載的 IoT Edge 模組中實作。
您描述 IoT 隨插即用 裝置使用數字對應項定義語言 (DTDL) 模型實作的遙測、屬性和命令。 本文中提及的模型有兩種類型:
- 無元件 - 沒有元件的模型。 模型會將遙測、屬性和命令宣告為主要介面內容區段中的最上層元件。 在 Azure IoT 總管工具中,此模型會顯示為單一預設元件。
- 多元件 - 由兩個或多個介面組成的模型。 主要介面會顯示為預設元件,其中包含遙測、屬性和命令。 一個或多個介面會宣告為具有更多遙測、屬性和命令的元件。
如需詳細資訊,請參閱 IoT 隨插即用模型化指南。
識別模型
若要宣告其實作的模型,IoT 隨插即用裝置或模組會藉由將 model-id
新增至 USERNAME
欄位,在 MQTT 連線封包中包含模型識別碼。
若要識別裝置或模組所實作的模型,服務可以從下列來源取得模型識別碼:
- 裝置對應項的
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
- 選擇性確認描述。
確認回應
當報告可寫入屬性時,裝置應該使用上述清單中的四個欄位來撰寫確認訊息,以指出實際的裝置狀態,如下表所述:
狀態(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 type
如果可寫入的屬性定義為物件,服務必須將完整物件傳送至裝置。 裝置應該藉由將足夠的資訊傳回服務來確認更新,讓服務了解裝置在更新上的運作方式。 此回應可能包括:
- 整個物件。
- 只有裝置更新的欄位。
- 欄位的子集。
對於大型物件,請考慮將您包含在確認中的物件大小降至最低。
下列範例顯示定義為 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 隨插即用慣例,以下是一些額外的資源: