

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

# 模擬 Device Shadow 服務通訊
<a name="using-device-shadows"></a>

本主題示範如何將 Device Shadow 服務如何作為中繼點，並允許裝置和應用程式使用影子來更新、儲存和擷取裝置的狀態。

若要示範本主題中所述的互動，並進一步探索，您需要 AWS 帳戶 和 系統，才能執行 AWS CLI。如果您沒有這些項目，您仍然可以在程式碼範例中看到互動。

在此範例中， AWS IoT 主控台代表裝置。 AWS CLI 代表透過影子存取裝置的應用程式或服務。介面與應用程式可能用來通訊的 API AWS CLI 非常相似 AWS IoT。此範例中的裝置是智慧型燈泡，應用程式會顯示燈泡的狀態，而且可以變更燈泡的狀態。

## 準備模擬
<a name="using-device-shadows-setup"></a>

以下程序會開啟模擬裝置的 [AWS IoT 主控台](https://console.aws.amazon.com/iot/home)，以及模擬應用程式的命令列視窗來初始化模擬。

**準備模擬環境的步驟**

1. 您需要 AWS 帳戶 ，才能自行執行本主題中的範例。如果您沒有 AWS 帳戶，請建立一個，如 中所述[設定 AWS 帳戶](setting-up.md)。

1. 開啟 [AWS IoT 主控台](https://console.aws.amazon.com/iot/home)，然後在左側選單中選擇 **Test (測試)** 以開啟 **MQTT client (MQTT 用戶端)**。

1. 在另一個視窗中，在已安裝 AWS CLI 的系統上開啟終端機視窗。

您應該開啟兩個視窗：一個在**測試**頁面上使用 AWS IoT 主控台，另一個使用命令列提示字元。

## 初始化裝置
<a name="using-device-shadows-init-device"></a>

在這個模擬中，我們將使用一個名為 *mySimulatedThing* 的物件物件，以及其名為 *simShadow1* 的影子。

**建立物件及其 IoT 政策**  
如要建立物件物件，請於 **AWS IoT 主控台**中：

1. 選擇 **Manage** (管理)，然後選擇 **Things** (物件)。

1. 如果列出實物，請按一下**建立**按鈕，否則請按一下**註冊單一實物**來建立單一 AWS IoT 實物。

1. 輸入名稱 `mySimulatedThing`，將其他設定保留為預設值，然後按一下**Next** (下一步)。

1. 使用單鍵憑證建立來產生憑證，其會驗證裝置到 AWS IoT的連線。按一下 **Activate** (啟用)，啟用憑證。

1. 您可連接政策 `My_IoT_Policy`，其將授與裝置發佈和訂閱 MQTT 預留主題的許可。如需如何建立 AWS IoT 物件以及如何建立此政策的詳細步驟，請參閱 [建立物件](create-iot-resources.md#create-aws-thing)。

**為物件建立已命名的影子**  
您可以向主題 `$aws/things/mySimulatedThing/shadow/name/simShadow1/update` 發佈更新請求來為物件建立已命名的影子，如下方所述。

或者，若要建立具名影子：

1. 在 **AWS IoT Console** (主控台) 中，在顯示的物件清單中選擇您的物件，然後選擇 **Shadows** (影子)。

1. 選擇 **Add a shadow** (新增影子)，輸入名稱 `simShadow1`，接著選擇 **Create** (建立)，以新增命名的影子。

**訂閱並發佈至預留 MQTT 主題**  
於主控台中，訂閱預留 MQTT 影子主題。這些主題是對 `get`、`update` 和 `delete` 動作的回應，以便您的裝置在發佈動作之後就可以接收回應。

**訂閱 **MQTT 用戶端**中的 MQTT 主題**

1. 於 **MQTT client** (MQTT 用戶端) 中，選擇 **Subscribe to a topic** (訂閱主題)。

1. 輸入 `get`、`update` 和 `delete` 主題以進行訂閱。從下方清單一次複製一個主題，將其貼到**Topic filter** (主題篩選條件) 欄位，再按一下 **Subscribe** (訂閱)。您應會看到顯示於 **Subscriptions** (訂閱) 之下的主題。
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/delete/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/delete/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/delta`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/documents`

   此時，您的模擬裝置已準備好接收由 AWS IoT發佈的主題。

**如要訂閱 **MQTT 用戶端**中的 MQTT 主題**  
在裝置自行初始化並訂閱回應主題之後，它會查詢所支援的影子。這個模擬支援只有一個影子，該影子命名為 *simShadow1*，支援命名為 *mySimulatedThing* 的物件物件。

**從 **MQTT 用戶端**取得目前影子狀態**

1. 於 **MQTT 用戶端** 中，選擇 **Publish to a topic (發佈至主題)**。

1. 在 **Publish** (發佈) 之下，輸入下列主題，然後刪除下方主題訊息內文視窗的任何內容，您可在其中輸入要取得的主題。接著，您可選擇 **Publish to topic** (發佈至主題)，發佈請求。`$aws/things/mySimulatedThing/shadow/name/simShadow1/get`。

   若您尚未建立命名的影子 `simShadow1`， 您收到了 `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/rejected` 主題中的一則訊息，且 `code` 為 `404`，(如此範例中所示)，則系統尚未建立該影子，因此我們接下來將其建立。

   ```
   {
     "code": 404,
     "message": "No shadow exists with name: 'simShadow1'"
   }
   ```

**建立具有裝置目前狀態的影子**

1. 在 **MQTT 用戶端**中，選擇**Publish to a topic** (發佈到主題)，然後輸入此主題：

   ```
   $aws/things/mySimulatedThing/shadow/name/simShadow1/update
   ```

1. 在您輸入主題的下方訊息內文視窗中，輸入此影子文件以顯示裝置正在報告其 ID 及其目前顏色的 RGB 值。選擇 **Publish** (發佈)，發佈請求。

   ```
   {
     "state": {
       "reported": {
         "ID": "SmartLamp21",
         "ColorRGB": [
           128,
           128,
           128
         ]
       }
     },
     "clientToken": "426bfd96-e720-46d3-95cd-014e3ef12bb6"
   }
   ```

若您在主題中收到一則訊息：
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted`：這表示已建立影子，而訊息內文包含目前的影子文件。
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/rejected`：檢閱訊息內文中的錯誤。
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/accepted`：影子已存在，且訊息內文具有目前的影子狀態，例如在此範例中。有了這個，您可以設置您的裝置或確認它符合影子狀態。

  ```
  {
    "state": {
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          128,
          128,
          128
        ]
      }
    },
    "metadata": {
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          }
        ]
      }
    },
    "version": 3,
    "timestamp": 1591140517,
    "clientToken": "426bfd96-e720-46d3-95cd-014e3ef12bb6"
  }
  ```

## 從應用程式傳送更新
<a name="using-device-shadows-app-update"></a>

本節使用 AWS CLI 來示範應用程式如何與影子互動。

**使用 取得影子的目前狀態 AWS CLI**  
在命令列輸入此命令：

```
aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 /dev/stdout
```

在 Windows 平台上，您可使用 `con`，而非 `/dev/stdout`。

```
aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 con
```

因為影子已存在，而且已由裝置初始化以反映其目前狀態，所以它會傳回下列的影子文件。

```
{
  "state": {
    "reported": {
      "ID": "SmartLamp21",
      "ColorRGB": [
        128,
        128,
        128
      ]
    }
  },
  "metadata": {
    "reported": {
      "ID": {
        "timestamp": 1591140517
      },
      "ColorRGB": [
        {
          "timestamp": 1591140517
        },
        {
          "timestamp": 1591140517
        },
        {
          "timestamp": 1591140517
        }
      ]
    }
  },
  "version": 3,
  "timestamp": 1591141111
}
```

應用程式可以使用此回應來初始化對其裝置狀態的表示法。

如果應用程式更新狀態，例如當使用者將智慧型燈泡的顏色變更為黃色時，應用程式會傳送 **update-thing-shadow** 命令。此命令會對應 `UpdateThingShadow` REST API。

**從應用程式更新影子**  
在命令列輸入此命令：

------
#### [ AWS CLI v2.x ]

```
aws iot-data update-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 \
    --cli-binary-format raw-in-base64-out \
    --payload '{"state":{"desired":{"ColorRGB":[255,255,0]}},"clientToken":"21b21b21-bfd2-4279-8c65-e2f697ff4fab"}' /dev/stdout
```

------
#### [ AWS CLI v1.x ]

```
aws iot-data update-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 \
    --payload '{"state":{"desired":{"ColorRGB":[255,255,0]}},"clientToken":"21b21b21-bfd2-4279-8c65-e2f697ff4fab"}' /dev/stdout
```

------

如果成功，這個命令應該會傳回下列影子文件。

```
{
  "state": {
    "desired": {
      "ColorRGB": [
        255,
        255,
        0
      ]
    }
  },
  "metadata": {
    "desired": {
      "ColorRGB": [
        {
          "timestamp": 1591141596
        },
        {
          "timestamp": 1591141596
        },
        {
          "timestamp": 1591141596
        }
      ]
    }
  },
  "version": 4,
  "timestamp": 1591141596,
  "clientToken": "21b21b21-bfd2-4279-8c65-e2f697ff4fab"
}
```

## 回應裝置中的更新
<a name="using-device-shadows-device-update"></a>

返回 AWS 主控台中的 **MQTT 用戶端**時，您應該會看到 AWS IoT 發佈的訊息，以反映上一節中發出的更新命令。

**在 **MQTT 用戶端**中檢視更新訊息**  
於 **MQTT 用戶端**中，在 **Subscriptions** (訂閱) 欄中選擇 **\$1aws/things/mySimulatedThing/shadow/name/simShadow1/update/delta**。如果主題名稱被截斷，您可以暫停以查看完整主題。在本主題的主題記錄中，您應會看到類似此訊息的 `/delta` 訊息。

```
{
  "version": 4,
  "timestamp": 1591141596,
  "state": {
    "ColorRGB": [
      255,
      255,
      0
    ]
  },
  "metadata": {
    "ColorRGB": [
      {
        "timestamp": 1591141596
      },
      {
        "timestamp": 1591141596
      },
      {
        "timestamp": 1591141596
      }
    ]
  },
  "clientToken": "21b21b21-bfd2-4279-8c65-e2f697ff4fab"
}
```

您的裝置會處理此訊息的內容，以將裝置狀態設定為符合訊息中的 `desired` 狀態。

裝置更新狀態以符合訊息中的`desired`狀態後，必須透過 AWS IoT 發佈更新訊息將新的報告狀態傳回 。此程序會在 **MQTT 用戶端**中模擬這個部分。

**從裝置更新影子**

1. 於 **MQTT 用戶端** 中，選擇 **Publish to a topic (發佈至主題)**。

1. 在訊息內文視窗的訊息內文視窗上方的主題欄位中，輸入影子的主題，接著輸入 `/update` 動作：`$aws/things/mySimulatedThing/shadow/name/simShadow1/update`，並在訊息內文中輸入此更新的影子文件，其中說明裝置的目前狀態。選擇 **Publish** (發佈)，發佈更新的裝置狀態。

   ```
   {
     "state": {
       "reported": {
         "ColorRGB": [255,255,0]
         }
     },
     "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
   }
   ```

   如果成功收到訊息 AWS IoT，您應該會在 **MQTT 用戶端**的 **\$1aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted** 訊息日誌中看到新的回應，其中包含影子的目前狀態，例如此範例。

   ```
   {
     "state": {
       "reported": {
         "ColorRGB": [
           255,
           255,
           0
         ]
       }
     },
     "metadata": {
       "reported": {
         "ColorRGB": [
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           }
         ]
       }
     },
     "version": 5,
     "timestamp": 1591142747,
     "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
   }
   ```

成功更新回報的裝置狀態，也會導致 AWS IoT 將訊息中影子狀態的完整描述傳送至`update/documents`主題，例如由裝置在上述程序中執行的影子更新所產生的此訊息內文。

```
{
  "previous": {
    "state": {
      "desired": {
        "ColorRGB": [
          255,
          255,
          0
        ]
      },
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          128,
          128,
          128
        ]
      }
    },
    "metadata": {
      "desired": {
        "ColorRGB": [
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          }
        ]
      },
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          }
        ]
      }
    },
    "version": 4
  },
  "current": {
    "state": {
      "desired": {
        "ColorRGB": [
          255,
          255,
          0
        ]
      },
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          255,
          255,
          0
        ]
      }
    },
    "metadata": {
      "desired": {
        "ColorRGB": [
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          }
        ]
      },
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591142747
          },
          {
            "timestamp": 1591142747
          },
          {
            "timestamp": 1591142747
          }
        ]
      }
    },
    "version": 5
  },
  "timestamp": 1591142747,
  "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
}
```

## 觀察應用程式中的更新
<a name="using-device-shadows-view-result"></a>

應用程式現在可以查詢裝置報告的目前狀態的影子。

**使用 取得影子的目前狀態 AWS CLI**

1. 在命令列輸入此命令：

   ```
   aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 /dev/stdout
   ```

   在 Windows 平台上，您可使用 `con`，而非 `/dev/stdout`。

   ```
   aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 con
   ```

1. 因為裝置剛剛更新影子，以反映其目前的狀態，所以應該傳回下列影子文件。

   ```
   {
     "state": {
       "desired": {
         "ColorRGB": [
           255,
           255,
           0
         ]
       },
       "reported": {
         "ID": "SmartLamp21",
         "ColorRGB": [
           255,
           255,
           0
         ]
       }
     },
     "metadata": {
       "desired": {
         "ColorRGB": [
           {
             "timestamp": 1591141596
           },
           {
             "timestamp": 1591141596
           },
           {
             "timestamp": 1591141596
           }
         ]
       },
       "reported": {
         "ID": {
           "timestamp": 1591140517
         },
         "ColorRGB": [
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           }
         ]
       }
     },
     "version": 5,
     "timestamp": 1591143269
   }
   ```

## 超越模擬
<a name="using-device-shadows-next-steps"></a>

試驗 AWS CLI (代表應用程式) 與主控台 (代表裝置) 之間的互動，以建立 IoT 解決方案的模型。