

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在裝置中使用影子
<a name="device-shadow-comms-device"></a>

本節說明使用 MQTT 訊息與陰影進行裝置通訊，MQTT 訊息是裝置與 AWS IoT Device Shadow 服務通訊的偏好方法。

影子通訊功能會模擬使用 MQTT 的發佈/訂閱通訊模型的請求/回應模型。每個影子動作包括一個請求主題，一個成功的回應主題 (`accepted`) 和一個錯誤響應主題 (`rejected`)。

如果您希望應用程式和服務能夠判斷裝置是否已連線，請參閱 [偵測裝置是否已連線](device-shadow-comms-app.md#thing-connection)。

**重要**  
因 MQTT 會使用發佈/訂閱通訊模型，因此您應*先*訂閱回應主題，再發佈請求主題。若您並未這麼做，則將不會收到發佈請求的回應。  
若您使用 [AWS IoT Device SDK](iot-sdks.md) 呼叫 Device Shadow 服務 API，則會為您處理。

本節範例使用主題的縮寫形式，其中 *ShadowTopicPrefix* 可參照已命名或未命名的影子，如本表格所述。

影子可以為已命名或未命名 (典型)。各影子所使用的主題只有在主題字首中有所不同。此表格會顯示每種影子類型所使用的主題字首。


| *ShadowTopicPrefix* 值 | 影子類型 | 
| --- | --- | 
| \$1aws/things/thingName/shadow | 未命名 (經典) 影子 | 
| \$1aws/things/thingName/shadow/name/shadowName | 已命名影子 | 

**重要**  
確保您的應用程式或服務對影子的使用符合一致性，並且受您裝置中對應的實作支援。例如，請考慮如何建立、更新和刪除影子。也請考慮如何在裝置中處理更新，以及透過影子存取裝置的應用程式或服務。您的設計應該清楚了解裝置狀態如何更新和報告，以及您的應用程式和服務如何與裝置及其影子互動。

若要建立完整的主題，請在 `ShadowTopicPrefix` 選取您要參照的影子類型、用對應值取代 `thingName` 及 `shadowName` (如適用) 的影子類型，然後將該類型附加至主題 stub，如下表所示。請記住，主題會區分大小寫。

如需有關影子保留主題的詳細資訊，請參閱 [影子主題](reserved-topics.md#reserved-topics-shadow)。

## 在第一次連線至 時初始化裝置 AWS IoT
<a name="device-shadow-comms-device-first-connect"></a>

裝置向 註冊後 AWS IoT，應該訂閱這些 MQTT 訊息，以取得其支援的陰影。


| 主題 | 意義 | 收到此主題時裝置應採取的動作 | 
| --- | --- | --- | 
|  `ShadowTopicPrefix/delete/accepted`  |  `delete` 請求已被接受並 AWS IoT 刪除影子。  |  適應已刪除影子所需的動作，例如停止發佈更新。  | 
|  `ShadowTopicPrefix/delete/rejected`  |  `delete` 請求遭到 拒絕， AWS IoT 且影子未遭到刪除。訊息內文包含錯誤資訊。  |  在訊息內文中回應錯誤訊息。  | 
|  `ShadowTopicPrefix/get/accepted`  |  `get` 請求已由 接受 AWS IoT，且訊息內文包含目前的影子文件。  |  處理訊息內文中的狀態文件所需的動作。  | 
|  `ShadowTopicPrefix/get/rejected`  |  `get` 請求遭到 拒絕 AWS IoT，且訊息內文包含錯誤資訊。  |  在訊息內文中回應錯誤訊息。  | 
|  `ShadowTopicPrefix/update/accepted`  |  `update` 請求已由 接受 AWS IoT，且訊息內文包含目前的影子文件。  |  確認訊息內文中的更新資料符合裝置狀態。  | 
|  `ShadowTopicPrefix/update/rejected`  |  `update` 請求遭到 拒絕 AWS IoT，且訊息內文包含錯誤資訊。  |  在訊息內文中回應錯誤訊息。  | 
|  `ShadowTopicPrefix/update/delta`  |  影子文件已由請求更新 AWS IoT，且訊息內文包含請求的變更。  |  更新裝置的狀態，以符合訊息內文中所需的狀態。  | 
|  `ShadowTopicPrefix/update/documents`  |  最近已完成影子的更新，而訊息內文包含目前的影子文件。  |  確認訊息內文中的更新狀態符合裝置的狀態。  | 

訂閱上表中每個影子的訊息之後，裝置應該測試，看看它支援的影子是否已經透過將 `/get` 主題發佈到每個影子來建立。如果收到 `/get/accepted` 訊息，訊息內文會包含影子文件，裝置可用來初始化其狀態。如果收到 `/get/rejected` 訊息，應該透過發佈具有目前裝置狀態的 `/update` 訊息來建立影子。

例如，假設您有一個沒有任何經典或已命名影子的物件 `My_IoT_Thing`。如果您現在於保留主題 `$aws/things/My_IoT_Thing/shadow/get` 上發佈 `/get` 請求，則會在 `$aws/things/My_IoT_Thing/shadow/get/rejected` 主題上傳回錯誤，因為物件沒有任何影子。若要解決此錯誤，請先使用 `$aws/things/My_IoT_Thing/shadow/update` 主題發佈 `/update` 訊息與目前裝置狀態 (如以下承載)。

```
{
	"state": {
		"reported": {
			"welcome": "aws-iot",
			"color": "yellow"
		}
	}
}
```

現在會為物件建立一個經典影子，並將訊息發佈至 `$aws/things/My_IoT_Thing/shadow/update/accepted` 主題。如果發佈至主題 `$aws/things/My_IoT_Thing/shadow/get`，則會將回應與裝置狀態傳回給 `$aws/things/My_IoT_Thing/shadow/get/accepted` 主題。

對於已命名的影子，在使用 get 請求之前，必須先建立已命名的影子或發佈含有影子名稱的更新。例如，若要建立已命名的影子 `namedShadow1`，請先將裝置狀態資訊發佈至主題 `$aws/things/My_IoT_Thing/shadow/name/namedShadow1/update`。若要擷取狀態資訊，請對已命名的影子 `$aws/things/My_IoT_Thing/shadow/name/namedShadow1/get` 使用 `/get` 請求。

## 在裝置連線到 時處理訊息 AWS IoT
<a name="device-shadow-comms-device-while-connected"></a>

當裝置連線到 時 AWS IoT，它可以接收 **/update/delta** 訊息，並應透過下列方式讓裝置狀態與其影子中的變更相符：

1. 讀取接收到的所有 **/update/delta** 訊息，並同步處理裝置狀態以進行比對。

1. 只要裝置狀態發生變化時，便使用具有裝置目前狀態的 `reported` 訊息內文發佈 **/update** 訊息。

當裝置連線時，它應該在指示時發佈這些訊息。


| 指示 | 主題 | 承載 | 
| --- | --- | --- | 
|  裝置的狀態已變更。  |  `ShadowTopicPrefix/update`  |  具有 `reported` 屬性的影子文件。  | 
| 裝置可能不會與影子同步。 |  `ShadowTopicPrefix/get`  | (空白) | 
|  裝置上的動作表示裝置將不再支援影子，例如移除或取代裝置時。  |  `ShadowTopicPrefix/delete`  | (空白) | 

## 當裝置重新連線至 時處理訊息 AWS IoT
<a name="device-shadow-comms-device-reconnect"></a>

當具有一或多個影子的裝置連線到 時 AWS IoT，應該透過下列方式將其狀態與其支援的所有影子狀態同步：

1. 讀取接收到的所有 **/update/delta** 訊息，並同步處理裝置狀態以進行比對。

1. 使用具有裝置目前狀態的 `reported` 訊息內文發佈 **/update** 訊息。