2026-03-31 21:34:59 +08:00
|
|
|
|
# 讨论记录
|
2026-03-31 17:56:51 +08:00
|
|
|
|
|
2026-03-31 21:34:59 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
2026-04-01 06:38:00 +08:00
|
|
|
|
## 讨论:系统时间同步 + NVS 配置稳定性修复
|
2026-03-31 21:34:59 +08:00
|
|
|
|
|
2026-04-01 06:38:00 +08:00
|
|
|
|
**日期**: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 |
|
2026-03-31 21:34:59 +08:00
|
|
|
|
|
|
|
|
|
|
### 问题清单
|
|
|
|
|
|
|
|
|
|
|
|
#### 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 17:56:51 +08:00
|
|
|
|
|
|
|
|
|
|
**日期**:2026-03-31
|
2026-03-31 21:34:59 +08:00
|
|
|
|
**目标**:为 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 00:50:41 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 讨论:时区设置功能
|
|
|
|
|
|
|
|
|
|
|
|
**日期**:2026-04-01
|
|
|
|
|
|
**目标**:为 MimiClaw 添加可配置的时区支持,默认改为中国时区
|
|
|
|
|
|
|
|
|
|
|
|
### 背景
|
|
|
|
|
|
- 原默认时区为 `PST8PDT,M3.2.0,M11.1.0`(太平洋时间)
|
|
|
|
|
|
- 需要支持用户自定义时区,特别是中国用户(UTC+8)
|
|
|
|
|
|
- 交互方式从 Telegram 改为飞书
|
|
|
|
|
|
|
|
|
|
|
|
### 实现方案
|
|
|
|
|
|
|
|
|
|
|
|
#### 存储方式
|
|
|
|
|
|
- **NVS 存储**:使用 `system_config` namespace,key 为 `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 个预设
|