写一个基于ESP32-S3原生和豆包api交互的示例

下面给出一个示例工程,展示如何在 ESP32-S3 上通过原生 ESP-IDF 与「豆包API」进行简单交互(例如:HTTP GET / POST),并解析返回的数据。该示例涵盖:Wi-Fi 连接HTTP 请求JSON 解析 等核心流程,以便你在此基础上改写、对接实际的「豆包API」。

说明: 由于并不清楚“豆包API”的实际接口形式,这里以一个“示例 URL”和“示例响应 JSON”为例进行演示,供你参考如何编写代码。

ESP32-S3 豆包大模型组合


一、工程结构

假设我们的工程结构如下:

├── CMakeLists.txt
├── main
│   ├── CMakeLists.txt
│   └── main.c
└── sdkconfig

其中 main.c 存放主要逻辑,CMakeLists.txt 根据 ESP-IDF 标准模板编写。


二、主要功能流程

  1. 初始化 NVS、Wi-Fi 并连接到指定路由器。
  2. 发起 HTTP 请求 到 “豆包API” 示例地址 https://api.doubao.com/v1/info
    • 可以是 GET 或 POST,根据你的 API 实际需求来调整。
  3. 解析响应数据(JSON),打印或使用响应内容。
  4. 定时或按需再次请求,“与原生 IDF 交互”即直接使用官方 API(esp_http_client_xxxcJSON 解析等)。

三、示例代码

1. 顶层 CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

set(PROJECT_NAME "esp_s3_doubao_demo")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(${PROJECT_NAME})

2. main/CMakeLists.txt

idf_component_register(SRCS "main.c"
                    INCLUDE_DIRS ".")

3. main.c

下面是一份精简示例,请结合你的项目需求进行修改(如替换 WIFI_SSIDWIFI_PASS、“豆包API”的 URL、处理返回数据等)。

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_http_client.h"
#include "cJSON.h"

/*----------------------------
 * 修改这里:Wi-Fi SSID & PASS
 *---------------------------*/
#define WIFI_SSID "your_wifi_ssid"
#define WIFI_PASS "your_wifi_password"

/*----------------------------
 * Tag for logging
 *---------------------------*/
static const char *TAG = "DouBao_API";

/* 
 * Wi-Fi 事件回调
 * 当发生STA连接成功、断开等事件时,会调用此函数
 */
static void event_handler(void* arg, esp_event_base_t event_base, 
                          int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect(); 
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        ESP_LOGI(TAG, "Wi-Fi disconnected, retrying...");
        esp_wifi_connect(); 
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "Got IP: %s",
                 ip4addr_ntoa(&event->ip_info.ip));
    }
}

/*
 * 初始化并连接 Wi-Fi(Station 模式)
 */
static void wifi_init(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    /* 注册事件回调 */
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        NULL));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = WIFI_SSID,
            .password = WIFI_PASS,
            .threshold.authmode = WIFI_AUTH_WPA2_PSK
        },
    };

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_LOGI(TAG, "Wi-Fi init done, connecting...");
}

/*
 * 解析服务器返回的 JSON 示例
 * 假设返回类似:
 * {
 *   "code": 0,
 *   "msg": "ok",
 *   "data": {
 *       "user": "test_user",
 *       "score": 88
 *   }
 * }
 */
static void parse_json_response(const char *json_str)
{
    cJSON *root = cJSON_Parse(json_str);
    if (!root) {
        ESP_LOGE(TAG, "Failed to parse JSON");
        return;
    }

    cJSON *code = cJSON_GetObjectItem(root, "code");
    cJSON *msg  = cJSON_GetObjectItem(root, "msg");
    cJSON *data = cJSON_GetObjectItem(root, "data");

    if (cJSON_IsNumber(code) && cJSON_IsString(msg) && data) {
        ESP_LOGI(TAG, "code = %d, msg = %s", code->valueint, msg->valuestring);

        cJSON *user = cJSON_GetObjectItem(data, "user");
        cJSON *score= cJSON_GetObjectItem(data, "score");
        if (cJSON_IsString(user) && cJSON_IsNumber(score)) {
            ESP_LOGI(TAG, "user: %s, score: %d", 
                     user->valuestring, score->valueint);
        }
    } else {
        ESP_LOGW(TAG, "JSON format not expected");
    }

    cJSON_Delete(root);
}

/*
 * HTTP GET 示例:访问「豆包API」
 */
static void doubao_http_get_task(void *pv)
{
    // 配置 HTTP Client
    esp_http_client_config_t config = {
        .url = "https://api.doubao.com/v1/info",  // 示例URL
        .method = HTTP_METHOD_GET,
        .timeout_ms = 5000,
        // 若需要HTTPS并使用自签证书,需要设置 .cert_pem 或 skip_cert_common_name_check 等
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    while (1) {
        esp_err_t err = esp_http_client_perform(client);
        if (err == ESP_OK) {
            int status_code = esp_http_client_get_status_code(client);
            int content_length = esp_http_client_get_content_length(client);

            ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d", 
                     status_code, content_length);

            // 读取服务器返回内容
            char *buffer = malloc(content_length + 1);
            if (buffer) {
                esp_http_client_read(client, buffer, content_length);
                buffer[content_length] = '\0'; // 结尾

                ESP_LOGI(TAG, "Response: %s", buffer);
                // 解析 JSON
                parse_json_response(buffer);

                free(buffer);
            }
        } else {
            ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
        }

        // 间隔一定时间再请求
        vTaskDelay(pdMS_TO_TICKS(5000));
    }

    // 不会到这里,但如果要结束,需要 clean up
    esp_http_client_cleanup(client);
    vTaskDelete(NULL);
}

/*
 * HTTP POST 示例:向「豆包API」发送数据
 */
static void doubao_http_post_task(void *pv)
{
    // 构造要发送的 JSON
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "device_id", "esp_s3_test");
    cJSON_AddNumberToObject(root, "temperature", 26.5);
    char *post_data = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);

    esp_http_client_config_t config = {
        .url = "https://api.doubao.com/v1/report",
        .method = HTTP_METHOD_POST,
        .timeout_ms = 5000,
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_post_field(client, post_data, strlen(post_data));

    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK) {
        int status_code = esp_http_client_get_status_code(client);
        int content_length = esp_http_client_get_content_length(client);
        ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d", 
                 status_code, content_length);

        // 如果需要读取响应
        if (content_length > 0) {
            char *buffer = malloc(content_length + 1);
            if (buffer) {
                esp_http_client_read(client, buffer, content_length);
                buffer[content_length] = '\0';
                ESP_LOGI(TAG, "Response: %s", buffer);
                // 根据需要解析
                free(buffer);
            }
        }
    } else {
        ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
    }

    free(post_data);
    esp_http_client_cleanup(client);
    vTaskDelete(NULL);
}

/*
 * app_main() -- 主函数
 */
void app_main(void)
{
    // 1. 初始化 NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        nvs_flash_erase();
        nvs_flash_init();
    }

    // 2. 初始化 Wi-Fi
    wifi_init();

    // 3. 等待 Wi-Fi 连接成功后,再启动任务
    //   可以粗略延时,也可以在 IP_EVENT_STA_GOT_IP 里创建任务,这里简单示例延时
    vTaskDelay(pdMS_TO_TICKS(5000));

    // 4. 创建一个任务执行 GET
    xTaskCreate(doubao_http_get_task, "DouBaoGetTask", 4096, NULL, 5, NULL);

    // 5. 创建一个任务执行 POST (视情况,需要时再创建)
    //    这里示例一次性发起 POST 并退出
    xTaskCreate(doubao_http_post_task, "DouBaoPostTask", 4096, NULL, 5, NULL);
}

关键点说明

  1. Wi-Fi 初始化

    • 使用了 ESP-IDF 的官方方式:esp_wifi_initesp_wifi_set_mode(WIFI_MODE_STA)esp_wifi_set_configesp_wifi_startesp_wifi_connect
    • 通过注册事件回调 (event_handler) 监听连接状态,获取 IP 后就能上网。
  2. HTTP 请求

    • 使用 esp_http_client 模块。
    • GET: 先 esp_http_client_perform(),然后读取状态码、读取响应内容并解析。
    • POST: 设置 header、post_field;perform 后获取返回数据。
  3. JSON 解析

    • cJSON 做解析、构造 JSON 数据。IDF 自带 cJSON 库,需在 menuconfig -> Component config -> JSON 中启用(若默认没启用)。
    • 注意内存分配释放malloc, free, cJSON_PrintUnformatted, cJSON_Delete 等)。
  4. 安全 (HTTPS)

    • 若豆包API 使用 HTTPS 且证书非权威机构签署,需要在 esp_http_client_config_t 里配置 .cert_pem 或者设置 .skip_cert_common_name_check = true 来跳过校验(不推荐)。
    • 若是正式环境,建议做好服务器证书验证。
  5. 任务栈大小

    • 此处示例给了 4096;根据实际请求大小、JSON 解析复杂度等,可能需要调大或调小。

四、menuconfig 相关设置

  1. 启用 Wi-Fi

    • idf.py menuconfig -> Component config -> Wi-Fi
    • 确保 STA 模式可用、选对国家代码等。
  2. 启用 HTTPS / SSL(若调用的豆包API是 HTTPS)

    • menuconfig -> Component config -> mbedTLS
    • 可以调整 MBEDTLS_SSL_MAX_CONTENT_LEN (默认4096) 等参数,避免握手时内存不足。
  3. 启用 cJSON

    • menuconfig -> Component config -> JSON -> cJSON library
    • 若不需要 cJSON,可以改用其它 JSON 库或更精简的处理方式。
  4. 其他网络协议栈

    • menuconfig -> Component config -> LWIP
    • 调整 TCP/IP 缓冲区、最大 socket 数量等,视并发需求配置。

五、验证方法

  1. 编译并烧写

    • 在项目目录下执行:
      idf.py set-target esp32s3
      idf.py menuconfig   # 配置 Wi-Fi、日志级别等
      idf.py build
      idf.py flash monitor
      
  2. 观察日志

    • 启动后,ESP32-S3 会连接到指定路由器;
    • 日志中若出现 Got IP: ... 则表示连接成功;
    • 然后会看到 GET 和 POST 任务的执行结果、返回内容等。
  3. 与“豆包API”真实环境对接

    • 替换为你实际的 API 地址 (域名/IP)、路由、URL path、POST body 等即可。

在这里插入图片描述

六、总结

  • 上述示例演示了如何在 ESP32-S3 上使用原生 ESP-IDF 的 API(Wi-Fi、HTTP Client、cJSON)与一个假想的「豆包API」进行网络交互。
  • 你可以根据 API 文档(如果“豆包API”有更详细接口说明),修改请求方式(GET/POST/PUT 等)、修改 JSON 格式解析逻辑,以及加入更多业务处理(如存储 NVS、本地处理数据等)。
  • 若需要 HTTPS 安全,请确保正确配置服务器证书或使用 IDF 提供的 CA 证书校验机制。

这样,你就能完成一个基于 ESP32-S3 原生 IDF 与 “豆包API” 进行完整交互的示例工程。祝你开发顺利!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值