Files
mimiclaw/taolun.md

214 lines
8.5 KiB
Markdown
Raw 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 配置稳定性修复
**日期**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 |
### 问题清单
#### 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. 工具调用格式兼容性验证
---
## 讨论:时区设置功能
**日期**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` / `timezone_show` 命令 |
| `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 个预设