资讯动态

xiaozhi-esp32 自定义开发板接入指南:从 config.json 到固件构建的完整流程

发布时间:2026/9/11 20:32:27 来源:尧图企业网站定制
xiaozhi-esp32 自定义开发板接入指南从 config.json 到固件构建的完整流程【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32本指南以 docs/custom-board.md 为核心骨架讲解如何在 xiaozhi-esp32 开源项目中从零新增一款自定义开发板包括目录结构约定、config.h/config.json配置要点、板级 C 类的实现、Kconfig 与 CMake 的构建系统接入以及通过scripts/build.py一键配置编译的完整流程。读完本文你将具备把任意基于 ESP32 系列芯片的硬件音频编解码器、屏幕、按键、4G 模块等组合接入该项目并生成带独立 OTA 固件通道的完整能力。适用前提本文基于当前仓库的实际代码main/boards/下 70 款板级实现、scripts/build.py、main/Kconfig.projbuild 与 main/CMakeLists.txt编写文中涉及的 ESP-IDF、LVGL 等外部工具链的使用以其官方文档为准。一、为什么需要“自定义开发板”机制xiaozhi-esp32 是一个基于 ESP32 系列芯片的 AI 语音助手项目支持 70 多款官方与社区开发板每一款都在main/boards/下拥有自己的独立目录。新增硬件支持的本质就是为你的板卡建立一套身份 配置 实现三件套身份identity由config.json中的type、name字段决定固件会向服务端上报该标识OTA 升级也依赖它定位固件配置configurationconfig.h中的引脚、采样率、屏幕参数等硬件级设定实现implementationxxx_board.cc中继承基类的板级初始化与虚函数实现。最重要的一条警告永远不要覆盖已有板卡的配置Warning对于 IO 配置与现有板卡不同的自定义硬件绝不要直接覆盖原有板卡的配置文件。必须新建一种板型或利用config.json的builds数组生成固件名不同、sdkconfig宏不同的独立变体。构建请使用python scripts/build.py [board-directory]。原因在 docs/custom-board.md 中有明确说明覆盖已有板卡配置是危险的因为 OTA 更新可能用原板卡的官方固件替换你的自定义固件。每一款板卡都必须拥有唯一身份和自己的固件更新通道——这与 scripts/build.py 中_collect_variants()对type/name全局唯一性的严格校验重复即报错是相互印证的。二、目录布局约定一个板卡目录通常包含以下文件文件作用xxx_board.cc板级初始化和胶水代码板级类、虚函数覆写、DECLARE_BOARD注册config.h引脚分配与板级设置config.json上报的板卡类型与发布配置供 CMake 和scripts/build.py消费README.md板卡专属说明硬件要求、烧录方法、特殊注意事项板卡可以平铺在main/boards/下也可以按厂商分组放在main/boards/manufacturer/board/下详见后文厂商子目录一节。当前仓库两种布局都有实例例如平铺的 main/boards/bread-compact-wifi/ 与分组存放的 main/boards/waveshare/esp32-p4-nano/。三、第一步创建板卡目录在main/boards/下按[厂商]-[型号]的命名风格新建目录示例m5stack-tab5mkdir main/boards/my-custom-board命名约定目录名使用小写字母与连字符如waveshare、lceda-course-examples便于与 Kconfig 符号、构建产物名称保持一致。四、第二步编写配置文件4.1 config.h引脚与硬件参数config.h集中定义全部硬件设定主要包括音频采样率与 I2S 引脚映射音频编解码器 I2C 地址与引脚按键与 LED 引脚显示参数与引脚。以下示例取自 docs/custom-board.md参照lichuang-c3-dev风格AUDIO_I2S_GPIO_*系列宏被 main/boards/common/wifi_board.h 等基类通过GetAudioCodec()间接消费#ifndef _BOARD_CONFIG_H_ #define _BOARD_CONFIG_H_ #include driver/gpio.h // Audio #define AUDIO_INPUT_SAMPLE_RATE 24000 #define AUDIO_OUTPUT_SAMPLE_RATE 24000 #define AUDIO_I2S_GPIO_MCLK GPIO_NUM_10 #define AUDIO_I2S_GPIO_WS GPIO_NUM_12 #define AUDIO_I2S_GPIO_BCLK GPIO_NUM_8 #define AUDIO_I2S_GPIO_DIN GPIO_NUM_7 #define AUDIO_I2S_GPIO_DOUT GPIO_NUM_11 #define AUDIO_CODEC_PA_PIN GPIO_NUM_13 #define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_0 #define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_1 #define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR // Buttons #define BOOT_BUTTON_GPIO GPIO_NUM_9 // Display #define DISPLAY_SPI_SCK_PIN GPIO_NUM_3 #define DISPLAY_SPI_MOSI_PIN GPIO_NUM_5 #define DISPLAY_DC_PIN GPIO_NUM_6 #define DISPLAY_SPI_CS_PIN GPIO_NUM_4 #define DISPLAY_WIDTH 320 #define DISPLAY_HEIGHT 240 #define DISPLAY_MIRROR_X true #define DISPLAY_MIRROR_Y false #define DISPLAY_SWAP_XY true #define DISPLAY_OFFSET_X 0 #define DISPLAY_OFFSET_Y 0 #define DISPLAY_BACKLIGHT_PIN GPIO_NUM_2 #define DISPLAY_BACKLIGHT_OUTPUT_INVERT true #endif // _BOARD_CONFIG_H_参数说明与取值提示AUDIO_INPUT/OUTPUT_SAMPLE_RATE语音链路采样率项目常见取值为 16000 或 24000需与所选音频编解码器及服务端协议匹配AUDIO_CODEC_PA_PIN功放PA使能引脚若硬件无独立 PA 使能可留空或不定义DISPLAY_MIRROR_X/Y与DISPLAY_SWAP_XY屏幕镜像与横竖屏交换开关与后文esp_lcd_panel_mirror()/esp_lcd_panel_swap_xy()调用一一对应DISPLAY_BACKLIGHT_OUTPUT_INVERT背光 PWM 极性是否反转取决于背光驱动电路是共阳还是共阴DISPLAY_WIDTH/HEIGHT/OFFSET_*分辨率与偏移用于SpiLcdDisplay的初始化参数。4.2 config.json兼容敏感的上报身份与构建配置config.json定义了对兼容性敏感的上报类型并驱动scripts/build.py{ type: my-custom-board, target: esp32s3, builds: [ { name: my-custom-board, sdkconfig_append: [ CONFIG_ESPTOOLPY_FLASHSIZE_8MBy, CONFIG_PARTITION_TABLE_CUSTOM_FILENAME\partitions/v2/8m.csv\ ] } ] }字段含义字段说明type兼容敏感的板卡家族标识固件上报给服务端。发布后应保持稳定变更会导致 OTA 通道失效target目标芯片必须与真实硬件一致esp32、esp32s3、esp32c3、esp32c6、esp32p4等name发布构建上报的固件变体名通常与type一致sdkconfig_append追加到默认配置中的额外 sdkconfig 行命名硬性约束type与name只能包含小写字母、数字、句点.与连字符-不允许下划线、空格和大写字母。这条规则在 scripts/build.py 中由_REPORTED_IDENTIFIER_PATTERN re.compile(r^[a-z0-9.-]$)与_validate_reported_identifier()强制校验违规会直接抛出ValueError。常用的sdkconfig_append条目// Flash size CONFIG_ESPTOOLPY_FLASHSIZE_4MBy CONFIG_ESPTOOLPY_FLASHSIZE_8MBy // Partition table CONFIG_PARTITION_TABLE_CUSTOM_FILENAME\partitions/v2/4m.csv\ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME\partitions/v2/8m.csv\ // Audio pipeline CONFIG_USE_DEVICE_AECy // enable on-device AEC项目在适用目标上默认使用 16MB Flash 与partitions/v2/16m.csv。不要重复写入与项目/目标默认值一致的条目只在确有板卡级差异时才使用sdkconfig_append覆盖。分区表定义见 partitions/v2/。不要在板卡config.json中选择语言或指定唤醒词。这些属于用户构建选项必须统一通过menuconfig或构建脚本参数配置以保证 CLI、Agent 与在线构建共用同一套接口这也正是 scripts/build.py 提供--language/--wake-word参数的原因。多变体builds 数组示例以仓库现有板卡 main/boards/bread-compact-wifi/config.json 为例同一块板通过两个 build 条目分别产出 128x32 与 128x64 OLED 的固件变体{ type: bread-compact-wifi, target: esp32s3, builds: [ { name: bread-compact-wifi, sdkconfig_append: [CONFIG_OLED_SSD1306_128X32y] }, { name: bread-compact-wifi-128x64, sdkconfig_append: [CONFIG_OLED_SSD1306_128X64y] } ] }此外builds条目还可选配idf_version字段如6.0做 ESP-IDF 版本门控由 scripts/build.py 的_get_builds_for_idf()处理便于在同一板卡下兼容不同 IDF 版本。五、第三步实现板级类创建my_custom_board.cc一个基础板级类包含四部分类声明继承WifiBoardWiFi 板或Ml307Board4G 板初始化辅助方法I2C、显示、按键、IoT/MCP 工具等虚函数覆写GetAudioCodec()、GetDisplay()、GetBacklight()等板卡注册DECLARE_BOARD(ClassName)。完整示例来自 docs/custom-board.md#include wifi_board.h #include codecs/es8311_audio_codec.h #include display/lcd_display.h #include application.h #include button.h #include config.h #include mcp_server.h #include esp_log.h #include driver/i2c_master.h #include driver/spi_common.h #define TAG MyCustomBoard class MyCustomBoard : public WifiBoard { private: i2c_master_bus_handle_t codec_i2c_bus_; Button boot_button_; LcdDisplay* display_; void InitializeI2c() { i2c_master_bus_config_t i2c_bus_cfg { .i2c_port I2C_NUM_0, .sda_io_num AUDIO_CODEC_I2C_SDA_PIN, .scl_io_num AUDIO_CODEC_I2C_SCL_PIN, .clk_source I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt 7, .intr_priority 0, .trans_queue_depth 0, .flags { .enable_internal_pullup 1, }, }; ESP_ERROR_CHECK(i2c_new_master_bus(i2c_bus_cfg, codec_i2c_bus_)); } void InitializeSpi() { spi_bus_config_t buscfg {}; buscfg.mosi_io_num DISPLAY_SPI_MOSI_PIN; buscfg.miso_io_num GPIO_NUM_NC; buscfg.sclk_io_num DISPLAY_SPI_SCK_PIN; buscfg.quadwp_io_num GPIO_NUM_NC; buscfg.quadhd_io_num GPIO_NUM_NC; buscfg.max_transfer_sz DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t); ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, buscfg, SPI_DMA_CH_AUTO)); } void InitializeButtons() { boot_button_.OnClick([this]() { auto app Application::GetInstance(); if (app.GetDeviceState() kDeviceStateStarting) { EnterWifiConfigMode(); return; } app.ToggleChatState(); }); } void InitializeDisplay() { esp_lcd_panel_io_handle_t panel_io nullptr; esp_lcd_panel_handle_t panel nullptr; esp_lcd_panel_io_spi_config_t io_config {}; io_config.cs_gpio_num DISPLAY_SPI_CS_PIN; io_config.dc_gpio_num DISPLAY_DC_PIN; io_config.spi_mode 2; io_config.pclk_hz 80 * 1000 * 1000; io_config.trans_queue_depth 10; io_config.lcd_cmd_bits 8; io_config.lcd_param_bits 8; ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, io_config, panel_io)); esp_lcd_panel_dev_config_t panel_config {}; panel_config.reset_gpio_num GPIO_NUM_NC; panel_config.rgb_ele_order LCD_RGB_ELEMENT_ORDER_RGB; panel_config.bits_per_pixel 16; ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, panel_config, panel)); esp_lcd_panel_reset(panel); esp_lcd_panel_init(panel); esp_lcd_panel_invert_color(panel, true); esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY); esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y); display_ new SpiLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY); } void InitializeTools() { // Register MCP tools here; see docs/mcp-usage.md. } public: MyCustomBoard() : boot_button_(BOOT_BUTTON_GPIO) { InitializeI2c(); InitializeSpi(); InitializeDisplay(); InitializeButtons(); InitializeTools(); GetBacklight()-SetBrightness(100); } virtual AudioCodec* GetAudioCodec() override { static Es8311AudioCodec audio_codec( codec_i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE, AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN, AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR); return audio_codec; } virtual Display* GetDisplay() override { return display_; } virtual Backlight* GetBacklight() override { static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return backlight; } }; DECLARE_BOARD(MyCustomBoard);实现要点基类WifiBoard定义于 main/boards/common/wifi_board.h它继承自Board默认的GetAudioCodec()返回nullptr并提供EnterWifiConfigMode()等辅助方法板级类只需覆写自己需要的虚函数按键回调中kDeviceStateStarting状态下进入 WiFi 配网模式EnterWifiConfigMode()否则切换对话状态app.ToggleChatState()这是项目通用的按键交互范式InitializeTools()留空即支持 MCP 工具注册如喇叭控制、亮度调节、电量读取等详见 MCP 使用指南若板卡带摄像头可参考 main/boards/common/esp32_camera.h 或 main/boards/common/esp_video.h 接入。六、第四步接入构建系统6.1 在 Kconfig 中添加条目打开 main/Kconfig.projbuild在choice BOARD_TYPETarget Board 选择块中追加条目choice BOARD_TYPE prompt Target Board default BOARD_TYPE_BREAD_COMPACT_WIFI help Board type. # ... other entries ... config BOARD_TYPE_MY_CUSTOM_BOARD bool My Custom Board depends on IDF_TARGET_ESP32S3 # pick the matching target endchoice注意与 main/Kconfig.projbuild 中现有 70 条目保持一致符号标识必须大写、下划线分隔如BOARD_TYPE_MY_CUSTOM_BOARDdepends on将条目限定到正确目标芯片IDF_TARGET_ESP32S3、IDF_TARGET_ESP32C3等bool后的标签文本可以是中英文或本地化描述该 choice 为每个目标芯片配置了默认板型如 ESP32-S3 默认BOARD_TYPE_BREAD_COMPACT_WIFI。6.2 在 CMakeLists.txt 中添加分支打开 main/CMakeLists.txt在板型条件链中追加elseif(CONFIG_BOARD_TYPE_MY_CUSTOM_BOARD) set(BOARD_DIR my-custom-board) set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) # pick a font for the display set(BUILTIN_ICON_FONT font_awesome_20_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64) # optional, for emoji display构建系统从main/boards/${BOARD_DIR}/加载源码并从该目录的config.json读取上报板型。若config.json或其顶层type缺失则回退使用完整BOARD_DIR将/替换为-作为板型。当前仓库 main/CMakeLists.txt 中的真实分支如CONFIG_BOARD_TYPE_ESP32_S3_BOX_3对应set(BOARD_DIR espressif/esp32-s3-box-3)可直接对照参考。字体与 emoji 选择建议按屏幕分辨率匹配小屏128x64 OLEDfont_puhui_basic_14_1/font_awesome_14_1中小屏240x240font_puhui_basic_16_4/font_awesome_16_4中屏240x320font_puhui_basic_20_4/font_awesome_20_4大屏480x320 及以上font_puhui_basic_30_4/font_awesome_30_4emoji 集合twemoji_3232x32 像素适合小屏、twemoji_6464x64 像素适合大屏。仓库中的高分辨率板型如 main/boards/espressif/esp32-s3-box-3/实际使用noto-color-emoji_128等更高规格集合可按需取用。七、第五步构建与烧录方案 A手动使用 idf.py设置目标芯片首次或切换目标时idf.py set-target esp32s3 # ESP32-S3 idf.py set-target esp32c3 # ESP32-C3 idf.py set-target esp32 # ESP32清理过期配置idf.py fullclean通过 menuconfig 选择板型idf.py menuconfig导航到Xiaozhi Assistant - Target Board选择你的板卡。构建并烧录idf.py build idf.py flash monitor方案 B使用 build.py推荐只要板卡目录包含config.json即可一键配置并构建python scripts/build.py my-custom-board语言与唤醒词属于用户构建选项可显式指定python scripts/build.py my-custom-board \ --language en-US \ --wake-word wn9_jarvis_tts参数取值规则与 scripts/build.py 的_normalize_language()、_wake_word_sdkconfig_options()实现一致--language接受 main/assets/locales/ 下列出的任意 locale--wake-word接受 ESP-SR 模型名、nihaoxiaozhi按目标芯片自动选择兼容模型或disabledESP32-C3/C5/C6 目标仅支持 WakeNet9s 模型wn9s_*ESP32-S3/P4/S31 构建自动使用 AFE 唤醒词引擎ESP32 使用 ESP 唤醒词引擎——目标不匹配会被显式拒绝见_WAKE_WORD_MODEL_PATTERN与目标判定逻辑。以文本或机器可读形式查询可选值python scripts/build.py --list-languages python scripts/build.py --list-languages --json python scripts/build.py --list-wake-words python scripts/build.py --list-wake-words --json注意唤醒词列表来自当前解析的 ESP-SR 组件。若managed_components/尚未生成请先执行idf.py reconfigure再查询。build.py的完整行为见 scripts/build.py无参数运行时打印帮助用--list-boards列出所有板型与变体含厂商前缀的发布名如waveshare-esp32-p4-nano-10.1-a所选板卡存在多个 builds 变体时会交互式提示选择非交互环境需传--name variant从config.json读取target仅当已有构建目录的目标芯片不同才执行清理然后通过一次idf.py reconfigure完成目标芯片、板名、默认配置与所选 build 的sdkconfig_append配置写入build/xiaozhi-build.sdkconfig.defaults片段随后的idf.py build直接复用该配置将所选 build 的name作为上报的固件变体名-DBOARD_NAME...默认只生成build/merged-binary.bin而不打包 ZIP传--zip才会生成releases/vversion_name.zip对上报标识type/name做全局唯一性校验重复会直接报错防止 OTA 身份冲突若sdkconfig_append中写了CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONINGy会自动补全其 Kconfig select 依赖蓝牙相关宏模拟 menuconfig 行为。八、第六步编写 README在板卡目录的README.md中描述板卡硬件组成、硬件要求、构建与烧录说明、以及任何特殊注意事项例如仓库中 main/boards/sensecap-watcher/README.md 这类板级文档的写法。九、厂商子目录布局当同一厂商有多款变体时推荐使用main/boards/manufacturer/board/分组布局例如 main/boards/waveshare/esp32-p4-nano/ 或 main/boards/lceda-course-examples/eda-tv-pro/。厂商子目录下的板卡需在config.json中声明同样值的字段例如manufacturer: waveshare。固件会将其作为board.manufacturer与board.type、board.name一并上报平铺的社区板卡不声明该字段上报空厂商字符串。同时在 CMake 分支中将BOARD_DIR设为相对main/boards/的完整路径elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_NANO) set(BOARD_DIR waveshare/esp32-p4-nano) set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) set(BUILTIN_ICON_FONT font_awesome_30_4) set(DEFAULT_EMOJI_COLLECTION twemoji_64)一致性约束由 scripts/build.py 的_collect_variants()强制校验板卡位于某厂商子目录下时config.json必须声明且只能声明与该子目录同名的manufacturer否则报错反之平铺板卡声明manufacturer也会报错并提示移动目录。布局经验法则同一厂商有两款以上共享驱动、资源或文档的板卡时使用厂商布局一次性板卡与社区示例使用平铺布局目录名使用小写与连字符。十、可复用的公共组件main/boards/common/提供了大量可直接复用的组件板级类可直接包含使用显示驱动支持的 LCD 系列包括 ST7789SPI、ILI9341SPI、SH8601QSPI等完整驱动见 main/display/lcd_display.h 及相关面板代码。音频编解码器main/audio/codecs/Es8311AudioCodec最常见Es8374AudioCodecEs8388AudioCodecEs8389AudioCodecBoxAudioCodecES7210 麦克风阵列 编解码器组合用于 ESP-Box 系列板卡NoAudioCodec无外部编解码器直接 I2SDummyAudioCodec无音频板卡的占位实现电源管理Axp2101电源管理 IC 辅助类Sy6970电池充电器辅助类AdcBatteryMonitor基于 ADC 的简单电池电压监测PowerSaveTimer/SleepTimer浅睡眠调度辅助。以上实现在 main/boards/common/ 下均有对应文件如 main/boards/common/axp2101.cc、main/boards/common/adc_battery_monitor.cc。网络基类WifiBoard纯 WiFi 基类Ml307Board/Nt26Board4G 模组基类DualNetworkBoardWiFi/4G 可切换基类RndisBoardRNDIS-over-USB 网络ESP32-S3 / ESP32-P4EspVideoESP32-S3 / ESP32-P4 上的 ESP-Video 辅助。输入辅助Button标准按键单击、长按、多击Knob旋转编码器封装PressToTalkMcpTool按键通话工具通过 MCP 自注册SystemReset开机长按按键执行安全出厂重置。MCP 集成任何板卡都可以注册自定义 MCP 工具——喇叭控制、屏幕亮度、电池读数、灯光控制等详见 MCP 使用指南。十一、板级类继承体系从 main/boards/common/board.h 与 main/boards/common/wifi_board.h 的源码结构可以梳理出如下继承关系Board基类WifiBoardWiFi 连接板卡Ml307Board/Nt26Board4G 模组板卡DualNetworkBoardWiFi 4G 可切换板卡RndisBoardRNDIS-over-USB 板卡选择基类时纯 WiFi 板继承WifiBoard4G 模组板继承Ml307Board/Nt26Board两者皆有可能的板继承DualNetworkBoard。十二、开发技巧与排错指南技巧从相似板卡开始复制并修改现有板卡通常比从零开始更快——比如你的硬件用 ES8311 ST7789就直接参考 main/boards/espressif/esp32-s3-box-lite/ 这类板卡增量点亮先让屏幕正常显示再调音频最后跑完整业务栈逐脚核对config.h中每个引脚都必须与原理图一致检查硬件兼容性尤其注意编解码器/PMIC/触摸控制器的组合。排错显示异常检查 SPI 配置、镜像方向与颜色反转esp_lcd_panel_invert_color是否正确无音频检查 I2S 接线、PA 使能引脚与编解码器 I2C 地址无法连接 WiFi复查 WiFi 凭据与配网方式无法连接服务器验证 WebSocket / MQTT 端点配置。十三、参考链接ESP-IDF 官方文档https://docs.espressif.com/projects/esp-idf/LVGL 官方文档https://docs.lvgl.io/ESP-SR 仓库https://github.com/espressif/esp-sr延伸阅读本文关联的原始指南见 docs/custom-board.md另有 docs/custom-board_zh.md 中文版MCP 工具注册细节见 MCP 使用指南板卡上报协议可参考 docs/websocket.md 与 docs/mqtt-udp.md。【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价