# DataSets **Repository Path**: NetADs/datasets ## Basic Information - **Project Name**: DataSets - **Description**: ESP32S3开发板上,从网上拉取数据的组件。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-27 - **Last Updated**: 2026-06-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # datasets 适用于 ESP-IDF v5.x 的轻量级 HTTP JSON 请求组件。提供简单的接口从 HTTPS 服务器获取并解析 JSON 数据。 ## 功能特点 - 自动 TLS 证书验证(使用 ESP-IDF 内置 CA 证书包) - DNS 解析诊断日志 - 可配置超时时间 - 自动 JSON 解析(基于 cJSON) - 内存安全(调用方负责释放返回的 cJSON 对象) - 符合 ESP-IDF v5.x 标准组件规范 - 可作为独立组件复用于其他项目 ## 目录结构 ``` datasets/ ├── CMakeLists.txt # 组件构建配置 ├── Kconfig # 组件配置菜单 ├── idf_component.yml # 组件描述文件 ├── include/ │ └── datasets.h # 公共头文件 ├── src/ │ └── datasets.c # 组件源代码 ├── examples/ # 示例应用目录 │ └── basic/ # 基础使用示例 │ ├── CMakeLists.txt │ ├── idf_component.yml │ └── main.c ├── README.md └── LICENSE ``` ## 使用方法 ### 方式 1:作为独立组件使用 1. **复制组件到你的项目** 将整个 `datasets` 目录复制到你的 ESP-IDF 项目目录下: ```bash cp -r datasets /path/to/your/project/ ``` 2. **在你的项目中添加依赖** 在你的项目的 `main/CMakeLists.txt` 或其他组件的 `CMakeLists.txt` 中: ```cmake idf_component_register( SRCS "your_source.c" INCLUDE_DIRS "include" REQUIRES datasets ) ``` 3. **在代码中使用** 以下示例演示了两种典型用法: **示例一:获取天气数据** ```c #include "datasets.h" #include "esp_log.h" #include "cJSON.h" void fetch_weather(void) { const char *url = "https://api.openweathermap.org/data/2.5/weather" "?q=Tianjin,CN&appid=ea66ccaf862ed887702caa6f0e7bae4b" "&units=metric&lang=zh_cn"; cJSON *root = datasets_get(url, 0); if (root == NULL) { ESP_LOGE(TAG, "Failed to fetch"); return; } /* cod 字段 200 表示成功 */ cJSON *cod = cJSON_GetObjectItem(root, "cod"); if (cod && cod->valueint != 200) { ESP_LOGE(TAG, "API error, cod: %d", cod->valueint); cJSON_Delete(root); return; } cJSON *name = cJSON_GetObjectItem(root, "name"); cJSON *weather_arr = cJSON_GetObjectItem(root, "weather"); cJSON *main_obj = cJSON_GetObjectItem(root, "main"); cJSON *wind_obj = cJSON_GetObjectItem(root, "wind"); ESP_LOGI(TAG, "===== %s 天气 =====", name ? name->valuestring : "Tianjin"); if (weather_arr && cJSON_IsArray(weather_arr)) { cJSON *w = cJSON_GetArrayItem(weather_arr, 0); if (w) { cJSON *desc = cJSON_GetObjectItem(w, "description"); if (desc) ESP_LOGI(TAG, "天气: %s", desc->valuestring); } } if (main_obj) { cJSON *temp = cJSON_GetObjectItem(main_obj, "temp"); cJSON *feels_like = cJSON_GetObjectItem(main_obj, "feels_like"); cJSON *humidity = cJSON_GetObjectItem(main_obj, "humidity"); if (temp) ESP_LOGI(TAG, "温度: %.1f C", temp->valuedouble); if (feels_like) ESP_LOGI(TAG, "体感: %.1f C", feels_like->valuedouble); if (humidity) ESP_LOGI(TAG, "湿度: %d%%", humidity->valueint); } if (wind_obj) { cJSON *speed = cJSON_GetObjectItem(wind_obj, "speed"); if (speed) ESP_LOGI(TAG, "风速: %.1f m/s", speed->valuedouble); } cJSON_Delete(root); } ``` **示例二:获取黄历数据** ```c void fetch_huangli(int year, int month, int day) { char url[256]; snprintf(url, sizeof(url), "https://api.jisuapi.com/huangli/date" "?appkey=03c9ed615ef4e64b" "&year=%d&month=%02d&day=%02d", year, month, day); cJSON *root = datasets_get(url, 0); if (root == NULL) { ESP_LOGE(TAG, "Failed to fetch"); return; } cJSON *status = cJSON_GetObjectItem(root, "status"); if (status && status->valueint != 0) { ESP_LOGE(TAG, "API error code %d", status->valueint); cJSON_Delete(root); return; } cJSON *result = cJSON_GetObjectItem(root, "result"); if (result) { cJSON *nongli = cJSON_GetObjectItem(result, "nongli"); cJSON *shengxiao = cJSON_GetObjectItem(result, "shengxiao"); cJSON *star = cJSON_GetObjectItem(result, "star"); cJSON *chong = cJSON_GetObjectItem(result, "chong"); cJSON *sha = cJSON_GetObjectItem(result, "sha"); cJSON *yi = cJSON_GetObjectItem(result, "yi"); cJSON *ji = cJSON_GetObjectItem(result, "ji"); ESP_LOGI(TAG, "农历: %s", nongli ? nongli->valuestring : ""); ESP_LOGI(TAG, "生肖: %s", shengxiao ? shengxiao->valuestring : ""); ESP_LOGI(TAG, "星座: %s", star ? star->valuestring : ""); ESP_LOGI(TAG, "冲: %s", chong ? chong->valuestring : ""); ESP_LOGI(TAG, "煞: %s", sha ? sha->valuestring : ""); if (yi && cJSON_IsArray(yi)) { char buf[256] = {0}; for (int i = 0; i < cJSON_GetArraySize(yi); i++) { if (i > 0) strlcat(buf, "、", sizeof(buf)); strlcat(buf, cJSON_GetArrayItem(yi, i)->valuestring, sizeof(buf)); } ESP_LOGI(TAG, "宜: %s", buf); } if (ji && cJSON_IsArray(ji)) { char buf[256] = {0}; for (int i = 0; i < cJSON_GetArraySize(ji); i++) { if (i > 0) strlcat(buf, "、", sizeof(buf)); strlcat(buf, cJSON_GetArrayItem(ji, i)->valuestring, sizeof(buf)); } ESP_LOGI(TAG, "忌: %s", buf); } } cJSON_Delete(root); } ``` ### 方式 2:通过 Git URL 引用 在你的 ESP-IDF 项目的 `idf_component.yml` 中添加: ```yaml dependencies: datasets: git: https://gitee.com/NetADs/datasets.git version: "^1.0.0" ``` 然后运行 `idf.py reconfigure` 自动下载组件。 ### 方式 3:使用 IDF Component Registry 组件已发布到 IDF Component Registry,可通过 `idf_component.yml` 直接引用: ```yaml dependencies: datasets: "^1.0.0" ``` ### 方式 4:本地路径引用(开发调试) 在开发阶段,可通过本地路径引用: ```yaml dependencies: datasets: path: /path/to/datasets ``` ### 方式 5:编译示例程序 组件包含示例程序,可直接编译测试: ```bash cd datasets/examples/basic idf.py build ``` ## API 参考 ### `datasets_get` ```c cJSON *datasets_get(const char *url, int timeout_ms); ``` | 参数 | 说明 | |------|------| | `url` | 完整 HTTPS URL(必须以 `https://` 开头) | | `timeout_ms` | 连接超时时间(毫秒),传 0 使用默认 30000ms | | 返回值 | 说明 | |--------|------| | `cJSON *` | 解析后的 JSON 根对象,调用方需调用 `cJSON_Delete()` 释放 | | `NULL` | 请求失败或 JSON 解析失败 | ### `datasets_fetch` ```c cJSON *datasets_fetch(datasets_request_t *req); ``` 灵活的请求接口,支持认证、自定义请求头、POST/PUT 等。 **`datasets_request_t` 结构体:** | 字段 | 类型 | 说明 | |------|------|------| | `base_url` | `const char *` | 必填:基础 URL | | `path` | `const char *` | 可选:API 路径 | | `query_params` | `const char *` | 可选:查询参数(不含 `?`) | | `method` | `esp_http_client_method_t` | HTTP 方法,默认 `HTTP_METHOD_GET` | | `post_data` | `const char *` | 可选:POST/PUT 请求体(JSON 字符串) | | `api_key` | `const char *` | 可选:API Key,作为 HTTP 请求头发送 | | `api_key_header` | `const char *` | 可选:API Key 的请求头名称,默认 `X-API-Key` | | `bearer_token` | `const char *` | 可选:Bearer Token,设置 `Authorization` 请求头 | | `custom_headers` | `const char **` | 可选:自定义请求头数组(`"Header: Value"` 格式) | | `header_count` | `int` | 自定义请求头数量 | | `timeout_ms` | `int` | 超时时间(毫秒),0 使用默认 30000ms | | `max_retries` | `int` | 最大重试次数,0 使用默认 2 次 | **三种认证方式示例:** ```c // 方式一:API Key 放在请求头(默认 X-API-Key) datasets_request_t req = { .base_url = "https://api.example.com", .path = "/v1/data", .api_key = "your-api-key", }; cJSON *root = datasets_fetch(&req); // 方式二:自定义 API Key 请求头名称 datasets_request_t req = { .base_url = "https://api.example.com", .path = "/v1/data", .api_key = "your-api-key", .api_key_header = "X-My-Custom-Key", }; // 方式三:Bearer Token 认证 datasets_request_t req = { .base_url = "https://api.example.com", .path = "/v1/data", .bearer_token = "your-jwt-token", }; ``` URL 查询参数中的 API Key(如 `?appkey=xxx`)可直接拼接在 `query_params` 中,或直接用 `datasets_get()` 传入完整 URL,无需额外配置。 ## 依赖项 | 组件 | 说明 | |------|------| | `esp_http_client` | ESP-IDF 内置 HTTP 客户端 | | `json` | ESP-IDF 内置 cJSON 库 | | `mbedtls` | TLS/SSL 支持(证书验证) | | `lwip` | 网络栈(DNS 解析) | ## 系统要求 - ESP-IDF v5.0 或更高版本 - ESP32 系列芯片(ESP32, ESP32-S, ESP32-C 系列) ## 配置要求 需要确保你的 `sdkconfig` 中启用了证书包: ``` CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y ``` ## 示例应用 完整的示例代码请参考 `examples/basic/main.c` 文件。 ## 故障排查 ### DNS 解析失败 检查日志输出中的 `DNS: ...` 信息,确认网络连接正常。 ### TLS 证书验证失败 - 确保使用 HTTPS URL - 确认服务器的 SSL 证书是有效的 - 检查 `sdkconfig` 中的证书包配置 ### 内存分配失败 - 减少响应数据大小 - 增加堆内存配置 - 检查是否有内存泄漏 ## 贡献 欢迎提交 Issue 和 Pull Request! ## 许可证 MIT License