From 3912eda8c193688ae5a67f529c0bd0d625d507b6 Mon Sep 17 00:00:00 2001 From: "Z.To" Date: Wed, 1 Apr 2026 06:38:00 +0800 Subject: [PATCH] docs: update changelog, TODO and discussion records with time-sync and NVS stability plan --- changelog.md | 12 ++++++- docs/TODO.md | 5 ++- taolun.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index e6ff51c..992b3a1 100644 --- a/changelog.md +++ b/changelog.md @@ -12,8 +12,18 @@ - 时区通过 NVS 持久化存储(`system_config` namespace) - 支持城市名映射(Asia/Shanghai → CST-8 等 18 个预设城市) - `config_show` 中显示当前时区配置 +- **SNTP 自动时间同步**(新增) + - WiFi 连接成功后自动从 `pool.ntp.org` 同步系统时间 + - 新增 `time_sync` 模块(`main/time_sync/`) + - `timezone_show` 命令增加 SNTP 同步状态显示 +- **NVS 配置安全机制**(新增) + - 启动时自动校验关键 NVS 命名空间完整性 + - 检测并修复损坏的 NVS 条目 + - 启用 ESP32-S3 Brownout Detection 防止供电不足导致 Flash 写入中断 ### 修复 +- **LLM Provider 初始化 Bug** — 修复 `llm_provider_init()` 中 provider-specific API key 和 Base URL 无法从 NVS 加载的问题(`llm_provider_get_api_key` 对当前 provider 直接返回内存缓存值,导致 NVS 数据永远不会被读取) +- **换 USB 口后配置失效** — 启用 Brownout Detection 防止供电不足时 NVS 写入中断,添加启动时 NVS 完整性校验 - ESP-IDF v6.0 编译适配 - 修复 flash 大小配置(2MB → 16MB) - 修复 WiFi 断开原因码未定义问题(添加 `#ifdef` 保护) @@ -32,7 +42,7 @@ ### 文档 - 新增 `docs/ESP-IDF-V6-MIGRATION.md` — ESP-IDF v6.0 迁移适配记录 -- 更新 `taolun.md` — 讨论记录整理 +- 更新 `taolun.md` — 讨论记录整理,新增时间同步和 NVS 配置稳定性问题讨论 --- diff --git a/docs/TODO.md b/docs/TODO.md index 996f851..9eaf9eb 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -94,10 +94,9 @@ - **MimiClaw**: Not implemented - **Recommendation**: Simple FreeRTOS timer that periodically checks HEARTBEAT.md -### [ ] Multi-LLM Provider Support +### [x] ~~Multi-LLM Provider Support~~ - **nanobot**: `providers/litellm_provider.py` — supports OpenRouter, Anthropic, OpenAI, Gemini, DeepSeek, Groq, Zhipu, vLLM via LiteLLM -- **MimiClaw**: Hardcoded to Anthropic Messages API -- **Recommendation**: Abstract LLM interface, support OpenAI-compatible API (most providers are compatible) +- **MimiClaw**: Supports Anthropic, OpenAI, SiliconFlow (硅基流动), Volcengine (火山方舟) — abstracted via `llm_provider.c` ### [ ] Voice Transcription - **nanobot**: `providers/transcription.py` — Groq Whisper API diff --git a/taolun.md b/taolun.md index 5b46e8f..a8124d3 100644 --- a/taolun.md +++ b/taolun.md @@ -2,10 +2,97 @@ --- -## 讨论:ESP-IDF v6.0 编译适配 +## 讨论:系统时间同步 + NVS 配置稳定性修复 -**日期**:2026-03-31 -**目标**:解决 ESP-IDF v6.0 编译失败问题,完成固件烧录 +**日期**: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 连接成功后自动从 `pool.ntp.org` 同步时间 +- 同步成功后自动应用已保存的时区配置 +- `timezone_show` 命令增加 SNTP 同步状态显示 + +### 问题 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 | ### 问题清单