Files
mimiclaw/taolun.md

8.5 KiB
Raw Blame History

讨论记录


讨论:系统时间同步 + 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

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

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 keysiliconflow_api_key)永远不会被加载到内存

同理,s_base_url 也存在相同问题。

为什么 Web 界面保存后能正常工作?

Web 界面的 /save 处理函数(wifi_onboard.c:377-408)会同时保存两份

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
  • 修复sdkconfigCONFIG_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 控制器)烧录:

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 个预设