# 协议

[English]

## JSON

### 移除内置 JSON 组件

ESP-IDF 已移除内置的 `json` 组件。用户应迁移至使用 IDF 组件管理器 中的 `espressif/cjson` 组件。

#### 迁移步骤

1. 从 CMakeLists.txt 中移除 json

   在组件的 `CMakeLists.txt` 文件中，从 `REQUIRES` 或 `PRIV_REQUIRES` 列表中移除 `json`：

       # 迁移前
       idf_component_register(SRCS "main.c"
                              PRIV_REQUIRES json esp_http_server)

       # 迁移后
       idf_component_register(SRCS "main.c"
                              PRIV_REQUIRES esp_http_server)

2. 将 espressif/cjson 添加到 idf_component.yml

   将 `espressif/cjson` 依赖项添加到组件的 `idf_component.yml` 文件中。如果该文件不存在，请在组件目录中创建它（例如 `main/idf_component.yml`）：

       dependencies:
         espressif/cjson: "^1.7.19"

3. 无需更改代码

   API 保持不变。现有的使用 cJSON 函数的代码无需修改即可继续工作：

       #include "cJSON.h"

       // 现有代码无需更改
       cJSON *root = cJSON_Parse(json_string);
       cJSON *item = cJSON_GetObjectItem(root, "key");
       cJSON_Delete(root);

更多信息：

- espressif/cjson 组件

- cJSON GitHub

## ESP-TLS

### 移除 wolfSSL 支持

ESP-TLS 已移除内置的 wolfSSL TLS 协议栈支持。使用 wolfSSL 的用户应迁移至以下两个方案之一：

1. mbedTLS（推荐）：默认 TLS 协议栈，完全集成并在 ESP-IDF 中维护。

2. 自定义 TLS 协议栈：使用自定义协议栈 API（见下文方案 B）注册自己的 TLS 实现。

已移除的 Kconfig 选项

以下 Kconfig 选项已被移除：

- `CONFIG_ESP_TLS_USING_WOLFSSL` - 请改用 `CONFIG_ESP_TLS_USING_MBEDTLS` 或 `CONFIG_ESP_TLS_CUSTOM_STACK`

- `CONFIG_ESP_DEBUG_WOLFSSL` - 进行 mbedTLS 调试，请使用 `CONFIG_MBEDTLS_DEBUG`

- `CONFIG_ESP_TLS_OCSP_CHECKALL` - OCSP 功能应由所选 TLS 协议栈处理

wolfSSL 用户迁移步骤

如果你的项目通过 ESP-TLS 使用 wolfSSL：

1. 方案 A - 切换到 mbedTLS

   - 从 sdkconfig 中移除 `CONFIG_ESP_TLS_USING_WOLFSSL=y`

   - 将自动使用默认的 `CONFIG_ESP_TLS_USING_MBEDTLS`

   - 使用标准 TLS 操作，无需更改代码

2. 方案 B - 使用自定义协议栈 API

   如需要继续使用 wolfSSL 或其他 TLS 库，可以将其注册为自定义协议栈：

   - 在 menuconfig 中启用 `CONFIG_ESP_TLS_CUSTOM_STACK`

   - 为你的 TLS 库实现 `esp_tls_stack_ops_t` 接口

   - 在创建任何 TLS 连接之前调用 `esp_tls_register_stack()`

   有关实现自定义 TLS 协议栈的详细文档，请参阅 自定义 TLS 协议栈支持。

### 已移除的废弃 API

已移除废弃函数 `esp_tls_conn_http_new()`。请使用以下替代函数：

- `esp_tls_conn_http_new_sync()` 用于阻塞连接

- `esp_tls_conn_http_new_async()` 用于非阻塞连接

新 API 需要您使用 `esp_tls_init()` 创建 `esp_tls_t` 结构，并提供对连接过程的更好控制。

### 统一私钥接口

`esp_tls_cfg`、`esp_tls_cfg_server` 和 `httpd_ssl_config` 中的 `use_secure_element` 字段已被弃用且不再起作用：将其设置为 `true` 会使连接（或服务器启动）失败并返回 `ESP_ERR_NOT_SUPPORTED`。保留该字段仅是为了源代码兼容性，它将在下一个主版本中被移除。ATECC608A 安全元件和所有其他硬件支持的密钥源（DS 外设、ECDSA 外设、密钥管理器）现在通过统一的 `esp_key_config_t` 接口和 PSA Crypto 密钥 ID 来访问。

迁移步骤

1. 将 `use_secure_element = true` 替换为使用 `ESP_KEY_SOURCE_PSA` 的新 `esp_key_config_t`，以及通过 `psa_import_key()` 获取的 PSA 密钥 ID。

2. `atcab_init()` 调用不再由 ESP-TLS 内部执行。使用 ATECC608A 的应用程序必须确保在使用前在应用层初始化安全元件。详情请参阅 esp-cryptoauthlib 文档。

3. `tcp_transport` 中的 `esp_transport_ssl_use_secure_element()` 函数已被弃用且不再起作用（连接将失败并返回 `ESP_ERR_NOT_SUPPORTED`）。请改用 `esp_transport_ssl_set_client_key_config()`。

4. 安全元件驱动的 Kconfig 选项已从 `CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN` / `CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY` 合并为 `CONFIG_MBEDTLS_SECURE_ELEMENT_DRIVER_ENABLED`。旧名称通过 `sdkconfig.rename` 自动映射。

详细使用示例请参阅 ESP-TLS 中的 ATECC608A（安全元件）。

## ESP HTTP 服务器

### 握手期间不再调用 WebSocket 处理器

自 v6.0.1 起，已注册的 URI 处理程序在 WebSocket 握手期间，针对 WebSocket 端点的回调 不再被调用。

在此更改之前，处理程序会在握手完成后立即以 `req->method == HTTP_GET` 的状态被调用，常用于应用程序的连接初始化：

    /* v6.0.1 之前的模式 — 自 v6.0.1 起不再生效 */
    static esp_err_t ws_handler(httpd_req_t *req)
    {
        if (req->method == HTTP_GET) {
            ESP_LOGI(TAG, "New WebSocket connection established");
            return ESP_OK;
        }
        /* 处理 WebSocket 帧 */
    }

自 v6.0.1 起，仅会针对后续的 WebSocket 数据帧调用该处理器，因此，帧处理程序中不再需要进行 `HTTP_GET` 检查。

#### 迁移选项

选项 1（推荐） — 将连接阶段的逻辑移动到一个专用的握手后回调中：

1. 在 menuconfig 中启用 CONFIG_HTTPD_WS_POST_HANDSHAKE_CB_SUPPORT。

2. 在 `httpd_uri_t` 结构体中注册 `ws_post_handshake_cb` 回调，使帧处理程序保持简洁，无需再进行 HTTP_GET 状态检查。

    static esp_err_t ws_on_connect(httpd_req_t *req)
    {
        ESP_LOGI(TAG, "New WebSocket connection established");
        return ESP_OK;
    }

    static esp_err_t ws_handler(httpd_req_t *req)
    {
        /* 仅处理 WebSocket 帧 */
    }

    static const httpd_uri_t ws_uri = {
        .uri                  = "/ws",
        .method               = HTTP_GET,
        .handler              = ws_handler,
        .is_websocket         = true,
        .ws_post_handshake_cb = ws_on_connect,
    };

选项 2（改动最少） — 将 `.ws_post_handshake_cb` 设置为与 `.handler` 相同的函数：

1. 在 menuconfig 中启用 CONFIG_HTTPD_WS_POST_HANDSHAKE_CB_SUPPORT。

2. 在 URI 注册中设置 `.ws_post_handshake_cb = ws_handler`。现有的 `if (req->method == HTTP_GET)` 检查在处理程序内部仍然有效，无需额外修改代码。

    static const httpd_uri_t ws_uri = {
        .uri                  = "/ws",
        .method               = HTTP_GET,
        .handler              = ws_handler,
        .is_websocket         = true,
        .ws_post_handshake_cb = ws_handler,   /* 同一个函数可恢复原有行为 */
    };

## ESP-Modbus

乐鑫ESP-Modbus 库 (esp-modbus) 支持基于 RS485、Wi-Fi 和以太网接口网络的 Modbus 通信。

`esp-modbus v2 (v2.x.x)` 组件是当前支持的组件版本：

- GitHub 上的 ESP-Modbus 组件

### 文档

- ESP-MODBUS 稳定版文档 v2.x.x

- 旧版本 v1.x.x 文档

### 应用示例

自 ESP-IDF v6.0 版本起，已从 ESP-IDF 中移除已废弃的 `esp-modbus v1` 组件示例。

- 旧版 esp-modbus v1.x.x 示例 (esp-idf v5.5)

以下示例分别演示了串行和 TCP 端口的 ESP-Modbus 库在从站和主站实现中的应用。

- mb_serial_slave - 演示如何将 ESP32 用作 Modbus 串行从站设备，通过 esp-modbus 协议栈，使外部 Modbus 主机能够使用 Modbus 协议读写设备参数。

- mb_serial_master - 演示如何在 ESP32 上使用 esp-modbus 协议栈端口作为 Modbus 串行主站设备，能够读写 Modbus 段中从站设备的值。

- mb_tcp_slave - 演示 esp-modbus TCP 从站协议栈端口，允许外部 Modbus 主机通过 Modbus 协议读写设备参数。

- mb_tcp_master - 演示如何在 ESP32 上使用 esp-modbus 协议栈端口作为 Modbus TCP 主站设备，能够读写 Modbus 网络中从站设备的值。

有关详细信息，请参阅每个具体示例的 `README.md` 文档。

### 讨论

- v2 版本讨论

## ESP-MQTT

重大变更：ESP-MQTT 迁移为托管组件，并更新了示例集。

- ESP-MQTT 组件已从 ESP-IDF 中移除，现作为托管组件 `espressif/mqtt` 提供。

  - 要将该组件添加至应用，运行 `idf.py add-dependency espressif/mqtt`。

  - 头文件与 API 保持兼容（使用 `mqtt_client.h`），但需通过组件管理器获取该组件。

- ESP-IDF 示例变更：

  - 移除了 `examples/protocols/mqtt/ssl*` 路径下的旧版 MQTT TLS 示例。

  - 新增参考示例：

    - protocols/mqtt：基于 TLS 的 MQTT。

    - protocols/mqtt5：基于 TLS 的 MQTT v5.0。

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。