

xiaozhi-esp32/
├── .gitignore # Git忽略文件
├── CMakeLists.txt # 工程构建文件
├── LICENSE # MIT许可证
├── README.md # 项目说明文档
├── README_en.md # 英文说明文档
├── README_ja.md # 日文说明文档
├── partitions.csv # 16M Flash分区表
├── partitions_32M_sensecap.csv # 32M Flash分区表
├── partitions_4M.csv # 4M Flash分区表
├── partitions_8M.csv # 8M Flash分区表
├── sdkconfig.defaults # 默认配置文件
├── sdkconfig.defaults.esp32c3 # ESP32-C3配置
├── sdkconfig.defaults.esp32s3 # ESP32-S3配置
├── docs/ # 文档目录
├── scripts/ # 脚本目录
├── .github/ # GitHub Actions配置
└── main/ # 主要源码目录
main/
├── main.cc # 程序入口文件
├── application.cc # 应用核心逻辑
├── application.h # 应用头文件
├── CMakeLists.txt # 构建配置
├── Kconfig.projbuild # 项目配置
├── boards/ # 开发板实现
│ ├── bread-compact-wifi/ # 面包板WiFi版本
│ ├── bread-compact-ml307/ # 面包板4G版本
│ ├── bread-compact-esp32/ # 面包板ESP32版本
│ └── esp-box-3/ # ESP-BOX-3版本
├── audio_codecs/ # 音频编解码器
│ ├── audio_codec.h # 音频编解码器基类
│ ├── no_audio_codec.cc # 无音频编解码器
│ ├── es8311_audio_codec.cc # ES8311编解码器
│ └── es8388_audio_codec.cc # ES8388编解码器
├── display/ # 显示相关
│ ├── display.h # 显示基类
│ ├── no_display.cc # 无显示设备
│ ├── oled_display.cc # OLED显示
│ └── lcd_display.cc # LCD显示
├── led/ # LED控制
│ ├── led.h # LED基类
│ ├── no_led.cc # 无LED设备
│ ├── single_led.cc # 单LED控制
│ └── circular_strip.cc # 环形LED灯带
├── protocols/ # 网络协议
│ ├── protocol.h # 协议基类
│ ├── websocket_protocol.cc # WebSocket协议
│ └── mqtt_protocol.cc # MQTT协议
├── iot/ # 物联网设备管理
│ ├── thing_manager.h # 设备管理器
│ ├── thing.h # 设备基类
│ ├── speaker.cc # 扬声器设备
│ ├── battery.cc # 电池设备
│ └── backlight.cc # 背光设备
├── audio_processing/ # 音频处理
│ ├── wake_word_detect.h # 唤醒词检测
│ ├── wake_word_detect.cc # 唤醒词检测实现
│ ├── audio_processor.h # 音频处理器
│ └── audio_processor.cc # 音频处理器实现
└── components/ # 自定义组件
├── opus_encoder/ # Opus编码器
├── opus_decoder/ # Opus解码器
└── ota/ # OTA更新
main.cc - 程序入口:
// main.cc 程序入口
extern"C"void app_main(void) {
// 初始化默认事件循环
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 初始化NVS flash
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, "Erasing NVS flash to fix corruption");
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 启动应用程序
Application::GetInstance().Start();
}
CMakeLists.txt - 构建配置:
# main/CMakeLists.txt
idf_component_register(
SRCS "main.cc"
"application.cc"
"boards/bread-compact-wifi/board.cc"
"audio_codecs/audio_codec.cc"
"display/display.cc"
"led/led.cc"
"protocols/protocol.cc"
"iot/thing_manager.cc"
"audio_processing/wake_word_detect.cc"
INCLUDE_DIRS "."
REQUIRES esp_wifi esp_http_client esp_websocket_client
)
Application类职责:
Application类职责:
├── 设备状态管理
│ ├── 空闲状态 (kDeviceStateIdle)
│ ├── 监听状态 (kDeviceStateListening)
│ ├── 说话状态 (kDeviceStateSpeaking)
│ └── 激活状态 (kDeviceStateActivating)
├── 音频处理协调
│ ├── 音频输入处理
│ ├── 音频输出处理
│ ├── 音频编解码
│ └── 音频重采样
├── 网络通信管理
│ ├── WebSocket连接
│ ├── 消息发送接收
│ └── 连接状态监控
├── 任务调度
│ ├── 主循环任务
│ ├── 后台任务
│ └── 定时任务
└── 系统管理
├── 固件更新
├── 设备重启
└── 错误处理
Application类核心方法:
class Application {
public:
// 单例模式
static Application& GetInstance();
// 应用启动
void Start();
// 主循环
void MainLoop();
// 状态管理
void SetDeviceState(DeviceState state);
DeviceState GetDeviceState() const;
// 音频处理
void InputAudio();
void OutputAudio();
// 网络通信
void StartListening();
void StopListening();
// 系统管理
void CheckNewVersion();
void Reboot();
private:
volatile DeviceState device_state_;
std::unique_ptr<Protocol> protocol_;
std::unique_ptr<OpusEncoderWrapper> opus_encoder_;
std::unique_ptr<OpusDecoderWrapper> opus_decoder_;
// 其他成员变量...
};
Board类职责:
Board类职责:
├── 硬件抽象
│ ├── 统一硬件接口
│ ├── 屏蔽硬件差异
│ └── 提供硬件访问
├── 设备管理
│ ├── 音频编解码器
│ ├── 显示设备
│ ├── LED控制
│ └── 按键处理
├── 网络连接
│ ├── WiFi连接
│ ├── 4G连接
│ └── 网络状态
└── 系统信息
├── 设备类型
├── 设备ID
└── 系统状态
Board类层次结构:
// 抽象基类
class Board {
public:
virtual ~Board() = default;
virtual std::string GetBoardType() = 0;
virtual AudioCodec* GetAudioCodec() = 0;
virtual Display* GetDisplay() = 0;
virtual Led* GetLed() = 0;
virtual void StartNetwork() = 0;
};
// WiFi板卡基类
class WifiBoard :public Board {
public:
virtual void StartNetwork() override;
virtual void EnterWifiConfigMode();
virtual void ResetWifiConfiguration();
};
// 4G板卡基类
class Ml307Board :public Board {
public:
virtual void StartNetwork() override;
virtual void WaitForNetworkReady();
};
ThingManager类职责:
ThingManager类职责:
├── 设备管理
│ ├── 设备注册
│ ├── 设备查找
│ └── 设备状态
├── 属性管理
│ ├── 属性获取
│ ├── 属性设置
│ └── 属性监控
├── 方法调用
│ ├── 方法执行
│ ├── 参数传递
│ └── 结果返回
└── 数据交换
├── JSON序列化
├── 数据格式转换
└── 协议适配
ThingManager类实现:
class ThingManager {
public:
// 单例模式
static ThingManager& GetInstance();
// 设备管理
void AddThing(Thing* thing);
void RemoveThing(Thing* thing);
// 属性管理
std::string GetDescriptorsJson();
std::string GetStatesJson();
// 方法调用
void Invoke(const cJSON* command);
private:
std::vector<Thing*> things_;
std::mutex things_mutex_;
};
小智AI系统架构:
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Application │ │ ThingManager │ │ Protocol │ │
│ │ (核心管理) │ │ (设备管理) │ │ (网络通信) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Hardware Layer │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Board │ │ AudioCodec │ │ Display │ │
│ │ (硬件抽象) │ │ (音频编解码) │ │ (显示设备) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Led │ │ Button │ │ Network │ │
│ │ (LED控制) │ │ (按键处理) │ │ (网络连接) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
类关系说明:
├── Application
│ ├── 依赖 Board (通过GetInstance获取)
│ ├── 依赖 ThingManager (通过GetInstance获取)
│ ├── 包含 Protocol (智能指针)
│ ├── 包含 OpusEncoder (智能指针)
│ └── 包含 OpusDecoder (智能指针)
├── Board
│ ├── 抽象基类
│ ├── 派生类 WifiBoard
│ ├── 派生类 Ml307Board
│ └── 提供硬件访问接口
├── ThingManager
│ ├── 管理 Thing 对象集合
│ ├── 提供设备描述信息
│ └── 处理设备方法调用
└── Protocol
├── 抽象基类
├── 派生类 WebsocketProtocol
└── 派生类 MqttProtocol
分层架构优势:
分层架构优势:
├── 职责分离
│ ├── 每层专注特定功能
│ ├── 降低耦合度
│ └── 提高可维护性
├── 可扩展性
│ ├── 易于添加新功能
│ ├── 支持硬件升级
│ └── 协议扩展
├── 可测试性
│ ├── 单元测试
│ ├── 集成测试
│ └── 模拟测试
└── 可复用性
├── 组件复用
├── 代码复用
└── 设计复用
依赖关系:
依赖关系:
├── 上层依赖下层
│ ├── Application 依赖 Board
│ ├── Application 依赖 ThingManager
│ └── Application 依赖 Protocol
├── 下层不依赖上层
│ ├── Board 不依赖 Application
│ ├── ThingManager 不依赖 Application
│ └── Protocol 不依赖 Application
└── 同层之间解耦
├── Board 与 ThingManager 解耦
├── Protocol 与 Board 解耦
└── 通过接口交互
步骤1:查看main.cc入口函数
// main/main.cc
extern"C"void app_main(void) {
// 初始化默认事件循环
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 初始化NVS flash
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, "Erasing NVS flash to fix corruption");
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 启动应用程序
Application::GetInstance().Start();
}
步骤2:跟踪Application::GetInstance()
// main/application.h
class Application {
public:
static Application& GetInstance() {
static Application instance;
return instance;
}
void Start();
// 其他方法...
};
步骤3:跟踪Application::Start()方法
// main/application.cc
void Application::Start() {
// 获取板卡对象
auto& board = Board::GetInstance();
// 设置设备状态
SetDeviceState(kDeviceStateStarting);
// 获取显示和音频编解码器
auto display = board.GetDisplay();
auto codec = board.GetAudioCodec();
// 配置音频编解码器
opus_decode_sample_rate_ = codec->output_sample_rate();
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(opus_decode_sample_rate_, 1);
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
// 设置音频编解码器回调
codec->OnInputReady([this, codec]() {
BaseType_t higher_priority_task_woken = pdFALSE;
xEventGroupSetBitsFromISR(event_group_, AUDIO_INPUT_READY_EVENT, &higher_priority_task_woken);
return higher_priority_task_woken == pdTRUE;
});
codec->OnOutputReady([this]() {
BaseType_t higher_priority_task_woken = pdFALSE;
xEventGroupSetBitsFromISR(event_group_, AUDIO_OUTPUT_READY_EVENT, &higher_priority_task_woken);
return higher_priority_task_woken == pdTRUE;
});
codec->Start();
// 创建主循环任务
xTaskCreate([](void* arg) {
Application* app = (Application*)arg;
app->MainLoop();
vTaskDelete(NULL);
}, "main_loop", 4096 * 2, this, 4, nullptr);
// 启动网络
board.StartNetwork();
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
// 初始化协议
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
protocol_ = std::make_unique<WebsocketProtocol>();
#else
protocol_ = std::make_unique<MqttProtocol>();
#endif
// 设置协议回调
protocol_->OnNetworkError([this](conststd::string& message) {
SetDeviceState(kDeviceStateIdle);
Alert(Lang::Strings::ERROR, message.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION);
});
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
std::lock_guard<std::mutex> lock(mutex_);
if (device_state_ == kDeviceStateSpeaking) {
audio_decode_queue_.emplace_back(std::move(data));
}
});
protocol_->Start();
// 检查固件版本
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
ota_.SetHeader("Client-Id", board.GetUuid());
ota_.SetHeader("Accept-Language", Lang::CODE);
auto app_desc = esp_app_get_description();
ota_.SetHeader("User-Agent", std::string(BOARD_NAME "/") + app_desc->version);
xTaskCreate([](void* arg) {
Application* app = (Application*)arg;
app->CheckNewVersion();
vTaskDelete(NULL);
}, "check_new_version", 4096 * 2, this, 2, nullptr);
// 初始化音频处理器(可选)
#if CONFIG_USE_AUDIO_PROCESSOR
audio_processor_.Initialize(codec->input_channels(), codec->input_reference());
audio_processor_.OnOutput([this](std::vector<int16_t>&& data) {
background_task_->Schedule([this, data = std::move(data)]() mutable {
opus_encoder_->Encode(std::move(data), [this](std::vector<uint8_t>&& opus) {
Schedule([this, opus = std::move(opus)]() {
protocol_->SendAudio(opus);
});
});
});
});
#endif
// 初始化唤醒词检测(可选)
#if CONFIG_USE_WAKE_WORD_DETECT
wake_word_detect_.Initialize(codec->input_channels(), codec->input_reference());
wake_word_detect_.OnVadStateChange([this](bool speaking) {
Schedule([this, speaking]() {
if (device_state_ == kDeviceStateListening) {
if (speaking) {
voice_detected_ = true;
} else {
voice_detected_ = false;
}
auto led = Board::GetInstance().GetLed();
led->OnStateChanged();
}
});
});
wake_word_detect_.OnWakeWordDetected([this](conststd::string& wake_word) {
Schedule([this, &wake_word]() {
if (device_state_ == kDeviceStateIdle) {
// 处理唤醒词
} elseif (device_state_ == kDeviceStateSpeaking) {
// 中止当前播放
} elseif (device_state_ == kDeviceStateActivating) {
// 处理激活状态
}
wake_word_detect_.StartDetection();
});
});
wake_word_detect_.StartDetection();
#endif
// 最终设置
SetDeviceState(kDeviceStateIdle);
esp_timer_start_periodic(clock_timer_handle_, 1000000);
}
步骤4:跟踪Board::GetInstance()
// main/boards/board.h
class Board {
public:
static Board& GetInstance() {
static Board* instance = static_cast<Board*>(create_board());
return *instance;
}
virtual std::string GetBoardType() = 0;
virtual AudioCodec* GetAudioCodec() = 0;
virtual Display* GetDisplay() = 0;
virtual Led* GetLed() = 0;
virtual void StartNetwork() = 0;
};
步骤5:跟踪create_board()函数
// main/boards/bread-compact-wifi/board.cc
#define DECLARE_BOARD(BOARD_CLASS_NAME) \
void* create_board() { \
return new BOARD_CLASS_NAME(); \
}
DECLARE_BOARD(BreadCompactWifiBoard)
程序启动流程:
程序启动流程:
1. app_main() 入口函数
2. 初始化事件循环
3. 初始化NVS flash
4. 调用 Application::GetInstance().Start()
5. 获取 Board 实例
6. 设置设备状态
7. 初始化音频编解码器
8. 创建主循环任务
9. 启动网络连接
10. 初始化协议
11. 检查固件版本
12. 初始化音频处理器
13. 初始化唤醒词检测
14. 设置最终状态
关键调用链:
app_main()
└── Application::GetInstance().Start()
├── Board::GetInstance()
├── SetDeviceState()
├── 音频编解码器初始化
├── 主循环任务创建
├── 网络启动
├── 协议初始化
├── 固件版本检查
├── 音频处理器初始化
└── 唤醒词检测初始化
参考资料
[1]
UML类图教程: https://www.uml.org.cn/oobject/201211231.asp
[2]
设计模式: https://refactoring.guru/design-patterns
[3]
架构设计原则: https://martinfowler.com/architecture/