

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

# 教學課程：使用 FreeRTOS 低功耗藍牙在 Espressif ESP32 上執行 OTA 更新
<a name="ota-updates-esp32-ble"></a>

**重要**  <a name="deprecation-message"></a>
此參考整合託管在已棄用的 Amazon-FreeRTOS 儲存庫上。我們建議您在建立新專案時從[這裡開始](freertos-getting-started-modular.md)。如果您已經有以現在已棄用的 Amazon-FreeRTOS 儲存庫為基礎的現有 FreeRTOS 專案，請參閱 [Amazon-FreeRTOS Github 儲存庫遷移指南](github-repo-migration.md)。 FreeRTOS 

本教學課程說明如何更新連接到 Android 裝置上 MQTT 低功耗藍牙代理的 Espressif ESP32 微控制器。它使用 AWS IoT Over-the-air(OTA) 更新任務來更新裝置。裝置 AWS IoT 會使用 Android 示範應用程式中輸入的 Amazon Cognito 登入資料連線至 。授權的操作員會從雲端啟動 OTA 更新。當裝置透過 Android 示範應用程式連線時，會啟動 OTA 更新，並在裝置上更新韌體。

FreeRTOS 版本 2019.06.00 主要和更新版本包含低功耗藍牙 MQTT 代理支援，可用於 Wi-Fi 佈建和 AWS IoT 服務的安全連線。透過使用低功耗藍牙功能，您可以建置低功耗裝置，這些裝置可以與行動裝置配對以進行連線，而不需要 Wi-Fi。裝置可以透過使用一般存取設定檔 (GAP) 和一般屬性 (GATT) 設定檔的 Android 或 iOS SDKs 連線，使用 MQTT 進行通訊。

以下是我們將遵循的步驟，以允許透過低功耗藍牙進行 OTA 更新：

1. **設定儲存：**建立 Amazon S3 儲存貯體和政策，並設定可執行更新的使用者。

1. **建立程式碼簽署憑證：**建立簽署憑證並允許使用者簽署韌體更新。

1. **設定 Amazon Cognito 身分驗證：**建立登入資料提供者、使用者集區和使用者集區的應用程式存取權。

1. **設定 FreeRTOS：**設定低功耗藍牙、用戶端憑證和程式碼簽署公有憑證。

1. **設定 Android 應用程式：**設定登入資料提供者、使用者集區，並將應用程式部署到 Android 裝置。

1. **執行 OTA 更新指令碼：**若要啟動 OTA 更新，請使用 OTA 更新指令碼。

如需更新運作方式的詳細資訊，請參閱 [FreeRTOS Over-the-Air更新](freertos-ota-dev.md)。如需如何設定低功耗藍牙 MQTT 代理功能的詳細資訊，請參閱 文章，[文章使用低功耗藍牙搭配 Espressif ESP32 上的 FreeRTOS](https://aws.amazon.com/blogs/iot/using-bluetooth-low-energy-with-amazon-freertos-on-espressif-esp32/)，作者為 Richard Kang。

## 先決條件
<a name="ota-updates-esp32-ble-prereq"></a>

若要執行本教學課程中的步驟，您需要下列資源：
+ ESP32 開發板。
+ MicroUSB 轉 USB A 纜線。
+  AWS 帳戶 （免費方案已足夠）。
+ 具有 Android v 6.0 或更新版本和藍牙 4.2 或更新版本的 Android 手機。

在您的開發電腦上，您需要：
+ Xtensa 工具鏈和 FreeRTOS 原始程式碼和範例有足夠的磁碟空間 (\~500 Mb)。
+ 已安裝 Android Studio。
+ [AWS CLI](https://aws.amazon.com/cli/) 已安裝 。
+ Python3 已安裝。
+ 適用於 [Python 的 boto3 AWS Software 開發人員套件 (SDK)](https://github.com/boto/boto3)。

本教學課程中的步驟假設 Xtensa 工具鏈、ESP-IDF 和 FreeRTOS 程式碼安裝在主`/esp`目錄中的 目錄中。您必須將 `~/esp/xtensa-esp32-elf/bin` 新增至`$PATH`變數。

## 步驟 1：設定儲存體
<a name="ota-updates-esp32-ble-step1"></a>

1. [建立 Amazon S3 儲存貯體以存放您的更新](dg-ota-bucket.md) 啟用版本控制以保留韌體映像。

1. [建立 OTA 更新服務角色](create-service-role.md) 並將下列 受管政策新增至角色：
   + AWSIotLogging
   + AWSIotRuleActions
   + AWSIotThingsRegistration
   + AWSFreeRTOSOTAUpdate

1. [建立可執行 OTA 更新的使用者](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html)。此使用者可以在帳戶中簽署和部署韌體更新至 IoT 裝置，並有權在所有裝置上執行 OTA 更新。存取權應僅限於信任的實體。

1. 請遵循 的步驟，[建立 OTA 使用者政策](create-ota-user-policy.md)並將其連接到您的使用者。

## 步驟 2：建立程式碼簽署憑證
<a name="ota-updates-esp32-ble-step2"></a>

1. 建立已啟用版本控制以保留韌體映像的 Amazon S3 儲存貯體。

1. 建立可用於簽署韌體的程式碼簽署憑證。匯入憑證時，請注意憑證 Amazon Resource Name (ARN)。

   ```
   aws acm import-certificate --profile=ota-update-user --certificate file://ecdsasigner.crt --private-key file://ecdsasigner.key
   ```

   輸出範例：

   ```
   {
   "CertificateArn": "arn:aws:acm:us-east-1:<account>:certificate/<certid>"
   }
   ```

   稍後您將使用 ARN 來建立簽署設定檔。如果需要，您現在可以使用下列命令建立設定檔：

   ```
   aws signer put-signing-profile --profile=ota-update-user --profile-name esp32Profile --signing-material certificateArn=arn:aws:acm:us-east-1:{{account}}:certificate/{{certid}} --platform AmazonFreeRTOS-Default --signing-parameters certname=/cert.pem
   ```

   輸出範例：

   ```
   {
   "arn": "arn:aws:signer::<account>:/signing-profiles/esp32Profile"
   }
   ```

## 步驟 3：Amazon Cognito 身分驗證組態
<a name="ota-updates-esp32-ble-step3"></a>

**建立 AWS IoT 政策**

1. 登入 [AWS IoT 主控台](https://console.aws.amazon.com/iot/)。

1. 在主控台的右上角，選擇**我的帳戶**。在**帳戶設定**下，記下您的 12 位數帳戶 ID。

1. 在左側的導覽窗格中，選擇**設定**。在**裝置資料端點**中，記下端點值。端點應該類似 `xxxxxxxxxxxxxx.iot.us-west-2.amazonaws.com`。在此範例中， AWS 區域為「us-west-2」。

1. 在左側導覽窗格中，選擇**安全**，選擇**政策**，然後選擇**建立**。如果您的帳戶中沒有任何政策，您會看到「您還沒有任何政策」訊息，您可以選擇**建立政策**。

1. 輸入政策的名稱，例如 "esp32\_mqtt\_proxy\_iot\_policy"。

1. 在 **Add statements (新增陳述式)** 區段中，選擇 **Advanced mode (進階模式)**。將下列 JSON 複製並貼入政策編輯器視窗。`aws-account-id` 將 取代為您的帳戶 ID，並將 `aws-region`取代為區域 （例如 "us-west-2")。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "iot:Connect",
               "Resource": "arn:aws:iot:{{us-east-1}}:{{123456789012}}:*"
           },
           {
               "Effect": "Allow",
               "Action": "iot:Publish",
               "Resource": "arn:aws:iot:{{us-east-1}}:{{123456789012}}:*"
           },
           {
               "Effect": "Allow",
               "Action": "iot:Subscribe",
               "Resource": "arn:aws:iot:{{us-east-1}}:{{123456789012}}:*"
           },
           {
               "Effect": "Allow",
               "Action": "iot:Receive",
               "Resource": "arn:aws:iot:{{us-east-1}}:{{123456789012}}:*"
           }
       ]
   }
   ```

------

1. 選擇**建立**。

**建立 AWS IoT 物件**

1. 登入 [AWS IoT 主控台](https://console.aws.amazon.com/iot/)。

1. 在左側導覽窗格中，選擇 **Manage (管理)**，然後選擇 **Things (實物)**。

1. 在右上角，選擇**建立**。如果您的帳戶中沒有註冊任何物件，則會顯示「您還沒有任何物件」訊息，您可以選擇**註冊物件**。

1. 在**建立 AWS IoT 物件**頁面上，選擇**建立單一物件**。

1. 在**將裝置新增至物件登錄**檔頁面上，輸入物件的名稱 （例如，"esp32-ble")。僅允許英數字元、連字號 (-) 和底線 (\_) 字元。選擇**下一步**。

1. 在**新增實物的憑證**頁面上，**在略過憑證並建立實物**下，選擇**建立不含憑證的實物**。由於我們使用使用 Amazon Cognito 憑證進行身分驗證和授權的 BLE 代理行動應用程式，因此不需要裝置憑證。

**建立 Amazon Cognito 應用程式用戶端**

1. 登入 [Amazon Cognito 主控台](https://console.aws.amazon.com/cognito/users/)。

1. 在右上角導覽橫幅中，選擇**建立使用者集區**。

1. 輸入集區名稱 （例如 "esp32\_mqtt\_proxy\_user\_pool")。

1. 選擇 **Review defaults** (檢閱預設值)。

1. 在**應用程式用戶端**中，選擇**新增應用程式用戶端**，然後選擇**新增應用程式用戶端**。

1. 輸入應用程式用戶端名稱 （例如 "mqtt\_app\_client")。

1. 確定已選取**產生用戶端秘密**。

1. 選擇 **Create app client (建立應用程式用戶端)**。

1. 選擇 **Return to pool details (回到集區的詳細資訊)**。

1. 在使用者集區的**檢閱**頁面上，選擇**建立集區**。您應該會看到一則訊息，指出「您的使用者集區已成功建立。」 記下集區 ID。

1. 在導覽窗格中，選擇**應用程式用戶端**。

1. 選擇**顯示詳細資訊**。記下應用程式用戶端 ID 和應用程式用戶端秘密。

**建立 Amazon Cognito 身分集區**

1. 登入 [Amazon Cognito 主控台](https://console.aws.amazon.com/cognito/federated)。

1. 選擇 **Create new identity pool** (建立新的身分池)。

1. 輸入身分集區的名稱 （例如 "mqtt\_proxy\_identity\_pool")。

1. 展開**身分驗證提供者**。

1. 選擇 **Cognito** 標籤。

1. 輸入您在先前步驟中記下的使用者集區 ID 和應用程式用戶端 ID。

1. 選擇 **Create Pool** (建立集區)。

1. 在下一頁中，若要為已驗證和未驗證的身分建立新的角色，請選擇**允許**。

1. 請記下身分集區 ID，其格式為 `us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`。

**將 IAM 政策連接至已驗證的身分**

1. 開啟 Amazon Cognito [主控台](https://console.aws.amazon.com/cognito/federated)。

1. 選取您剛建立的身分集區 （例如 "mqtt\_proxy\_identity\_pool")。

1. 選擇 **Edit identity pool (編輯身分集區)**。

1. 記下指派給已驗證角色的 IAM 角色 （例如，「Cognito\_mqtt\_proxy\_identity\_poolAuth\_Role」)。

1. 開啟 [ IAM 主控台](https://console.aws.amazon.com/iam/home)。

1. 在導覽窗格中，選擇 **Roles** (角色)。

1. 搜尋指派的角色 （例如，「Cognito\_mqtt\_proxy\_identity\_poolAuth\_Role」)，然後選取該角色。

1. 選擇**新增內嵌政策**，然後選擇 **JSON**。

1. 輸入下列政策：

------
#### [ JSON ]

****  

   ```
   {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
          {
             "Effect": "Allow",
             "Action": [
                "iot:AttachPolicy",
                "iot:AttachPrincipalPolicy",
                "iot:Connect",
                "iot:Publish",
                "iot:Subscribe"
             ],
             "Resource": "*"
          }]
       }
   ```

------

1. 選擇**檢閱政策**。

1. 輸入政策名稱 （例如，"mqttProxyCognitoPolicy")。

1. 選擇**建立政策**。

## 步驟 4：設定 Amazon FreeRTOS
<a name="ota-updates-esp32-ble-step4"></a>

1. 從 Amazon FreeRTOS [FreeRTOS GitHub ](https://github.com/aws/amazon-freertos)程式碼。

1. 若要啟用 OTA 更新示範，請遵循中的步驟[Espressif ESP32-DevKitC 和 ESP-WROVER-KIT 入門](getting_started_espressif.md)。

1. 在下列檔案中進行這些額外的修改：

   1. 開啟`vendors/espressif/boards/esp32/aws_demos/config_files/aws_demo_config.h`並定義 `CONFIG_OTA_UPDATE_DEMO_ENABLED`。

   1. 開啟 `vendors/espressif/boards/esp32/aws_demos/common/config_files/aws_demo_config.h`並`democonfigNETWORK_TYPES`變更為 `AWSIOT_NETWORK_TYPE_BLE`。

   1. 開啟 `demos/include/aws_clientcredential.h`並輸入 的端點 URL`clientcredentialMQTT_BROKER_ENDPOINT`。

      輸入 的物件名稱 `clientcredentialIOT_THING_NAME`（例如，"esp32-ble")。當您使用 Amazon Cognito 憑證時，不需要新增憑證。

   1. 開啟 `vendors/espressif/boards/esp32/aws_demos/config_files/aws_iot_network_config.h`並變更 `configENABLED_NETWORKS` `configSUPPORTED_NETWORKS`，並只包含 `AWSIOT_NETWORK_TYPE_BLE`。

   1. 開啟 `vendors/{{vendor}}/boards/{{board}}/aws_demos/config_files/ota_demo_config.h` 檔案，然後輸入您的憑證。

      ```
      #define otapalconfigCODE_SIGNING_CERTIFICATE [] = "{{your-certificate-key}}";
      ```

   應用程式應該啟動並列印示範版本：

   ```
   11 13498 [iot_thread] [INFO ][DEMO][134980] Successfully initialized the demo. Network type for the demo: 2
   12 13498 [iot_thread] [INFO ][MQTT][134980] MQTT library successfully initialized.
   13 13498 [iot_thread] OTA demo version 0.9.20
   14 13498 [iot_thread] Creating MQTT Client...
   ```

## 步驟 5：設定 Android 應用程式
<a name="ota-updates-esp32-ble-step5"></a>

1. 從 [amazon-freertos-ble-android-sdk](https://github.com/aws/amazon-freertos-ble-android-sdk) GitHub 儲存庫下載 Android 低功耗藍牙 SDK 和範例應用程式。

1. 開啟 檔案`app/src/main/res/raw/awsconfiguration.json`，並使用下列 JSON 範例中的指示填入集區 ID、區域、AppClientId 和 AppClientSecret。

   ```
   {
     "UserAgent": "MobileHub/1.0",
     "Version": "1.0",
     "CredentialsProvider": {
       "CognitoIdentity": {
         "Default": {
           "PoolId": "{{Cognito->Manage Identity Pools->Federated Identities->mqtt_proxy_identity_pool->Edit Identity Pool->Identity Pool ID}}",
           "Region": "{{Your region (for example us-east-1)}}"
         }
       }
     },
   
     "IdentityManager": {
       "Default": {}
     },
   
     "CognitoUserPool": {
       "Default": {
         "PoolId": "{{Cognito-> Manage User Pools -> esp32_mqtt_proxy_user_pool -> General Settings -> PoolId}}",
         "AppClientId": "{{Cognito-> Manage User Pools -> esp32_mqtt_proxy_user_pool -> General Settings -> App clients ->Show Details}}",
         "AppClientSecret": "{{Cognito-> Manage User Pools -> esp32_mqtt_proxy_user_pool -> General Settings -> App clients ->Show Details}}",
         "Region": "{{Your region (for example us-east-1)}}"
       }
     }
   }
   ```

1. 開啟`app/src/main/java/software/amazon/freertos/DemoConstants.java`並輸入您先前建立的政策名稱 （例如 {{esp32\_mqtt\_proxy\_iot\_policy}}) 以及區域 （例如 {{us-east-1}})。

1. 建置並安裝 示範應用程式。

   1. 在 Android Studio 中，選擇**建置**，然後選擇**製作模組應用程式**。

   1. 選擇**執行**，然後選擇**執行應用程式**。您可以前往 Android Studio 中的 logcat 視窗窗格來監控日誌訊息。

   1. 在 Android 裝置上，從登入畫面建立 帳戶。

   1. 建立使用者。如果使用者已存在，請輸入登入資料。

   1. 允許 Amazon FreeRTOS 示範存取裝置的位置。

   1. 掃描低功耗藍牙裝置。

   1. 將找到之裝置的滑桿移至**開啟**。

   1. 在 ESP32 的序列連接埠偵錯主控台上按 **y**。

   1. 選擇**配對 & Connect**。

1. 建立連線後，**更多...**連結會變成作用中。連線完成時，Android 裝置 logcat 中的連線狀態應變更為「BLE\_CONNECTED」：

   ```
   2019-06-06 20:11:32.160 23484-23497/software.amazon.freertos.demo I/FRD: BLE connection state changed: 0; new state: BLE_CONNECTED
   ```

1. 在傳輸訊息之前，Amazon FreeRTOS 裝置和 Android 裝置會交涉 MTU。您應該會在 logcat 中看到下列輸出：

   ```
   2019-06-06 20:11:46.720 23484-23497/software.amazon.freertos.demo I/FRD: onMTUChanged : 512 status: Success
   ```

1. 裝置會連線至應用程式，並使用 MQTT Proxy 開始傳送 MQTT 訊息。若要確認裝置可以通訊，請確定 MQTT\_CONTROL 特性資料值變更為 01：

   ```
   2019-06-06 20:12:28.752 23484-23496/software.amazon.freertos.demo D/FRD: <-<-<- Writing to characteristic: MQTT_CONTROL with data: 01
   2019-06-06 20:12:28.839 23484-23496/software.amazon.freertos.demo D/FRD: onCharacteristicWrite for: MQTT_CONTROL; status: Success; value: 01
   ```

1. 配對裝置時，您會在 ESP32 主控台上看到提示。若要啟用 BLE，請按 **y**。除非您執行此步驟，否則示範將無法運作。

   ```
   E (135538) BT_GATT: GATT_INSUF_AUTHENTICATION: MITM Required
   W (135638) BT_L2CAP: l2cble_start_conn_update, the last connection update command still pending.
   E (135908) BT_SMP: Value for numeric comparison = 391840
   15 13588 [InputTask] Numeric comparison:391840
   16 13589 [InputTask] Press 'y' to confirm
   17 14078 [InputTask] Key accepted
   W (146348) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK
   18 16298 [iot_thread] Connecting to broker...
   19 16298 [iot_thread] [INFO ][MQTT][162980] Establishing new MQTT connection.
   20 16298 [iot_thread] [INFO ][MQTT][162980] (MQTT connection 0x3ffd5754, CONNECT operation 0x3ffd586c) Waiting for operation completion.
   21 16446 [iot_thread] [INFO ][MQTT][164450] (MQTT connection 0x3ffd5754, CONNECT operation 0x3ffd586c) Wait complete with result SUCCESS.
   22 16446 [iot_thread] [INFO ][MQTT][164460] New MQTT connection 0x3ffc0ccc established.
   23 16446 [iot_thread] Connected to broker.
   ```

## 步驟 6：執行 OTA 更新指令碼
<a name="ota-updates-esp32-ble-step6"></a>

1. 若要安裝先決條件，請執行下列命令：

   ```
   pip3 install boto3
   ```

   ```
   pip3 install pathlib
   ```

1. 在 中增加 FreeRTOS 應用程式版本`demos/include/aws_application_version.h`。

1. 建立新的 .bin 檔案。

1. 下載 python 指令碼 [ start\_ota.py。](https://github.com/aws-samples/amazon-freertos-ota-scripts/blob/master/scripts/start_ota.py)若要查看指令碼的說明內容，請在終端機視窗中執行下列命令：

   ```
   python3 start_ota.py -h
   ```

   您應該會看到類似下列的內容：

   ```
   usage: start_ota.py [-h] --profile PROFILE [--region REGION]
                       [--account ACCOUNT] [--devicetype DEVICETYPE] --name NAME
                       --role ROLE --s3bucket S3BUCKET --otasigningprofile
                       OTASIGNINGPROFILE --signingcertificateid
                       SIGNINGCERTIFICATEID [--codelocation CODELOCATION]
   Script to start OTA update
   optional arguments:
   -h, --help            show this help message and exit
   --profile PROFILE     Profile name created using aws configure
   --region REGION       Region
   --account ACCOUNT     Account ID
   --devicetype DEVICETYPE thing|group
   --name NAME           Name of thing/group
   --role ROLE           Role for OTA updates
   --s3bucket S3BUCKET   S3 bucket to store firmware updates
   --otasigningprofile OTASIGNINGPROFILE
                         Signing profile to be created or used
   --signingcertificateid SIGNINGCERTIFICATEID
                         certificate id (not arn) to be used
   --codelocation CODELOCATION
                         base folder location (can be relative)
   ```

1. 如果您使用提供的 CloudFormation 範本來建立資源，請執行下列命令：

   ```
   python3 start_ota_stream.py --profile otausercf --name esp32-ble --role ota_ble_iot_role-sample --s3bucket afr-ble-ota-update-bucket-sample --otasigningprofile abcd --signingcertificateid {{certificateid}}
   ```

   您應該會在 ESP32 偵錯主控台中看到更新開始：

   ```
   38 2462 [OTA Task] [prvParseJobDoc] Job was accepted. Attempting to start transfer.
   ---
   49 2867 [OTA Task] [prvIngestDataBlock] Received file block 1, size 1024
   50 2867 [OTA Task] [prvIngestDataBlock] Remaining: 1290
   51 2894 [OTA Task] [prvIngestDataBlock] Received file block 2, size 1024
   52 2894 [OTA Task] [prvIngestDataBlock] Remaining: 1289
   53 2921 [OTA Task] [prvIngestDataBlock] Received file block 3, size 1024
   54 2921 [OTA Task] [prvIngestDataBlock] Remaining: 1288
   55 2952 [OTA Task] [prvIngestDataBlock] Received file block 4, size 1024
   56 2953 [OTA Task] [prvIngestDataBlock] Remaining: 1287
   57 2959 [iot_thread] State: Active  Received: 5   Queued: 5   Processed: 5   Dropped: 0
   ```

1. 當 OTA 更新完成時，裝置會視需要重新啟動 OTA 更新程序。然後，它會嘗試使用更新的韌體進行連線。如果升級成功，更新的韌體會標記為作用中，您應該會在主控台中看到更新的版本：

   ```
   13 13498 [iot_thread] OTA demo version 0.9.21
   ```