Files
mimiclaw/taolun.md
Z.To c1368962cc
Some checks failed
Build / idf-build (push) Has been cancelled
fix: 添加 Kconfig.projbuild 修复模块开关失效问题
- 创建 main/Kconfig.projbuild 声明所有自定义模块配置项
- 修复 fullclean 后 sdkconfig 丢失 CONFIG_MIMI_* 配置的问题
- 更新 AGENTS.md 添加认知修正栏目和模块开关文档
- 记录 Kconfig 踩坑讨论到 taolun.md
2026-04-04 06:44:52 +08:00

533 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 讨论记录
---
## 实施记录:时间同步 + NVS 稳定性 + LLM Provider Bug 修复
**日期**2026-04-01
**分支**`feature/time-sync-nvs-stability`
**状态**:已实现,待烧录验证
### 修复的核心 Bug
#### Bug 1: `llm_provider_init()` 无法从 NVS 加载 provider-specific API key
**文件**`main/llm/llm_provider.c`
**问题**`llm_provider_init()` 调用 `llm_provider_get_api_key(s_current_provider->name)` 加载当前 provider 的 key但该函数对当前 provider 直接返回内存中的 `s_api_key`(初始为空字符串),导致 NVS 中的 `siliconflow_api_key``volcengine_api_key` 等永远不会被加载到内存。`s_base_url` 同理。
**修复**:改为直接通过 `get_provider_api_key_nvs_key()` 获取 NVS key 名,然后 `nvs_get_str()` 直接读取,绕过内存缓存。
#### Bug 2: 时间显示 1970
**文件**:新增 `main/time_sync/`
**问题**ESP32 上电后 RTC 从 0 开始,没有 SNTP 客户端自动同步时间。
**修复**:新建 `time_sync` 模块WiFi 连接后自动启动 SNTP`ntp.ntsc.ac.cn` 同步时间。
#### Bug 3: Brownout 导致 NVS 损坏
**文件**:新增 `main/nvs_safety/`,修改 `sdkconfig.defaults`
**问题**:不同 USB 口供电能力不同WiFi 峰值电流 300-500mA供电不足时 Flash 写入中断导致 NVS 损坏。
**修复**:启用 Brownout Detection + 启动时 NVS 完整性校验与自动修复。
### 新增 CLI 命令
| 命令 | 功能 |
|------|------|
| `ntp_status` | 查看完整状态(时区 + 本地时间 + 同步状态 + NTP 服务器 + 上次同步时间) |
| `ntp_sync` | 立即手动同步一次 |
| `ntp_set <server>` | 设置 NTP 服务器(存 NVS重启后生效 |
### 实施过程中的潜在问题与修复
#### 问题 1: `tool_set_timezone.c` 缺少 `<strings.h>`
**发现**`strcasecmp()``strcasestr()` 在 POSIX 标准中定义在 `<strings.h>` 而非 `<string.h>` 中。某些编译器会报错。
**修复**:添加 `#include <strings.h>`
#### 问题 2: `parse_and_set_time_from_date()` 中多余的 `tzset()` 调用
**发现**:在 `mktime()` 之后又调用了 `setenv("TZ", "UTC0", 1); tzset();`,这会把时区重新设为 UTC导致后续 `localtime_r()` 返回 UTC 时间而非用户设置的时区时间。
**修复**:移除 `mktime()` 后的 `setenv`/`tzset()` 调用。时区恢复由调用方(`tool_set_timezone_execute`)在设置完系统时钟后通过 `setenv("TZ", resolved_tz, 1); tzset()` 处理。
#### 问题 3: `serial_cli.c` 中 `vTaskDelay` 的 FreeRTOS 头文件
**确认**`freertos/task.h` 已在文件顶部包含(第 32 行),无需额外添加。
#### 问题 4: `time_sync.c` 中 `sntp_stop()` API 兼容性
**确认**`sntp_stop()` 是 ESP-IDF 标准 SNTP API`esp_sntp.h` 中定义v5.x 和 v6.x 均支持。
#### 问题 5: `nvs_safety.c` 中 NVS 迭代器 API
**确认**`nvs_iterator_t``nvs_entry_find()``nvs_entry_info()``nvs_entry_next()` 是 ESP-IDF 标准 NVS API`nvs.h` 中定义。
### 最终文件变更清单
| 文件 | 操作 | 说明 |
|------|------|------|
| `main/llm/llm_provider.c` | **修复** | 修复 `llm_provider_init()` 加载逻辑 |
| `main/time_sync/time_sync.h` | 新建 | SNTP 时间同步头文件 |
| `main/time_sync/time_sync.c` | 新建 | SNTP 时间同步实现 |
| `main/nvs_safety/nvs_safety.h` | 新建 | NVS 完整性校验头文件 |
| `main/nvs_safety/nvs_safety.c` | 新建 | NVS 损坏检测与修复 |
| `main/mimi.c` | 修改 | WiFi 连接后调用 `time_sync_init()` + 启动时调用 `nvs_safety_check()` |
| `main/cli/serial_cli.c` | 修改 | `timezone_show` 改为 `ntp_status`,新增 `ntp_sync``ntp_set` 命令 |
| `main/tools/tool_set_timezone.c` | 修改 | 添加 `<strings.h>`,设置时区后检测时间有效性 |
| `main/mimi_config.h` | 修改 | 添加 `MIMI_NVS_KEY_NTP_SERVER``MIMI_DEFAULT_NTP_SERVER` |
| `main/CMakeLists.txt` | 修改 | 添加新源文件 |
| `sdkconfig.defaults` | 修改 | 启用 Brownout Detection + SNTP |
### 认知修复(编译错误避坑指南)
#### ESP-IDF v6.0 API 迁移要点
1. **SNTP API**`sntp_*``esp_sntp_*`,组件属于 `lwip` 而非独立组件
2. **NVS API**:迭代器操作需要指针参数,记得释放迭代器
3. **类型系统**`arg_str1` 是函数,结构体成员用 `struct arg_str`
4. **组件依赖**v6.0 中 `esp_sntp` 组件不存在,无需添加
#### 常见错误模式
- **结构体类型错误**:混淆函数名和类型名
- **API 签名变化**:参数数量或类型改变
- **组件重组**:功能移动到其他组件
- **未使用代码**:及时清理未使用的函数和变量
#### 预防措施
1. 使用 `#ifdef` 保护平台相关常量(如 `WIFI_REASON_*`
2. 检查函数返回值,特别是迭代器操作
3. 定期清理未使用的代码
4. 参考官方迁移指南和头文件声明
---
## 编译错误修复速查表
| 问题类型 | 错误示例 | 修复方案 | 涉及文件 |
|----------|----------|----------|----------|
| 结构体类型 | `arg_str1 *server` | 使用 `struct arg_str *server` | `serial_cli.c` |
| SNTP 弃用 | `sntp_init()` | 改用 `esp_sntp_init()` | `time_sync.c` |
| NVS 参数 | `nvs_entry_find(3个参数)` | 添加第4个参数 `&it` | `nvs_safety.c` |
| 未使用函数 | `provider_is_openai` | 删除函数定义 | `llm_proxy.c` |
| 组件依赖 | `esp_sntp` 组件不存在 | 移除依赖声明 | `CMakeLists.txt` |
| WiFi 常量 | `WIFI_REASON_ASSOC_EXPIRE` | 添加 `#ifdef` 保护 | `wifi_manager.c` |
---
## 讨论:系统时间同步 + NVS 配置稳定性修复
**日期**2026-04-01
**目标**:修复两个关键问题 — 时间显示 1970、换 USB 口后配置不生效
### 问题 1时间显示 1970-01-01
**现象**
```
Current timezone: Asia/Shanghai [NVS]
Local time: 1970-01-01 00:00:23 GMT (Thursday)
```
**根因**:代码中没有初始化 SNTP/NTP 客户端。ESP32 上电后 RTC 时钟从 0 开始计时,`time(NULL)` 返回的就是 1970 年以来的秒数。目前只有 LLM 调用 `get_current_time` 工具时才会通过 HTTP 同步时间。
**修复方案**
- 新建 `main/time_sync/time_sync.c`,使用 ESP-IDF 内置 SNTP 组件
- WiFi 连接成功后自动从 `ntp.ntsc.ac.cn` 同步时间
- 同步成功后自动应用已保存的时区配置
- `ntp_status` 命令显示完整时间状态时区、本地时间、同步状态、NTP 服务器、上次同步时间)
### 问题 2换 USB 口/电脑后不工作 + 模型配置不加载
**现象**
- 插入其他 Type-C 口或电脑,设备不正常工作
- 需要在 Web 界面重新填写大模型 ID 和密钥,保存重启后才正常
- 命令行中模型状态显示异常
**根因分析**
#### 2.1 LLM Provider 初始化 Bug核心问题
`llm_provider.c:260-284` 中,`llm_provider_init()` 通过 `llm_provider_get_api_key()` 加载当前 provider 的 API key
```c
void llm_provider_init(void) {
const char *api_key = llm_provider_get_api_key(s_current_provider->name);
if (api_key) {
strncpy(s_api_key, api_key, sizeof(s_api_key) - 1);
}
```
`llm_provider_get_api_key()` 的逻辑是(`llm_provider.c:209-214`
```c
const char *llm_provider_get_api_key(const char *provider_name) {
if (strcmp(provider_name, s_current_provider->name) == 0) {
return s_api_key; // 直接返回内存中的值,不从 NVS 读!
}
// 否则才从 NVS 加载...
```
**形成死循环**`llm_provider_init()` 想从 NVS 加载 key → 调用 `llm_provider_get_api_key` → 发现是当前 provider → 直接返回内存中的 `s_api_key`(初始为空)→ 把空值复制给自己 → **NVS 中的 provider-specific key如 `siliconflow_api_key`)永远不会被加载到内存**
同理,`s_base_url` 也存在相同问题。
**为什么 Web 界面保存后能正常工作?**
Web 界面的 `/save` 处理函数(`wifi_onboard.c:377-408`)会**同时保存两份**
```c
nvs_sync_field(root, "api_key", MIMI_NVS_LLM, MIMI_NVS_KEY_API_KEY); // 通用 key
nvs_sync_field(root, "api_key", MIMI_NVS_LLM, api_key_nvs); // provider-specific key
```
`llm_proxy_init()` 能正确加载 `MIMI_NVS_KEY_API_KEY`(通用 key所以 Web 保存后能用。但如果只通过 CLI 的 `set_siliconflow_key` 设置(只保存到 `siliconflow_api_key`),上电后就不会被加载。
#### 2.2 Brownout欠压导致 NVS 损坏
ESP32-S3 开启 WiFi 时峰值电流可达 300-500mA不同 USB 端口的供电能力差异很大。供电不足时:
- 可能导致静默重启或 Flash 写入中断
- `nvs_commit` 过程中断电会导致 NVS 数据损坏
- WiFi 不稳定但日志看起来"正常"
**修复方案**
1. 修复 `llm_provider_init()` — 直接从 NVS 读取当前 provider 的 key 和 Base URL绕过 `llm_provider_get_api_key` 的内存缓存
2. 新建 `main/nvs_safety/nvs_safety.c` — 启动时校验关键 NVS 命名空间的完整性,检测并修复损坏条目
3.`sdkconfig.defaults` 中启用 ESP32-S3 的 Brownout Detection
### 改动清单
| 文件 | 操作 | 说明 |
|------|------|------|
| `main/llm/llm_provider.c` | **修复** | 修复 `llm_provider_init()` 加载逻辑 |
| `main/time_sync/time_sync.h` | 新建 | SNTP 时间同步头文件 |
| `main/time_sync/time_sync.c` | 新建 | SNTP 时间同步实现 |
| `main/nvs_safety/nvs_safety.h` | 新建 | NVS 完整性校验头文件 |
| `main/nvs_safety/nvs_safety.c` | 新建 | NVS 损坏检测与修复 |
| `main/mimi.c` | 修改 | WiFi 连接后调用 `time_sync_init()` + 启动时调用 `nvs_safety_check()` |
| `main/cli/serial_cli.c` | 修改 | `timezone_show` 增加 SNTP 同步状态 |
| `main/CMakeLists.txt` | 修改 | 添加新源文件和 `esp_netif` 依赖 |
| `sdkconfig.defaults` | 修改 | 启用 Brownout Detection |
### 问题清单
#### 1. Flash 大小配置错误
- **错误**:分区表需要 16MB但 sdkconfig 配置为 2MB
- **修复**`sdkconfig``CONFIG_ESPTOOLPY_FLASHSIZE` 改为 16MB
#### 2. WiFi 断开原因码未定义
- **错误**`WIFI_REASON_ASSOC_EXPIRE` 等符号在 v6.0 中未定义
- **修复**`wifi_manager.c` 中所有 reason code 添加 `#ifdef` 保护
#### 3. CMakeLists.txt 缺少源文件
- **错误**`llm_provider.c` 未加入编译列表,导致链接错误
- **修复**:添加 `ota/ota_manager.c` 到 SRCS
#### 4. 头文件缺失(共 16 处)
| 文件 | 缺失头文件 | 原因 |
|------|-----------|------|
| `cli/serial_cli.c` | `llm/llm_provider.h` | `llm_provider_set_api_key` |
| `llm/llm_provider.c` | `esp_http_client.h` | `esp_http_client_set_header` |
| `bus/message_bus.c` | `freertos/FreeRTOS.h`, `freertos/queue.h` | `xQueueCreate`, `QueueHandle_t` |
| `wifi/wifi_manager.c` | `esp_event.h` | `esp_event_handler_instance_register` |
| `wifi/wifi_manager.c` | `freertos/FreeRTOS.h`, `freertos/task.h`, `freertos/event_groups.h` | `xEventGroupCreate`, `vTaskDelay` |
| `ota/ota_manager.c` | `esp_system.h` | `esp_restart` |
| `channels/telegram/telegram_bot.c` | `freertos/FreeRTOS.h`, `freertos/task.h` | `xTaskCreatePinnedToCore`, `vTaskDelay` |
| `tools/tool_registry.c` | `<stdlib.h>` | `free()` |
| `proxy/http_proxy.c` | `<sys/time.h>` | `struct timeval` |
| `gateway/ws_server.c` | `<stdint.h>` | `uint8_t` |
### ESP-IDF v6.0 API 兼容性验证
以下 API 在 v6.0 中**仍然存在**,无需修改:
- `esp_spiffs_info()`
- `esp_websocket_client_send_bin()`
- `esp_tls_set_conn_sockfd()` / `esp_tls_set_conn_state()`
- `esp_console_new_repl_uart()` / `esp_console_new_repl_usb_serial_jtag()`
- `esp_https_ota()` + `esp_https_ota_config_t`
- `esp_wifi_set_config()`
### 烧录说明
ESP32-S3 使用 **USB 口**(内置 USB Serial/JTAG 控制器)烧录:
```powershell
idf.py -p COMx flash monitor
```
- 插 USB 口(标记为 `USB`),不是 UART 口
- 如遇连接失败,按住 BOOT 键再插线进入下载模式
---
## 讨论:增加国内大模型厂商接入
**日期**2026-03-31
**目标**:为 MimiClaw 增加硅基流动和火山方舟(豆包模型)接入
### 项目现状
- 当前支持Anthropic (Claude)、OpenAI (GPT)
- 运行平台ESP32-S3纯 C 语言
- 交互方式Telegram 机器人
### 国内厂商 API 兼容性
- **硅基流动**OpenAI 兼容Base URL `https://api.siliconflow.cn/v1`
- **火山方舟**OpenAI 兼容Base URL `https://ark.cn-beijing.volces.com/api/v3`
### 实现方案
由于两者都提供 OpenAI 兼容 API可复用现有 OpenAI 集成代码,只需:
1. 修改 Base URL
2. 调整认证方式Bearer Token
3. 处理模型名称规范
### 待解决问题
1. 认证方式差异确认
2. 模型名称规范
3. 工具调用格式兼容性验证
---
## 讨论NTP 时间管理 CLI 命令
**日期**2026-04-01
**目标**:完善时间管理 CLI支持手动同步、状态查看、自定义 NTP 服务器
### 背景
- 初始方案只有 `timezone_show` 显示时区和时间,缺少 NTP 同步状态和手动同步能力
- 用户需要能手动触发时间同步、查看上次同步时间、自定义 NTP 服务器
### 命令设计
| 命令 | 功能 |
|------|------|
| `ntp_status` | 查看完整状态(时区 + 本地时间 + 同步状态 + NTP 服务器 + 上次同步时间) |
| `ntp_sync` | 立即手动同步一次 |
| `ntp_set <server>` | 设置 NTP 服务器(存 NVS重启后生效 |
- 默认 NTP 服务器:`ntp.ntsc.ac.cn`(中国科学院国家授时中心)
- 同步状态:`synced`(已同步)、`syncing`(同步中)、`not_synced`(未同步)
### `ntp_status` 输出示例
```
Current timezone: Asia/Shanghai [NVS]
Local time: 2026-04-01 18:30:45 CST (Wednesday)
Time sync: synced
NTP server: ntp.ntsc.ac.cn
Last synced: 2026-04-01 18:00:12
```
### `set_timezone` 联动更新
- 设置时区后,如果检测到系统时间仍为 1970未同步自动触发一次 HTTP 时间获取
- 确保用户设置时区后立刻看到正确的本地时间
### 改动文件
| 文件 | 操作 |
|------|------|
| `main/time_sync/time_sync.h` | 增加 `time_sync_get_last_synced()``time_sync_set_server()` |
| `main/time_sync/time_sync.c` | 记录上次同步时间戳,支持自定义 NTP 服务器 |
| `main/cli/serial_cli.c` | 将 `timezone_show` 改为 `ntp_status`,新增 `ntp_sync``ntp_set` 命令 |
| `main/tools/tool_set_timezone.c` | 设置时区后检测时间有效性,必要时触发 HTTP 时间同步 |
---
## 讨论:时区设置功能
**日期**2026-04-01
**目标**:为 MimiClaw 添加可配置的时区支持,默认改为中国时区
### 背景
- 原默认时区为 `PST8PDT,M3.2.0,M11.1.0`(太平洋时间)
- 需要支持用户自定义时区特别是中国用户UTC+8
- 交互方式从 Telegram 改为飞书
### 实现方案
#### 存储方式
- **NVS 存储**:使用 `system_config` namespacekey 为 `timezone`
- **Build-time 默认值**`MIMI_TIMEZONE` 改为 `"CST-8"`
- **优先级**NVS 值 > Build-time 值
#### CLI 命令
```
set_timezone <TZ> # 例如: set_timezone CST-8 或 set_timezone Asia/Shanghai
timezone_show # 显示当前时区配置和本地时间
```
#### LLM 工具
- 新增 `set_timezone` 工具LLM 可通过对话设置时区
- 支持 POSIX 格式(`CST-8`)和城市名(`Asia/Shanghai`
- 内置 18 个城市名映射表
### 改动文件
| 文件 | 操作 |
|------|------|
| `main/mimi_config.h` | 默认时区改为 `CST-8`,添加 `MIMI_NVS_KEY_TIMEZONE` |
| `main/tools/tool_set_timezone.h` | **新建** |
| `main/tools/tool_set_timezone.c` | **新建** |
| `main/tools/tool_registry.c` | include 新头文件 + 注册工具 |
| `main/cli/serial_cli.c` | 添加 `set_timezone` / `ntp_status` / `ntp_sync` / `ntp_set` 命令 |
| `main/CMakeLists.txt` | 添加 `tool_set_timezone.c` 到 SRCS |
### 支持的时区格式
- POSIX: `CST-8`, `JST-9`, `EST5EDT,M3.2.0,M11.1.0`, `UTC0`
- 城市名: Asia/Shanghai, Asia/Tokyo, America/New_York 等 18 个预设
---
## 讨论:编译时模块开关(模块化配置)
**日期**2026-04-03
**分支**`feature/module-config`
**目标**:通过编译时配置选择性禁用不需要的模块,减少固件体积,消除未配置模块的警告日志
### 问题背景
1. **Task Watchdog 超时**ESP32-S3 运行一天后触发看门狗超时,怀疑是设计问题
2. **Telegram 警告日志**:用户使用飞书但未配置 Telegram控制台每 5 秒打印 "No bot token configured"
3. **代码冗余**Telegram、OpenAI 接口等未使用的模块仍然编译进固件
### 用户需求
用户希望:
1. 通过编译选项禁用不需要的模块(如 Telegram
2. 从源码层面直接过滤不用的组件,减少代码体积
3. 禁用模块后不触发警告日志
### 实现方案
#### 方案选择:编译时条件编译(方案 02
**优点**
- 直接减少 Flash 占用
- 零 RAM 占用,不创建任务
- 从源头消除警告日志
- 实现简单
**缺点**
- 切换模块需要重新编译
#### 技术实现
##### 1. 配置文件:`sdkconfig.defaults`
```c
// Channel Modules
CONFIG_MIMI_CHAN_TELEGRAM=n // 默认禁用
CONFIG_MIMI_CHAN_FEISHU=y // 默认启用
// Tool Modules
CONFIG_MIMI_TOOL_WEB_SEARCH=y
CONFIG_MIMI_TOOL_GPIO=n
// Optional Modules
CONFIG_MIMI_WS_SERVER=y
CONFIG_MIMI_WIFI_ONBOARD=y
CONFIG_MIMI_OTA=n
```
##### 2. CMakeLists.txt条件编译源文件
```cmake
if(CONFIG_MIMI_CHAN_TELEGRAM)
list(APPEND srcs "channels/telegram/telegram_bot.c")
endif()
```
##### 3. 头文件 stub调用方无感知
```c
// telegram_bot.h
#ifdef CONFIG_MIMI_CHAN_TELEGRAM
esp_err_t telegram_bot_init(void);
esp_err_t telegram_bot_start(void);
#else
static inline esp_err_t telegram_bot_init(void) { return ESP_OK; }
static inline esp_err_t telegram_bot_start(void) { return ESP_OK; }
#endif
```
### 修改文件清单
| 文件 | 修改内容 |
|------|----------|
| `sdkconfig.defaults` | 添加模块开关配置 |
| `main/CMakeLists.txt` | 条件编译源文件 |
| `main/channels/telegram/telegram_bot.h` | 添加 stub |
| `main/channels/feishu/feishu_bot.h` | 添加 stub |
| `main/gateway/ws_server.h` | 添加 stub |
| `main/onboard/wifi_onboard.h` | 添加 stub |
| `main/ota/ota_manager.h` | 添加 stub |
| `main/tools/tool_web_search.h` | 添加 stub |
| `main/tools/tool_gpio.h` | 添加 stub |
| `main/tools/tool_registry.c` | 条件注册工具 |
| `main/cli/serial_cli.c` | 条件注册 CLI 命令 |
| `main/mimi.c` | 条件调用模块 |
| `AGENTS.md` | 更新文档 |
### 模块依赖关系
- **Channel 模块**telegram、feishu
-`mimi.c` 调用init/start
-`outbound_dispatch_task` 调用send
- CLI 命令也需要条件编译
- **Tool 模块**web_search、gpio
-`tool_registry.c` 调用(注册 + 执行)
- CLI 命令也需要条件编译
- **可选模块**ws_server、wifi_onboard、ota
-`mimi.c` 调用
- `wifi_onboard` 禁用时需特殊处理(不能进入 captive portal
### 注意事项
1. **OTA 模块**:目前未初始化,但已编译
2. **工具描述中的渠道提示**cron_add 工具描述中提到 telegram可保留只是描述不影响功能
3. **get_time 工具**:使用 telegram.org 代理获取时间(技术原因,不属于 telegram_bot 模块)
### 预期效果
| 禁用项 | 效果 |
|--------|------|
| Telegram | 不编译 telegram_bot.c无 5 秒警告,节省约 15KB+ Flash |
| GPIO | 不编译 tool_gpio.c无 gpio_* 工具,节省约 5KB Flash |
| WebSocket | 不编译 ws_server.c节省约 10KB Flash |
| WiFi Onboard | 不能进入 captive portal 模式,需其他方式配置 WiFi |
---
## 讨论Kconfig 缺失导致模块开关失效
**日期**2026-04-04
**问题**编译后飞书命令消失、HTTP 配置页面不可用
### 现象
`sdkconfig.defaults` 中正确配置了 `CONFIG_MIMI_CHAN_FEISHU=y``CONFIG_MIMI_WIFI_ONBOARD=y`,执行 `idf.py fullclean && idf.py build` 后:
- 烧录后控制台没有飞书相关命令(`set_feishu_creds` 等)。
- 设备没有启动 HTTP 配置服务(`192.168.4.1` 无法访问)。
- 检查生成的 `sdkconfig` 文件,发现**完全没有**这些自定义配置项。
### 根因
ESP-IDF 的构建系统在生成 `sdkconfig` 时,**只会保留有 Kconfig 声明的配置项**。
- `sdkconfig.defaults` 仅用于提供默认值。
- 如果项目缺少 `Kconfig``Kconfig.projbuild` 文件来声明这些选项ESP-IDF 会认为它们是无效配置并直接丢弃。
- 之前的版本可能 `sdkconfig` 是手动维护的或缓存未清理,但 `fullclean` 后重新生成时就会丢失这些"无名"配置。
### 修复方案
创建 `main/Kconfig.projbuild` 文件,声明所有自定义模块开关。
### 认知修正
**ESP-IDF 配置系统工作流**
1. `Kconfig.projbuild`**声明**配置项(告诉系统"这是什么")。
2. `sdkconfig.defaults`:提供**默认值**(告诉系统"默认选什么")。
3. `sdkconfig`:构建系统根据前两者**自动生成**(实际编译用的配置)。
4. `CMakeLists.txt`:读取 `sdkconfig` 中的值**决定编译哪些文件**。
**结论**:新增模块开关时,**必须**创建 Kconfig 声明,否则 `sdkconfig.defaults` 无效。