From fa4582bf70f1ce9d162bd902025aeaeb22119378 Mon Sep 17 00:00:00 2001 From: crispyberry Date: Thu, 5 Feb 2026 18:56:04 +0800 Subject: [PATCH] feat: wire up app_main with all subsystems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Startup sequence: NVS → SPIFFS → bus → memory → WiFi → CLI → Telegram → agent loop → WebSocket → outbound dispatch. CMakeLists registers all source files and ESP-IDF dependencies. Co-Authored-By: Claude Opus 4.5 --- main/CMakeLists.txt | 22 +++++++- main/mimi.c | 131 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index f44f8b3..f7e9f3c 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,20 @@ -idf_component_register(SRCS "mimi.c" - INCLUDE_DIRS ".") +idf_component_register( + SRCS + "mimi.c" + "bus/message_bus.c" + "wifi/wifi_manager.c" + "telegram/telegram_bot.c" + "llm/llm_proxy.c" + "agent/agent_loop.c" + "agent/context_builder.c" + "memory/memory_store.c" + "memory/session_mgr.c" + "gateway/ws_server.c" + "cli/serial_cli.c" + "ota/ota_manager.c" + INCLUDE_DIRS + "." + REQUIRES + nvs_flash esp_wifi esp_netif esp_http_client esp_http_server + esp_https_ota esp_event json spiffs console vfs +) diff --git a/main/mimi.c b/main/mimi.c index 7b66f33..ba04578 100644 --- a/main/mimi.c +++ b/main/mimi.c @@ -1,6 +1,137 @@ #include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_event.h" +#include "esp_system.h" +#include "esp_heap_caps.h" +#include "esp_spiffs.h" +#include "nvs_flash.h" + +#include "mimi_config.h" +#include "bus/message_bus.h" +#include "wifi/wifi_manager.h" +#include "telegram/telegram_bot.h" +#include "llm/llm_proxy.h" +#include "agent/agent_loop.h" +#include "memory/memory_store.h" +#include "memory/session_mgr.h" +#include "gateway/ws_server.h" +#include "cli/serial_cli.h" + +static const char *TAG = "mimi"; + +static esp_err_t init_nvs(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_LOGW(TAG, "NVS partition truncated, erasing..."); + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + return ret; +} + +static esp_err_t init_spiffs(void) +{ + esp_vfs_spiffs_conf_t conf = { + .base_path = MIMI_SPIFFS_BASE, + .partition_label = NULL, + .max_files = 10, + .format_if_mount_failed = true, + }; + + esp_err_t ret = esp_vfs_spiffs_register(&conf); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "SPIFFS mount failed: %s", esp_err_to_name(ret)); + return ret; + } + + size_t total = 0, used = 0; + esp_spiffs_info(NULL, &total, &used); + ESP_LOGI(TAG, "SPIFFS: total=%d, used=%d", (int)total, (int)used); + + return ESP_OK; +} + +/* Outbound dispatch task: reads from outbound queue and routes to channels */ +static void outbound_dispatch_task(void *arg) +{ + ESP_LOGI(TAG, "Outbound dispatch started"); + + while (1) { + mimi_msg_t msg; + if (message_bus_pop_outbound(&msg, UINT32_MAX) != ESP_OK) continue; + + ESP_LOGI(TAG, "Dispatching response to %s:%s", msg.channel, msg.chat_id); + + if (strcmp(msg.channel, MIMI_CHAN_TELEGRAM) == 0) { + telegram_send_message(msg.chat_id, msg.content); + } else if (strcmp(msg.channel, MIMI_CHAN_WEBSOCKET) == 0) { + ws_server_send(msg.chat_id, msg.content); + } else { + ESP_LOGW(TAG, "Unknown channel: %s", msg.channel); + } + + free(msg.content); + } +} void app_main(void) { + ESP_LOGI(TAG, "========================================"); + ESP_LOGI(TAG, " MimiClaw - ESP32-S3 AI Agent"); + ESP_LOGI(TAG, "========================================"); + /* Print memory info */ + ESP_LOGI(TAG, "Internal free: %d bytes", + (int)heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + ESP_LOGI(TAG, "PSRAM free: %d bytes", + (int)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + + /* Phase 1: Core infrastructure */ + ESP_ERROR_CHECK(init_nvs()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(init_spiffs()); + + /* Initialize subsystems */ + ESP_ERROR_CHECK(message_bus_init()); + ESP_ERROR_CHECK(memory_store_init()); + ESP_ERROR_CHECK(session_mgr_init()); + ESP_ERROR_CHECK(wifi_manager_init()); + ESP_ERROR_CHECK(telegram_bot_init()); + ESP_ERROR_CHECK(llm_proxy_init()); + ESP_ERROR_CHECK(agent_loop_init()); + + /* Start Serial CLI first (works without WiFi) */ + ESP_ERROR_CHECK(serial_cli_init()); + + /* Start WiFi */ + esp_err_t wifi_err = wifi_manager_start(); + if (wifi_err == ESP_OK) { + ESP_LOGI(TAG, "Waiting for WiFi connection..."); + if (wifi_manager_wait_connected(30000) == ESP_OK) { + ESP_LOGI(TAG, "WiFi connected: %s", wifi_manager_get_ip()); + + /* Start network-dependent services */ + ESP_ERROR_CHECK(telegram_bot_start()); + ESP_ERROR_CHECK(agent_loop_start()); + ESP_ERROR_CHECK(ws_server_start()); + + /* Outbound dispatch task */ + xTaskCreatePinnedToCore( + outbound_dispatch_task, "outbound", + MIMI_OUTBOUND_STACK, NULL, + MIMI_OUTBOUND_PRIO, NULL, MIMI_OUTBOUND_CORE); + + ESP_LOGI(TAG, "All services started!"); + } else { + ESP_LOGW(TAG, "WiFi connection timeout. Configure via CLI: wifi_set "); + } + } else { + ESP_LOGW(TAG, "No WiFi credentials. Configure via CLI: wifi_set "); + } + + ESP_LOGI(TAG, "MimiClaw ready. Type 'help' for CLI commands."); }