让设备听懂一句“打开风扇”,并不只是给 GPIO 写一个高电平。麦克风采集、网络消息、工具调用和负载驱动都要接上。本篇基于 小智 ESP32 开源项目 的本地工作区,记录语音链路和风扇扩展代码之间的关系。
先说明归属:小智的核心语音、通信协议和 MCP 框架来自上游,项目采用 MIT 许可。这里不是从零实现聊天机器人,也没有通过完整提交比对确认每处本地改动的作者。
设备端与云端如何分工
固件使用 C++、ESP-IDF 与 FreeRTOS。启动后,应用从板级对象取得音频编解码器,初始化音频服务,再连接网络并选择协议。设备负责录音、唤醒、音频前处理、编解码与播放;语音识别、大模型响应和语音合成由服务端完成,不能把整套智能能力描述为 ESP32 离线运行。
上行时,麦克风经 I2S 取得 PCM,经过处理后进入编码队列,转换成 Opus 包发送。下行包进入解码队列,恢复 PCM,再交给播放任务。输入、输出与编解码由不同任务处理,应用通过事件组协调发送、唤醒和语音活动状态。
协议与工具调用的交界
网络层抽象出统一 Protocol 接口。WebSocket 同时承载 JSON 控制消息与二进制音频;另一条路径由 MQTT 传控制消息、UDP 传音频。握手会声明采样率、声道数、Opus 格式及 MCP 能力。
收到 MCP 消息后,应用交给设备端服务器,依次处理初始化、工具列表与工具调用,再执行设备回调。因此,“存在一个控制函数”和“模型能够调用这个函数”之间,还隔着明确的工具注册与消息分发。
已有机制与本地扩展
上游已提供音频队列、采样率适配、按需建立音频连接和空闲通道关闭等机制;通用工具覆盖状态、音量,以及硬件存在时的屏幕或摄像头功能。这些是继承的工程能力,不应写成个人优化成果,也没有在本文中测量其资源收益。
本地 main/blower.cc 配置 GPIO 输出并初始化为低电平,定义风扇开关属性,以及更新软件状态、设置引脚电平的回调。构建清单纳入该文件,板级初始化也有创建 Blower 的语句,可确认它不只是文字设想。
但扩展仍使用旧式 iot::Thing 与 ThingManager,当前应用入口已经走 MCP。现有源码研究没有找到配套旧框架定义,也没有找到风扇对应的 MCP 工具注册。这是静态接入缺口,不是一次实际编译失败的结论。
硬件验证边界
目前不能宣称该扩展已经编译成功、完成语音控制或通过实机验证。下一步应先统一扩展接口,将开关动作注册为 MCP 工具,再按具体板型核对初始化和引脚配置。
随后才是电源、驱动电路与负载验证。软件记录为“开启”,只能证明发出了控制意图;GPIO 电平也不能代替真实转动反馈。把协议接通、引脚动作与硬件效果分别验收,比一句“支持智能风扇”更有用。
实现线索
音频任务见 main/audio/audio_service.cc,工具分发见 main/mcp_server.cc。本文为源码学习与扩展记录,未执行构建、烧录或设备测试。