

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 教程：使用 ESP32 FreeRTOS 低功耗蓝牙在 Espressif 上执行 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)。

本教程向您展示如何在 Android 设备上更新连接到 MQTT 低功耗蓝牙代理的乐鑫 ESP32 微控制器。它使用 AWS IoT Over-the-air (OTA) 更新任务更新设备。设备 AWS IoT 使用在安卓演示应用程序中输入的 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 代理功能的更多信息，请参阅 Richard Kang 在 Espressif 上的《在 FreeRTOS [上使用低功耗蓝牙 FreeRTOS》 ESP32](https://aws.amazon.com/blogs/iot/using-bluetooth-low-energy-with-amazon-freertos-on-espressif-esp32/)一文。

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

要执行本教程中的步骤，您需要以下资源：
+  ESP32 开发板。
+ 一根 MicroUSB 转 USB A 电缆。
+ 一个 AWS 账户（免费套餐就足够了）。
+ 一台使用 Android v 6.0 或更高版本和蓝牙版本 4.2或更高版本的 Android 手机。

在开发计算机上，您需要：
+ 有足够的磁盘空间（约 500 Mb）来存放 Xtensa 工具链和 FreeRTOS 源代码和示例。
+ 已安装 Android Studio
+ 已安装 [AWS CLI](https://aws.amazon.com/cli/)。
+ 已安装 Python3。
+ 适用于 Py [thon 的 boto3 AWS 软件开发套件 (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) 并为角色添加以下托管策略：
   + AWSIot正在记录
   + 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 资源名称 (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. 在**添加语句**部分中，选择**高级模式**。将以下 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. 在左侧导航窗格中选择**管理**，然后选择**事物**。

1. 在右上角，选择**创建**。如果您的账户中没有注册任何事物，则会显示消息“您还没有任何事物”，并且您可以选择**注册事物**。

1. 在**创建 AWS IoT 事物**页面上，选择**创建单个事物**。

1. 在**将设备添加到事物注册表**页面上，为您的事物输入一个名称（例如，“esp32-ble”）。仅允许使用字母数字字符、连字符 (-) 和下划线 (\_) 字符。选择**下一步**。

1. 在**添加事物的证书**页面上的**跳过证书并创建事物**下，选择**创建没有证书的事物**。由于我们使用 BLE 代理移动应用程序，该应用程序使用 Amazon Cognito 凭证进行身份验证和授权，因此不需要设备证书。

**创建 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. 选择**创建应用程序客户端**。

1. 选择 **Return to pool details**（返回池详细信息）。

1. 在用户群体的**审核**页面上，选择**创建群体**。您应该会看到一条“已成功创建用户池”的消息。记下该群体 ID。

1. 在导航窗格中选择**应用程序客户端**。

1. 选择**显示详细信息**。记录应用程序客户端 ID 和应用程序客户端密钥。

**创建 Amazon Cognito 身份池**

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

1. 选择**创建新身份池**。

1. 输入身份池的名称（例如，“mqtt\_proxy\_identity\_pool”）。

1. 展开**身份验证提供程序**。

1. 选择 **Cognito** 选项卡。

1. 输入在前面的步骤中记下的用户群体 ID 和应用程序客户端 ID。

1. 选择**创建池**。

1. 在下一页上，要为经过身份验证和未经过身份验证的身份创建新角色，请选择**允许**。

1. 记下身份池 ID，其格式为 `us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`。

**将 IAM policy 附加到经过身份验证的身份。**

1. 打开 [Amazon Cognito 控制台](https://console.aws.amazon.com/cognito/federated)。

1. 选择刚才创建的身份池（例如，“mqtt\_proxy\_identity\_pool”）。

1. 选择**编辑身份池**。

1. 记下分配给经过身份验证的角色的 IAM 角色（例如，“cognito\_mqtt\_proxy\_identity\_poolauth\_Role”）。

1. 打开 [IAM 控制台](https://console.aws.amazon.com/iam/home)。

1. 在导航窗格中，选择**角色**。

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. 输入策略名称（例如，“mqttProxyCognito策略”）。

1. 选择**创建策略**。

## 步骤 4：配置 Amazon FreeRTOS
<a name="ota-updates-esp32-ble-step4"></a>

1. [从 FreeRTOS 存储库下载最新版本的亚马逊 FreeRTOS 代码。 GitHub ](https://github.com/aws/amazon-freertos)

1. 要启用 OTA 更新演示，请按照[开始使用 Espressif ESP32-C 和 DevKit 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` 并输入 `clientcredentialMQTT_BROKER_ENDPOINT` 的端点 URL。

      输入 `clientcredentialIOT_THING_NAME` 的事物名称（例如，“esp32-ble”）。使用 Amazon Cognito 凭证时，无需添加证书。

   1. 打开 `vendors/espressif/boards/esp32/aws_demos/config_files/aws_iot_network_config.h` 并更改 `configSUPPORTED_NETWORKS` 和 `configENABLED_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 存储库中下载安卓蓝牙低功耗 SDK](https://github.com/aws/amazon-freertos-ble-android-sdk) GitHub 和示例应用程序。

1. 打开文件`app/src/main/res/raw/awsconfiguration.json`并填写池 ID AppClientId、区域，然后 AppClientSecret 按照以下 JSON 示例中的说明进行操作。

   ```
   {
     "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. 在串行端口调试控制台上按 **y** ESP32。

   1. 选择**配对并连接**。

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 代理发送 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. 在 `demos/include/aws_application_version.h` 中增加 FreeRTOS 应用程序的版本。

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
   ```