Harness_ESP32S31
Health Warn
- No license — Repository has no license file
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Fail
- rm -rf — Recursive force deletion command in components/esp_littlefs/src/littlefs/.github/workflows/test.yml
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
ESP32-S31 多功能智能终端:主线 = 蓝牙音箱 + PC 歌词副屏 + 局域网对讲 + OTA A/B 双槽防砖;支线 = 端侧人脸识别打卡 + 小智 AI 对话 + 动态壁纸 —— Agent 闭环开发实践
基于 ESP32-S31-Korvo-1 的多功能智能音箱
基于 ESP32-S31-Korvo-1 的多功能智能音箱固件:蓝牙音箱 / PC 音乐副屏 / 局域网对讲 / 录音回放 / 音乐视频播放 / WiFi-OTA / USB 扩展屏
不只是代码,更是一套 AI Agent 可读规范 → 写代码 → 烧录 → 抓日志 → 反复验证的智能开发闭环
📸 功能展示
| 🔌 USB 扩展屏(Windows 认作真显示器,SET 键一键切换) | 🖥 PC NOW 音乐副屏(局域网推送封面 / 歌词 / 进度 / 媒体控制) |
|---|---|
![]() |
![]() |
| 🔵 蓝牙音箱(A2DP Sink,手机推歌 + 实时歌词) | ⛅ 天气时钟(SNTP 校时 + 和风天气实时仪表盘) |
![]() |
![]() |
📡 这是什么
一台 ESP32-S31 设备 = 蓝牙音箱 + PC 歌词副屏 + 局域网对讲机 + 录音笔 + 音视频播放器,主界面 7 个 Tab:
| Tab | 功能 | 说明 |
|---|---|---|
| 🎙 CALL | 局域网实时对讲 | UDP 50000/50001 全双工语音,端到端 ≤100 ms(16 kHz/16 bit/mono) |
| 💾 REC | 本地录音 | 一键开录 → 存 SD 卡 WAV → FILES 页回放 |
| 🎵 AUDIO | 音乐播放中心 | SD 卡音乐(esp_player 硬解);顶部切换 LOCAL 板载扬声器 / BT PUSH 蓝牙耳机推流 |
| 🔵 SINK | 蓝牙音箱 | A2DP Sink:手机推歌到本机播放,AVRCP 取歌名/进度显示 |
| 🎬 VIDEO | 视频播放 | 播放 SD 卡 MJPEG AVI,硬件 JPEG 解码 + PPA 缩放,全屏 800×480 |
| 🖥 PC | PC 音乐副屏 | 局域网接收 PC"正在播放"(网易云等):旋转封面 + 三行滚动歌词(1.25 s 提前量补偿)+ 媒体控制键 |
| ⚙ SYS | 系统入口 | RGB 灯 / WiFi / 蓝牙信息 / 固件升级(版本查询·双向 OTA·运行槽显示与手动切槽)/ 存储·堆栈监视卡 |
系统级能力:
| 能力 | 说明 |
|---|---|
| 🔄 WiFi OTA | 设备端 ota_service + LVGL 升级覆盖层,A/B 双槽轮替(ota_0 ⇄ ota_1),见 docs/项目规划/WiFi_OTA_烧录验收与使用流程.md |
| 🖥 USB 扩展屏(uext) | 另一套独立固件:本机变 Windows 的 800×480 USB 副屏(TinyUSB HS 收 JPEG → 硬解直写屏),主固件内SET 键一键切换,详见下文 |
| ⛅ 下拉仪表盘 | SNTP 校时 + 和风天气壁纸实时刷新 |
| 🔊 音频仲裁 | audio_service 命令队列模型,UI 不直接碰 codec;播放/录音/对讲互斥调度 |
🔀 双固件架构(主固件 ⇄ 副屏固件)
┌─────────────────────────────────────────┐
16 MB Flash │ ota_0(5M) ⇄ ota_1(5M) uext(ota_2) │
│ 主固件 A/B OTA 轮替 USB 副屏固件 │
└─────────────────────────────────────────┘
SET 键单击(主固件)→ 倒计时确认卡 → 重启进副屏
SET 键单击(副屏) → 回写引导标志 → 重启回主固件
- 主固件(本仓库源码):LVGL 全功能界面,OTA 只在 ota_0/ota_1 间轮替,永不覆盖 uext 槽(
ota_service.c: ota_pick_update_slot()显式锁槽,该补丁勿删)。 - 副屏固件(预编译包在本仓库
firmware/uext_screen/):源码为独立 IDF 工程(不在本仓库),USB Type-A 口直连 PC,Windows 端装 Espressif 官方签名 IDD 驱动后即成扩展显示器。画质参数:JPEG 质量 9 / 单帧上限 450 KB。 - ⚠️ 副屏固件只能定点烧写
0xA20000,对它跑idf.py flash会覆盖主固件。
🔄 WiFi OTA 升级(A/B 双槽,v2.1.0 发布版)
零新增端口:控制面复用 UDP 50003(link_manager),数据面复用 TCP 50005(pc_host 内置 HTTP),
设备作 HTTP 客户端主动拉取(无需 PC 能直连设备)。
PC: pc_host「固件升级」页 设备: ota_service(middleware/network/)
① 选 bin → 解析 esp_app_desc_t ⑥ 收 OFFER → 6 条校验链
(版本/大小/SHA256) (离线/录音/会话/重复/待自证/槽容量)
② SemVer 比对 → OTA_OFFER(×3) ──UDP 50003──▶ ⑦ 全过 → OTA_ACCEPT ◀──┐
③ 进度条 ◀──OTA_PROGRESS(×N)────────────────── ⑧ HTTP GET :50005/firmware.bin
④ 边收边写**对侧槽**(32KB 攒块,
⑤ OTA_RESULT{ok} ◀─────────────────────────── 每 256KB 段哈希落 nvs)
esp_ota_end 段CRC校验 → set_boot_partition → OTA_RESULT{ok:1} → 1s 后重启
新固件自证(WiFi 已连 且 link 在线,1s 周期条件驱动,~10s 转正)
└─ 转正失败/窗口内断电 ⇒ bootloader 自动回滚旧槽(防砖)
- PC 端(
pc_host/ui/pages/ota_page.py):固件解析 / 版本比对 /
进度与结果展示 /--force·截断·坏固件注入等验收开关 / bin 拖拽选件 / 固件按版本归档 +
sqlite 升级历史(「升级历史」按钮,M4);下载侧 600s 绝对超时 + 120s 活动超时。 - 设备端(
main/middleware/network/ota_service.c):
A/B 双槽锁死 ota_0⇄ota_1(永不触碰 uext 槽);flash IO 任务栈强制内部 RAM
(IDF 冻结 cache 期间断言 SP,PSRAM 栈必 panic);断点真续传(256KB 段哈希落 nvs →
重推时旧段回读验哈希 → esp_partition 裸写 + 水位擦除续下,最多重下 256KB)。 - LVGL 浮层(
ui/overlays/overlay_ota.c):升级期间全屏遮罩进度卡 + "请勿断电"警示,
触摸不穿透;线程纪律 = 事件回调只赋值,刷新全在lv_timer。 - 防砖四防线:①
esp_ota_end镜像头 + 段 CRC;② 256KB 段摘要链 + 段数一致性;
③ 自证 + bootloader 自动回滚(已计划外实测:升级后断电 → 正确回退旧槽);
④ 最坏情况 USB 全量重刷。
16 MB Flash 分布(partitions.csv V1.3,无 factory)
0x000000 ┌────────────────────────┐
│ bootloader(隐含 ~36K) │
0x009000 ├────────────────────────┤
│ nvs 24 KB │ ← WiFi 凭据 / OTA 断点段哈希 / 壁纸索引
0x00F000 │ phy_init 4 KB │
0x011000 │ otadata 8 KB │ ← A/B 槽选择 + PENDING_VERIFY 回滚标记
0x020000 ├────────────────────────┤
│ ota_0 5 MB │ ← 主固件 A 槽
0x520000 │ ota_1 5 MB │ ← 主固件 B 槽(OTA 写入对侧)
0xA20000 ├────────────────────────┤
│ uext (ota_2) 2.875 MB│ ← USB 副屏固件专属,OTA 永不触碰(定点烧写)
0xD00000 ├────────────────────────┤
│ storage (littlefs) 3 MB│ ← 壁纸池 / 素材(OTA 完全不碰)
0x1000000└────────────────────────┘
OTA 只写 ota_0/ota_1 的对侧;
nvs/storage/uext一概不碰。
固件尺寸硬上限 = 5,242,880 B(超出设备回OTA_REJECT reason=space)。版本三层(v2.1.0 起):①
version.txt= 发布 SemVer(人工决定,发布才动);
② 构建标识+g<sha>[.dirty]—— 由CMakeLists.txt在project()之前注入,
所以idf.py build裸跑就带 sha,无需-DPROJECT_VER(那个会写进CMakeCache造成版本滞留);
③app_elf_sha256兜底归档(pc_host解析后进firmware.json/ sqlite)。
发布构建用pwsh -f tools/build_fw.ps1 -NoMeta(置RELEASE_BUILD=1+ 拒绝脏工作区),
器件最终上报纯2.1.0;日常构建报2.1.0+g<sha>。
版本比对在两端都只比前三段数字(自动剥掉v前缀与+之后的 metadata)。吞吐定档(§80,2026-11-12):TCP 窗口保持 IDF 默认 5760/16 —— 四组实测里
187 KB/s 就是最大值(65535/16 反而掉到 60 KB/s);verify仅 0.47 s、dl/total≈0.99,
已排除 flash 与 sha,瓶颈在无线空口(rx ba win: 2)。详见验收报告 §十一。双向 OTA(§79):PC 心跳携带
fw_latest(本机 build bin 编译版本),设备端 SYS 页
Firmware Update 卡实时显示云端最新版本;点 Check update 发OTA_REQ—— PC 判无更新回OTA_NOUPDATE,有更新则自动起升级会话(走同一套 OFFER/校验/归档链路)。
真续传已实弹验收通过(只发 40% → 归零重推 → 从 256KB 段边界 RESUME,2026-10-08)。手动切槽 Switch slot(§79e):SYS 页显示当前运行槽(ota_0/ota_1),一键切到对侧槽;
防砖双闸 = 对侧槽镜像头校验失败拒切 + 槽状态 INVALID/ABORTED 拒切。显示稳定性定稿(§79g / v2.0):LCD 刷新模式 bb→AUTO(GDMA 环形链直扫 PSRAM 整帧,
flash 写冻结期挂起、恢复后行序天然对齐)——根治"连 WiFi / 连 PC 时刻屏幕内容下移定格";
OTA 下载期壁纸轮换与粒子动画自动暂停(§78 全静止变体)保留。
上位机全局深色主题(#181818 + 法拉利红,§77)。
操作与逐项验收详见 docs/项目规划/WiFi_OTA_烧录验收与使用流程.md,
协议字段见 docs/项目规划/通信接口规范_ICD.md。
🤖 为什么这仓库不只是固件
传统嵌入式开发:人写代码 → 人编译 → 人插线烧录 → 人开串口看日志 → 人判断对错 → 人改。
本仓库把这套流程沉淀成 Agent 可执行的 Skill + 工程规范:
Agent 读 docs/工程规范/01~11
↓
按模板写 middleware / ui 代码
↓
idf.py build (自动看 error:)
↓
idf.py -p COM9 flash (自动看 Hash verified)
↓
python docs/_serial_capture.py(拉 RTS 复位,抓 12 s 日志)
↓
Agent 读日志:panic? 功能日志? 静默?
↓
不对就改代码,再走一遍
skills/esp-idf-closed-loop.md—— 闭环 SOP,Agent 每次开发前必读;docs/工程规范/—— 分层架构、命名、模块模板、CheckList(01~11 + 附录);docs/项目规划/—— 需求文档、todolist、改动记录(§编号制)、各专项实施方案、ICD 接口规范。
🚫 红线(Agent 写代码时必须遵守)
- middleware 层不得
#include "lvgl.h"; - UI 事件回调里不得直接建硬件任务、不得操作 codec / I2S / I2S 寄存器;
- 业务任务栈 ≥ 8192 字节;
- 新增
.c必须注册main/CMakeLists.txt的SRCS(放进对应领域分组); #include必须写从main/根开始的完整路径,禁止裸文件名(见 F25);- 高频音频链路(每 20 ms)禁止
ESP_LOGI。
🛠 硬件平台
| 项 | 值 |
|---|---|
| 开发板 | ESP32-S31-Korvo-1 V1.1(官方) |
| MCU | ESP32-S31 双核 RISC-V @ 320 MHz,512 KB SRAM |
| 存储 | 16 MB Flash + 16 MB Octal PSRAM @ 200 MHz |
| Codec | ES8389(I2C 0x20,MCLK=GPIO42 未连 → use_mclk=false) |
| 音频 I/O | 双 MEMS 麦 + 双 NS4150B 功放 |
| 屏幕 | 4.3" RGB 800×480 ST7262E43,16-bit RGB565 总线(GDMA 自动刷新)+ 电容触摸(GT1151) |
| USB | Type-A = USB 2.0 OTG HS(副屏数据口,对外 500 mA);Type-C = 板载 UART 桥(烧录/日志口) |
| ESP-IDF | v6.1.0(IDF_TARGET=esp32s31) |
| 烧录端口 | COM9(以设备管理器为准) |
| 分区表 | nvs 24K / phy 4K / otadata 8K / ota_0 5M / ota_1 5M / uext(ota_2) 2.875M / storage littlefs 3M(无 factory,A/B OTA + 副屏槽) |
| 文件系统 | LittleFS(挂载点 /littlefs);录音/音乐存 SD 卡 |
📁 目录结构
display_audio_photo/
├── main/
│ ├── app/main.c # app_main() 初始化顺序 + SET 键事件分发
│ ├── middleware/ # 硬件业务,不 include LVGL
│ │ ├── audio/ # audio_service / record_service / udp_voice / session_manager
│ │ ├── bluetooth/ # bt_audio_service(A2DP Source) / bt_sink_service / bt_push_service / link_manager
│ │ ├── network/ # wifi_manager / pcnow_service / ota_service / net_time_service
│ │ └── system/ # button_service / led_service / fs_service / sdcard_service
│ ├── ui/ # LVGL 界面(PageManager 栈式导航)
│ │ ├── ui_manager/ # page_manager 页面注册/切换/返回栈
│ │ ├── pages/ # page_splash / page_main / page_wifi / page_bluetooth
│ │ │ # page_system / page_rgb / page_wav_player
│ │ ├── tabs/ # tab_call / tab_record / tab_audio / tab_btsink
│ │ │ # tab_video / tab_pcnow / tab_sys_entry
│ │ ├── overlays/ # overlay_manager / overlay_wallpaper / overlay_wp_particles
│ │ │ # overlay_ota(WiFi升级) / overlay_uext(副屏切换确认卡)
│ │ ├── common/ # ui_common(控件工厂)+ ui_theme.h(颜色/字体宏唯一来源)
│ │ └── assets/ # fonts/ bin 字体 + icons/ 图标(生成物,勿手改)
│ └── 3rd/ringbuf/ # 第三方纯 C 环形缓冲
├── pc_host/ # PySide6 PC 上位机(对讲 + 录音 + PC NOW 推流;入口 start_all.bat)
├── tools/pc_now_agent/ # C# 轻量替代:SMTC 抓取 → UDP 推流到设备(与 pc_host 二选一)
├── firmware/uext_screen/ # ★ USB 副屏固件预编译烧录包(bin + Windows 驱动 + 烧录说明)
├── docs/
│ ├── 工程规范/ # Agent 写代码前必读(01~11 + 附录)
│ ├── 项目规划/ # 需求 / todolist / 改动记录 / ICD / 各专项方案
│ └── _serial_capture.py # 替代 idf.py monitor
├── skills/
│ └── esp-idf-closed-loop.md # 闭环 SOP:build→flash→抓日志→定位→再改
├── littlefs_content/ # LittleFS 素材(壁纸 / 开机提示音)
├── components/ # 本地组件(esp_littlefs / cjson)
├── partitions.csv # V1.3:ota_0/ota_1 各 5M + uext(ota_2) + storage 3M
└── CMakeLists.txt
分层规则、各目录职责与归位判断见
docs/工程规范/01_工程分层架构.md。
🚀 快速开始(主固件)
1. 安装 ESP-IDF(用 EIM 一键管理)
EIM(Espressif IDF Manager) 是乐鑫官方的 IDF 版本管理器,图形界面,免去手动装 Python / 工具链。
- 下载:https://idf.espressif.com/
- 本仓库用 v6.1.0,安装时在 EIM 里选 v6.1.x 即可
安装完后 EIM 会自动配好 Python venv、交叉编译工具链、OpenOCD、CMake。
2. 打开 IDF 终端
双击本仓库根目录的 IDF_v6.1_Powershell.lnk(或手动执行 PowerShell profile):
. 'C:\Espressif\tools\Microsoft.v6.1.PowerShell_profile.ps1'
cd <本仓库根>
成功标志:看到 IDF_PATH: C:\esp\v6.1\esp-idf 等。
3. 编译 + 烧录(COM9)
idf.py build
idf.py -p COM9 flash
idf.py -p COM9 storage-flash # 首次烧录 / littlefs 素材变更后,刷 storage 分区
⚠️ 改过
partitions.csv后必须fullclean重编 + 重跑storage-flash。
4. 看日志
非交互终端跑 idf.py monitor 会报 TTY 错误,用本仓库脚本:
& "C:\Espressif\tools\python\v6.1\venv\Scripts\python.exe" docs\_serial_capture.py
自动拉 RTS 复位,读 12 秒启动日志。
🖥 USB 副屏固件烧录(uext)
三种场景对号入座:
A. 只想用副屏(不碰源码)—— 直接用预编译包
仓库自带 firmware/uext_screen/(含 uext_screen.bin + Windows 已签名驱动 + 详细说明):
- 主固件先按上面流程烧好(分区表必须带 uext 槽);
- IDF 终端定点烧写(COM 口以设备管理器为准):
python -m esptool -p COM9 write-flash 0xA20000 firmware/uext_screen/uext_screen.bin - 主界面单击 SET 键 → 倒计时确认卡点确认,重启进入副屏模式;
- PC 端双击
firmware/uext_screen/xfz1986_usb_graphic_250224_rc_sign.exe装官方签名 IDD 驱动; - USB Type-A 口连 PC → 设备管理器出现
USB\VID_303A&PID_2986复合设备 →Win+P设为"扩展这些显示器"→ 出现 800×480 扩展屏; - 触摸可用,需在 Windows"平板设置"里做屏幕映射;
- 切回主固件:副屏模式下单击 SET 键,自动重启回主固件(无需重烧)。
B. 想改副屏固件源码
源码仓库:xkk6663/uext_screen(独立 IDF 工程,含 7 个离线 vendor 组件;架构与坑见 docs/项目规划/USB副屏集成技术方案.md)。只 idf.py build,绝不 idf.py flash,产物定点烧 0xA20000。
C. 画质调优
改 uext_screen 工程的 CONFIG_USB_EXTEND_SCREEN_JPEG_QUALITY(当前 9,上限 10)与 CONFIG_USB_EXTEND_SCREEN_FRAME_LIMIT_B(当前 450000)。注意:落屏格式是 RGB565(16-bit 屏总线),没有 RGB888 可开——JPEG 质量与帧上限是仅有的两个真实画质旋钮。
🖥 PC 端(PC NOW 副屏推流 / 对讲)
设备 PC Tab 与 CALL Tab 需要局域网内一台 PC 配合,二选一:
| 端 | 技术 | 说明 |
|---|---|---|
pc_host/ |
PySide6 GUI | 全功能:对讲 / 录音 / PC NOW 推流(网易云 debug 端口 9222 抓取播放态 → 歌词/封面/进度)/ WiFi OTA 固件升级。启动:桌面 ESP32_Voice_Host.bat 或 pc_host/start_all.bat(幂等) |
tools/pc_now_agent/ |
C# 单体 | 轻量:Windows SMTC 直接抓"正在播放"推 UDP(OTA 命令行备用,推荐用 pc_host 固件升级页)。与 pc_host 的推流端口冲突,同一时间只跑一个 |
协议细节见 docs/项目规划/通信接口规范_ICD.md。
🧠 如何让 AI Agent 接管开发
- 把本仓库喂给 Agent(豆包 / Claude / Cursor 等);
- 让 Agent 先
Read skills/esp-idf-closed-loop.md; - 再
Read docs/工程规范/01~11; - 给任务(例如"实现 wifi_manager.c 按 STA 模式连指定 SSID");
- Agent 会自己:按模板写代码 → 注册
SRCS→ build → flash → 抓日志 → 定位修复 → 在docs/项目规划/改动记录.md追加 §记录。
✅ 当前进度
- M1 音频链路(ES8389 / I2S DMA / WAV 播放 / 本地录音)
- UI 骨架(7 Tab + 开屏壁纸 + 上拉手势 + RGB / WiFi / System 监视卡)
- Wi-Fi STA(扫描/连接/状态灯)+ SNTP + 和风天气仪表盘
- M2 UDP 通话(link_manager + udp_voice + PC 端)
- 阶段 A/B:SD 卡存储 + 音频/视频播放(AUDIO HUB / VIDEO tab,MJPEG 硬解)
- 蓝牙双模式:A2DP Source 本地推流(AUDIO 页切换)+ A2DP Sink 蓝牙音箱(SINK tab)
- PC NOW 音乐副屏(封面旋转 + 全量 LRC 歌词 1.25s 补偿 + 媒体键),pc_host / pc_now_agent 双端
- M6 OTA:A/B 双槽 WiFi 升级(ota_service + LVGL 覆盖层 + PC 端烧录 agent)——已实弹验收(v1.0→v1.4 五连升 + 断电回滚实测,2026-10-08)
- USB 扩展屏(uext 双固件架构:SET 键双向切换 + 预编译烧录包
firmware/uext_screen/) - v1.5 → v2.0 发布版迭代(2026-10-08):录音上限动态化(§72)+ OTA 真续传真机验收 +
固件归档 sqlite(§73,M4)+ 上位机深色主题(§77)+ OTA 期全静止(§78)+ 双向 OTA(§79)+
SYS 页一屏布局(§79b)+ 心跳抖动修复(§79c)+ 手动切槽(§79e)+ 屏偏移根治 bb→AUTO(§79g) - M3 TCP 录音远端化 + M4 多任务调度深化
- 小智 AI 对话接入(方案已定稿:
docs/项目规划/小智AI对话接入实施方案.md,未开工)
License:Apache-2.0(沿用 esp-bsp) · Maintainer:xkk6663
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found



