

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

# 在裝置中使用 AWS IoT MQTT 型檔案交付
<a name="mqtt-based-file-delivery-in-devices"></a>

如要啟動資料傳輸程序，裝置必須接收**初始資料集**，其至少包含串流 ID。在任務文件中含括初始資料集，您可使用 [AWS IoT 任務](iot-jobs.md) 來排程裝置的資料傳輸任務。當裝置收到初始資料集時，應該開始與以 AWS IoT MQTT 為基礎的檔案交付互動。若要與 AWS IoT MQTT 型檔案交付交換資料，裝置應該：
+ 使用 MQTT 通訊協定來訂閱 [MQTT 型檔案交付主題](reserved-topics.md#reserved-topics-mqtt-based-file-delivery)。
+ 使用 MQTT 訊息傳送請求，然後等待接收回應。

您可選擇性地在初始資料集中包含串流檔案 ID 和串流版本。將串流檔案 ID 傳送至裝置可簡化裝置韌體/軟體的程式設計，因為其不需要提出 `DescribeStream` 請求來取得此 ID。裝置可指定 `GetStream` 請求中的串流版本，強制執行一致性檢查，以防串流意外更新。

## 使用 DescribeStream 以取得串流資料
<a name="mqtt-based-file-delivery-describe-stream"></a>

AWS IoT 以 MQTT 為基礎的檔案交付提供將串流資料傳送至裝置的 `DescribeStream` API。此 API 傳回的串流資料包括串流 ID、串流版本、串流說明和串流檔案清單，每個檔案都有一個檔案 ID 和檔案大小 (以位元組為單位)。裝置可利用此資訊來選取任意檔案以啟動資料傳輸程序。

**注意**  
若您的裝置在初始資料集中收到所有必要的串流檔案 ID，您無須使用 `DescribeStream` API。

請依照下列步驟提出 `DescribeStream` 請求。

1. 訂閱「已接受」主題篩選條件 `$aws/things/ThingName/streams/StreamId/description/json`。

1. 訂閱「已拒絕」主題篩選條件 `$aws/things/ThingName/streams/StreamId/rejected/json`。

1. 將訊息傳送至 `$aws/things/ThingName/streams/StreamId/describe/json` 來發佈 `DescribeStream` 請求。

1. 若接受該請求，您的裝置將會在「已接受」主題篩選條件上收到 `DescribeStream` 回應。

1. 若請求遭到拒絕，您的裝置將會在「已拒絕」主題篩選條件上收到錯誤回應。

**注意**  
若您在顯示的主題和主題篩選條件中將 `json` 替換為 `cbor`，您的裝置將會收到 CBOR 格式的訊息，這比 JSON 更精簡。

### DescribeStream 請求
<a name="mqtt-based-file-delivery-describe-stream-request"></a>

JSON 中的典型 `DescribeStream` 請求看起來會如下列範例所示。

```
{
    "c": "ec944cfb-1e3c-49ac-97de-9dc4aaad0039"
}
```
+ (選用) "`c`" 為用戶端字符欄位。

  用戶端字符不可超過 64 個位元組。長於 64 個位元組的用戶端字符會造成錯誤回應及 `InvalidRequest` 錯誤訊息。

### DescribeStream 回應
<a name="mqtt-based-file-delivery-describe-stream-response"></a>

JSON 中的 `DescribeStream` 回應看起來會如下列範例所示。

```
{
    "c": "ec944cfb-1e3c-49ac-97de-9dc4aaad0039",
    "s": 1,
    "d": "This is the description of stream ABC.",
    "r": [
        {
            "f": 0,
            "z": 131072
        },
        {
            "f": 1,
            "z": 51200
        }
    ]
}
```
+ "`c`" 為用戶端字符欄位。若其提供於 `DescribeStream` 請求中，則會傳回。使用用戶端字符，使回應與其請求產生關聯。
+ "`s`" 是整數形式的串流版本。您可使用此版本，對您的 `GetStream` 請求執行一致性檢查。
+ "`r`" 包含串流中的一份檔案清單。
  + "`f`" 是整數形式的串流檔案 ID。
  + "`z`" 是以位元組數為單位的串流檔案大小。
+ "`d`" 包含串流的說明。

## 從串流檔案取得資料區塊
<a name="mqtt-based-file-delivery-get-getstream"></a>

您可使用 `GetStream` API，裝置便可接收小型資料區塊形式的串流檔案，因此其可供處理大型區塊大小有限制的裝置使用。如要接收整個資料檔案，裝置可能需要傳送或接收多個請求和回應，直至所有資料區塊已接收並加以處理為止。

### GetStream 請求
<a name="mqtt-based-file-delivery-getstream-request"></a>

請依照下列步驟提出 `GetStream` 請求。

1. 訂閱「已接受」主題篩選條件 `$aws/things/ThingName/streams/StreamId/data/json`。

1. 訂閱「已拒絕」主題篩選條件 `$aws/things/ThingName/streams/StreamId/rejected/json`。

1. 將 `GetStream` 請求發佈至主題 `$aws/things/ThingName/streams/StreamId/get/json`。

1. 若接受該請求，您的裝置將會在「已接受」主題篩選條件上收到一個或多個 `GetStream` 回應。每個回應訊息包含一個單一區塊的基本資訊和資料承載。

1. 重複步驟 3 和 4，以接收所有資料區塊。若請求的資料量大於 128 KB，您必須重複這些步驟。您必須設定裝置的程式，來使用多個 `GetStream` 請求，以接收所有請求的資料。

1. 若請求遭到拒絕，您的裝置將會在「已拒絕」主題篩選條件上收到錯誤回應。

**注意**  
若您在顯示的主題和主題篩選條件中將 "json" 替換為 "cbor"，您的裝置將會收到 CBOR 格式的訊息，這比 JSON 更精簡。
AWS IoT 以 MQTT 為基礎的檔案交付會將區塊的大小限制為 128 KB。若您對超過 128 KB 的區塊提出請求，請求將會失敗。
您可對總大小大於 128 KB 的多個區塊提出請求 (例如，若您對總量為 160 KB 的資料提出 5 個區塊 (每個區塊 32 KB) 的請求)。在這種情況下，請求不會失敗，但您的裝置必須提出多個請求才能接收所有請求的資料。當您的裝置提出其他請求時，服務會傳送其他區塊。我們建議您僅於正確接收並處理先前的回應之後，才可繼續進行新的請求。
無論所請求的資料大小總量為何，您都應該將裝置設定為在未收到區塊或未正確收到區塊時啟動重試。

JSON 中的典型 `GetStream` 請求看起來會如下列範例所示。

```
{
    "c": "1bb8aaa1-5c18-4d21-80c2-0b44fee10380",
    "s": 1,
    "f": 0,
    "l": 4096,
    "o": 2,
    "n": 100,
    "b": "..."
}
```
+ [選用] "`c`" 為用戶端字符欄位。

  用戶端字符不能超過 64 位元組。長於 64 個位元組的用戶端字符會造成錯誤回應及 `InvalidRequest` 錯誤訊息。
+ [選用] "`s`" 為串流版本欄位 (一個整數)。

  MQTT 型檔案交付會依據此請求的版本和雲端中的最新串流版本套用一致性檢查。若從 `GetStream` 請求中的裝置傳送的串流版本與雲端中最新串流版本不相符，則服務會傳送錯誤回應及 `VersionMismatch` 錯誤訊息。一般而言，裝置會在初始資料集或 `DescribeStream` 的回應中接收預期的 (最新的) 串流版本。
+ "`f`" 是串流檔案 ID (範圍為 0 到 255 的整數)。

  當您使用 或 SDK 建立 AWS CLI 或更新串流時，需要串流檔案 ID。若裝置請求 ID 不存在的串流檔案，則服務會傳送錯誤回應和 `ResourceNotFound` 錯誤訊息。
+ "`l`" 為以位元組為單位的資料區塊大小 (範圍為 256 到 131,072 的整數)。

  請參閱 [建置 GetStream 請求的點陣圖](#mqtt-based-file-delivery-build-a-bitmap)，以取得有關如何使用點陣圖欄位來指定 `GetStream` 回應中將會傳回之串流檔案部分的說明。若裝置指定一個超出範圍的區塊大小，則服務會傳送錯誤回應和 `BlockSizeOutOfBounds` 錯誤訊息。
+ [選用] "`o`" 為串流檔案中區塊的偏移量 (範圍為 0 到 98,304 的整數)。

  請參閱 [建置 GetStream 請求的點陣圖](#mqtt-based-file-delivery-build-a-bitmap)，以取得有關如何使用點陣圖欄位來指定 `GetStream` 回應中將會傳回之串流檔案部分的說明。98,304 的最大值是以 24 MB 串流檔案大小限制為基礎，最小區塊大小為 256 個位元組。若未指定，則預設值為 0。
+ [選用] "`n`" 為請求的區塊數量 (範圍為 0 到 98,304 的整數)。

  "n" 欄位指定 (1) 請求的區塊數量，或 (2) 使用點陣圖欄位 ("b") 時，點陣圖請求將會傳回區塊數量的限制。此第二次使用是可選的。若未定義，其預設為 131072/*DataBlockSize*。
+ [選用] "`b`" 是個代表所請求區塊的點陣圖。

  使用點陣圖，您的裝置可以請求不連續的區塊，這使得在錯誤後處理重試更為方便。請參閱 [建置 GetStream 請求的點陣圖](#mqtt-based-file-delivery-build-a-bitmap)，以取得有關如何使用點陣圖欄位來指定 `GetStream` 回應中將會傳回之串流檔案部分的說明。對此欄位，請將點陣圖轉換為以十六進記法表示點陣圖值的字串。點陣圖必須小於 12,288 個位元組。

**重要**  
應指定 "`n`" 或 "`b`"。如果未指定，當檔案大小小於 131072 位元組 (128 KB) 時，`GetStream` 請求可能無效。

### GetStream 回應
<a name="mqtt-based-file-delivery-getstream-response"></a>

對於請求的每個資料區塊，JSON 中的 `GetStream` 回應看似此範例。

```
{
    "c": "1bb8aaa1-5c18-4d21-80c2-0b44fee10380",
    "f": 0,
    "l": 4096,
    "i": 2,
    "p": "..."
}
```
+ "`c`" 為用戶端字符欄位。若其提供於 `GetStream` 請求中，則會傳回。使用用戶端字符，使回應與其請求產生關聯。
+ "`f`" 為目前資料區塊承載所屬串流檔案的 ID。
+ "`l`" 為資料區塊承載的大小 (以位元組為單位)。
+ "`i`" 為包含於承載中的資料區塊 ID。資料區塊的編號從 0 開始。
+ "`p`" 包含資料區塊承載。此欄位是一個字串，表示以 [Base64](https://en.wikipedia.org/wiki/Base64) 編碼的資料區塊值。

### 建置 GetStream 請求的點陣圖
<a name="mqtt-based-file-delivery-build-a-bitmap"></a>

您可使用 `GetStream` 請求中的點陣圖欄位 (`b`)，從串流檔案獲取非連續區塊。此有助於 RAM 容量有限的裝置處理網路交付問題。裝置僅能請求那些未接收或未正確接收的區塊。點陣圖決定將會傳回的串流檔案區塊。對於點陣圖中設定為 1 的每個位元，會傳回串流檔案相對應的區塊。

下列範例說明如何在 `GetStream` 請求中指定點陣圖及其支援欄位。例如，您想要以 256 個位元組 (區塊大小) 的區塊接收串流檔案。將每個 256 個位元組的區塊視為具有一個數字，指定其在檔案中的位置，從 0 開始。所以區塊 0 是檔案中第一個 256 個位元組的區塊，區塊 1 是第二個區塊，依此類推。您想要從該檔案請求區塊 20、21、24 和 43。

**區塊偏移**  
因為第一個區塊為數字 20，請指定偏移 (欄位 `o`) 為 20 以節省點陣圖中的空間。

**區塊的數量**  
為確保您的裝置不會收到超過其在有限記憶體資源下可處理的區塊數，您可指定 MQTT 型檔案交付傳送的每則訊息中應傳回的區塊數量上限。請注意，若點陣圖本身指定的區塊數量小於此數，或者其讓 MQTT 型檔案交付傳送的回應訊息總大小大於每個 `GetStream` 請求 128 KB 的服務限制，則會忽略此值。

**區塊點陣圖**  
點陣圖本身是一個以十六進記法表示的無符號位元組陣列，包含於 `GetStream` 請求中作為數字的字串表示。但若要建構此字串，讓我們先將點陣圖視為一長串的位元 (二進制數)。若在此序列中的某個位元設定為 1，則串流檔案相對應的區塊將會傳送回裝置。對於我們的範例，我們想要接收區塊 20、21、24 和 43，因此我們必須在點陣圖中設定位元 20、21、24 和 43。我們可以使用區塊偏移來節省空間，因此在我們從每個區塊減去偏移量之後，我們要設定位元 0、1、4 和 23，如下列範例所示。  

```
 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 
```
一次取一個位元組 (8 位元)，這通常會寫成："0b00010011"、"0b00000000" 和 "0b10000000"。位元 0 出現在我們的二進製表示中的第一個位元組末尾，位元 23 出現在最後一個位元組的開頭。除非您知道慣例，否則這可能會令人困擾。第一個位元組包含位元 7-0 (依該順序)，第二個位元組包含位元 15-8，第三個位元組包含位元 23-16，依此類推。於十六進記法中，此會轉換為 "0x130080"。  
您可將標準二進制轉換為十六進記法。一次取四個二進制數字，並將其轉換為相對應的十六進制。例如，"0001" 變成 "1"，"0011" 變成 "3" 等等。

![\[在 GetStream 請求中建構字串的區塊點陣圖明細。\]](http://docs.aws.amazon.com/zh_tw/iot/latest/developerguide/images/blockBitmap.png)

綜上所述，我們 `GetStream` 請求的 JSON 如下所示。  

```
{
    "c" : "1",       
    "s" : 1,         
    "l" : 256,       
    "f" : 1,         
    "o" : 20,        
    "n" : 32,       
    "b" : "130080"
}
```
+ "`c`" 為用戶端字符欄位。
+ 「`s`」是預期串流版本。
+ "`l`" 為資料區塊承載的大小 (以位元組為單位)。
+ 「`f`」是來源檔案索引的 ID。
+ 「`o`」是區塊位移。
+ 「`n`」是區塊數量。
+ 「`b`」是從位移開始遺失的區塊點陣圖。此值必須是 based64 編碼。

## 處理 AWS IoT MQTT 型檔案交付的錯誤
<a name="mqtt-based-file-delivery-errors"></a>

對 `DescribeStream` 和 `GetStream` 兩個 API 傳送至裝置的錯誤回應包含用戶端字符、錯誤碼及錯誤訊息。典型的錯誤回應看似下列範例所示。

```
{
    "o": "BlockSizeOutOfBounds", 
    "m": "The block size is out of bounds", 
    "c": "1bb8aaa1-5c18-4d21-80c2-0b44fee10380" 
}
```
+ "`o`" 為指出錯誤發生原因的錯誤代碼。如需詳細資訊，請參閱本節稍後的錯誤碼。
+ "`m`" 為包含錯誤詳細資料的錯誤訊息。
+ "`c`" 為用戶端字符欄位。若其提供於 `DescribeStream` 請求中，則可能會傳回。您可使用用戶端字符，使回應與其請求產生關聯。

  用戶端字符欄位不一定會包含在錯誤回應中。當提供於請求中的用戶端字符無效或格式錯誤時，其不會傳回錯誤回應。

**注意**  
若為回溯相容性，錯誤回應中的欄位可能為非縮寫形式。例如，錯誤代碼可能由「代碼」或 "o" 欄位進行指定，用戶端字符欄位可由 "clientToken" 或 "c" 欄位進行指定。我們建議您使用上述縮寫形式。

**InvalidTopic**  
串流訊息的 MQTT 主題是無效的。

**InvalidJson**  
串流請求不是一個有效的 JSON 文件。

**InvalidCbor**  
串流請求不是有效的 CBOR 文件。

**InvalidRequest**  
該請求通常被標識為格式錯誤。如需詳細資訊，請參閱錯誤訊息。

**未經授權**  
該請求無權存取儲存媒體 (例如 Amazon S3) 中的串流資料檔案。如需詳細資訊，請參閱錯誤訊息。

**BlockSizeOutOfBounds**  
區塊大小超出範圍。請參閱 [AWS IoT Core Service Quotas](https://docs.aws.amazon.com//general/latest/gr/iot-core.html#limits_iot) 中的「**MQTT 型檔案交付**」一節。

**OffsetOutOfBounds**  
偏移超出範圍。請參閱 [AWS IoT Core Service Quotas](https://docs.aws.amazon.com//general/latest/gr/iot-core.html#limits_iot) 中的「**MQTT 型檔案交付**」一節。

**BlockCountLimitExceeded**  
請求區塊的數量超出範圍。請參閱 [AWS IoT Core Service Quotas](https://docs.aws.amazon.com//general/latest/gr/iot-core.html#limits_iot) 中的「**MQTT 型檔案交付**」一節。

**BlockBitmapLimitExceeded**  
請求點陣圖的大小超出範圍。請參閱 [AWS IoT Core Service Quotas](https://docs.aws.amazon.com//general/latest/gr/iot-core.html#limits_iot) 中的「**MQTT 型檔案交付**」一節。

**ResourceNotFound**  
找不到請求的串流、檔案、檔案版本或區塊。如需詳細資訊，請參閱錯誤訊息。

**VersionMismatch**  
請求中的串流版本與 MQTT 型檔案交付功能中的串流版本不相符。這表示自裝置最初接收串流版本以來，串流資料已遭修改。

**ETagMismatch**  
串流中的 S3 ETag 與最新 S3 物件版本的 ETag 不相符。

**InternalError**  
於 MQTT 型檔案交付時發生內部錯誤。