esp-harness · 沉淀汇报 · 联网 + 真实 OTA v1.7.0 · 2026·05·22

设备从此

自己升级

继 v1.6 项目成熟化后, v1.7 把硬件接入真实世界WiFi STA 连接 (event-group + IP_GOT 双门控, 3 次自动重试), NVS 凭证持久化 (重启自动续连), 真实 OTA over HTTPS (esp_https_ota 流式拉取 + 整数百分点 EVT 上报), 双槽 partitions.csv (ota_0/ota_1 各 5M + rollback), qmi8658 自动 patch (CMake 内联 + toolkit 重试双层防御). 端到端 — wifi connect ssid=… pass=… 一行上网, ?ota download url=… 一行升级.

§ 01 — At a glance

已经不是一个仓库
而是三层可复用结构

230+ 次 commit, 落 5 个 git tag (v1.0 → v1.4); aurora-harness 公共 API 30+ 函数 / 6 个头文件; 全部由 manifest --json 一行可见 + 每层都有 onboarding 文档。

17
Toolkit 命令
doctor / test + v1.7 自动 patch (build 失败自动 retry waveshare__qmi8658)
20
Scenes 总数
+ XX Track (harness_progress 参考). XIX/XX 都是 toast/progress 原语的 demo scene
13 / 13
Sim diff PASS
含 Track; 13 个 host-runnable scene 全部稳定 < 1% diff (Pulse 5% 容差)
3 / 3
Integration tests
esp-harness test 跑 pytest: doctor + manifest + sim diff. 10s
BSP
组件已板无关
harness/bsp_iface.h 只 2 个符号 (lock/unlock), PORTING.md 多板清单
8 / 8
Doctor checks
ESP-IDF / cmake / Pillow / pyserial / mingw / SDL2 / 串口 / sibling repo — 全 OK
§ 02 — Scaffold mindset

每个能力
都是独立可复用的积木

本轮最关键的不是"做了什么"而是"怎么做"。每一个新 feature 都按"可复用积木 + 集成文档"的标准产出: aurora-harness 是 LEGO 底板, harness_toast() 是新积木块, Scene XIX Notify 是参考拼装, INTEGRATION.md 是说明书。一个新项目复用这套, 跟 Aurora 自己用是一样的接口。

具体做法: 任何"任何 LVGL+console 项目都该有"的能力 — 协议、scene framework、toast、?stat — 都进了 aurora-harness 组件。Aurora-specific 的 (?audio, ?sd, ?wifi 等) 留在 main/ 作为应用胶水。 这条线划清楚, 才能让"新人项目"和"Aurora 自己"用同一份核心。

§ 03 — 架构 (v1.3)

三层都在
同一个 manifest 之下

                ┌─── esp-harness manifest --json ───┐
                │   一条命令枚举所有能力             │
                └────────────────┬───────────────────┘
                                 │
        ┌────────────────────────┼────────────────────────┐
        ▼                        ▼                        ▼
  ┌──────────────┐         ┌──────────────┐        ┌──────────────┐
  │   TOOLKIT    │         │   FIRMWARE   │        │  SIMULATOR   │
  │              │         │              │        │              │
  │  Python CLI  │         │  ESP-IDF v6  │        │   SDL2 host  │
  └──────┬───────┘         └──────┬───────┘        └──────┬───────┘
         │                      │                        │
         │ 14 cmds              │ 19 scenes              │ 12 scenes
         │ + init 模板          │ + ?ota partition       │ + record 多帧
         │ + sim diff/record    │ + harness_toast 浮层   │ + diff vs golden
         │ + console --repl     │ + scene_t description  │ + CI ubuntu
         │ + manifest           │ + ?stat fps/heap       │
         │                      │                        │
         │                                              ┌────────────────────────────────┐│  components/aurora-harness/   ││   ↳ 可复用 ESP-IDF 组件         ││     console_protocol           ││     scene_framework            ││     toast 浮层                  ││     default_cmds (?stat)       │└────────────────────────────────┘↑ firmware 和 sim 都依赖它
         │
         ▼
  build / flash / monitor / run
  manifest / bench / backtrace
  screenshot / console / audio / tap
  sim {snapshot, diff, update-golden, record}
  init <new-project>

   ─────────────  Discovery surface 双向连通  ─────────────

  AI 改源码 → sim diff 5s (sim) / sim record 看动画
  AI 改源码 → build + flash + run 30s (设备 e2e)
  AI 改源码 → bench --compare 8s (跨版本性能回归)
  AI 起新项目 → esp-harness init 1 行 (scaffold)
  AI 调试设备 → console --repl 交互
§ 04 — 全 6 阶段实施

每阶段一个
明确的 能力跃迁

A
v1 收口
4 tasks · 30 min
tag v1.0.0
先打个 v1.0 钉子, 才能在它之上换地基

scenes-map XIV-XVI, boot flicker (NVS-restore 挪到 LVGL unlock 前), CHANGELOG ×2 仓, v1.0.0 tag 双仓 push.

不可逆改动前必先 tag — sim/ 引入 host build 重构是不可逆变更, v1.0 是它的安全网。

B
Bench 基线
3 tasks · 45 min
让"性能退步"变成 exit code

bench.py 加 --baseline/--compare, 8 个 metric 方向性阈值表。data/baseline.json 落地 v1.0 实测基线, AGENT.md §6.5 文档化。

方向性阈值 — heap 跌报警, 涨多少都不报; loopback 涨报警, 跌不报。对称阈值会被正常方差淹没。

C
WiFi/BLE/OTA
3 tasks · 1.5 hr
tag v1.1.0
同样的硬件, 两套表达

Scene XVII Survey (WiFi 数据表) + XVIII Sniff (BLE 数据表) — 与 IX Spectrum / VIII Whisper 共享同一外设, 两种视觉风格 (艺术 vs 表格)。 ?ota info/mark-valid/rollback partition state 读取。修 MAX_SCENES silent drop bug。

D
LVGL Simulator
2.5 hr
端到端通
scaffold → 跑通 → toolkit 驱动 — 三段串好

用户态 scoop 装 MinGW gcc 16.1 + 手动解压 SDL2 dev libs (无 admin), 跑通 466×466 LVGL 窗口。补 headless 模式 --scene N --snapshot PATH, toolkit sim snapshot 一键调用。

三层独立验证 — GUI 模式跑通, 再 headless 模式跑通, 再 toolkit 调用跑通。一锅炖出错没办法定位。

F
组件化
4 tasks · 1.5 hr
tag v1.2.0
把 console_protocol + scene_framework
提升为 aurora-harness 组件

git mv 4 个文件保留历史, 20 个调用方 sed 改 #include "harness/X.h" 命名空间形式。 main 改 REQUIRES 取代 SRCS, sim CMakeLists 指向组件路径直接编译。

配套文档: 组件 README 350 行 (API 契约 / 集成 / 线程模型 / 限制), sim/INTEGRATION.md (新项目复用 sim 的清单), 顶层 README 改写 "Aurora 是三合一"。

分界线: 任何 LVGL+console 项目都该有的能力 → 组件; peripheral-coupled 的 → 应用胶水留 main/。

G
10 轮迭代
10 tasks · 5 hr
tag v1.3.0
每个迭代一个新积木 + 文档
  • G1 ?stat 上提进 aurora-harness 作为 harness_default_register() 入口2d21b33
  • G2 harness_toast() 任意 task 安全的浮层原语8334d7e
  • G3 Scene XIX Notify — toast 参考实现8334d7e
  • G4 GitHub Actions CI workflow + sim CMakeLists 跨平台修1d4c30f
  • G5 esp-harness init <name> 项目模板生成器 (9 文件)04243f9
  • G6 sim record 动画多帧捕获04243f9
  • G7 console --repl 交互式 + 斜杠命令04243f9
  • G8 showcase AGENT.md — 给后续 AI 的上手手册6c3a8c5
  • G9 scene_t 加 description + tags 元数据6c3a8c5
  • G10 本汇报 HTML v2 → 入库到 docs/harness-report.htmlb35fbb7
H
脚手架收口
10 tasks · 6 hr
tag v1.4.0
把还卡在应用层的
通用能力全部上提

v1.3 把核心抽出为组件; v1.4 把其余通用部分也送进去, 让 main/ 真正只剩 Aurora-specific 胶水。组件同时去掉对单一 BSP 的硬绑定, 加上多板移植清单。

  • H1 cmd_scene 上提 + scene_change_listener 解耦 chromec192562
  • H2 cmd_tap + cmd_swipe 上提 (纯 LVGL indev)e60ae2c
  • H3 cmd_dump + PSRAM 截屏机制整段挪到 screenshot.c725826f
  • H4 bsp_iface.h 抽象 + 解 Waveshare 硬绑定 + PORTING.md39c73d4
  • H5 harness_progress() 进度条原语 + Scene XX Track 示范5258f73
  • H6 harness_default_register() 注册全套 (stat / scene / tap / swipe / ?dump) + 文档收口5258f73
  • H7 esp-harness doctor — 8 项依赖健康检查24de11a
  • H8 esp-harness test + pytest 集成测试套 (3 tests, 10s)24de11a
  • H9 idf_component.yml v1.4.0 registry 准备 + RELEASING.md0150546
  • H10 汇报 HTML v3 → docs/harness-report.html + v1.4.0 tag70275d8
I
monorepo 落地
10 tasks · 4 hr
tag v1.5.0 (本汇报)
从两仓
esp-harness 单仓

用户提议把分散在两个仓库的内容合并成单一 esp-harness, 按 artifact 类型而非功能模块切顶层。新结构让"库 / 工具 / 演示 / 模板"四类东西物理边界跟语义边界完全对齐, 各自独立, 各自 可发布。

  • I1 新仓骨架 — components / tools / examples / sim-base / boards / docs / .github初始化
  • I2aurora-harness 组件 + Waveshare BSP 进 boards/cp -r
  • I3 搬 toolkit 进 tools/esp-harness/含 tests/
  • I4 搬 Aurora demo 进 examples/aurora/含 sim/
  • I5sim-base/ — ESP-IDF stub + mock_bsp + INTEGRATION.md 上提真模板化
  • I6 改全部路径引用 — sim CMakeLists / conftest / doctor / sim auto-detect / GHA workflow14 处
  • I7README.md 三路 onboarding + AGENT.md + docs/architecture.md + docs/getting-started.md~1200 行
  • I8 esp-harness new 重设计 — vendor/link/depend 三模式, 生成 AGENT.mdinit 保留作 alias
  • I9 端到端验证 — target build 13.8s / sim build / sim diff 13/13 / pytest 3/3 / manifest 17 cmds / new smoke全过
  • I10 单一 initial commit + v1.5.0 tag + 本汇报 HTML v452d4ee9
J
项目成熟化
12 tasks · 5 hr
tag v1.6.0 (本汇报)
完整文档生态 +
视觉身份, 失忆测试通过

v1.6 的目标只有一句话: 陌生人 (或失忆的作者) 30 秒认出 这是什么, 5 分钟读懂为什么, 10 分钟跑出第一个项目。配套整 套成熟项目应有的文档生态 + 品牌身份。

  • J1 Logo + wordmark + social card + favicon + brand READMEdocs/brand/
  • J2 docs/manifesto.md — 项目哲学 + out-of-scope 边界声明survive amnesia
  • J3 根 README 重写为真正 landing page (badges / hero / 三路 / vs others 对比)~250 行
  • J4 docs/index.html homepage (hero / terminal / 三路 / 架构 / 对比)同 editorial 风
  • J5 .github/ — CONTRIBUTING + 3 issue templates + PR template + config.yml7 文件
  • J6 docs/faq.md (16 问答) + docs/troubleshooting.md (症状-修复 表)amnesia friendly
  • J7 3 张 SVG 架构图 (three-layers / dev-loop / repo-layout)docs/diagrams/
  • J8 第二个 example — examples/hello-minimal/ (template integrity check)~150 LOC
  • J9 GitHub repo metadata — description / homepage / 14 topics / wiki offgh repo edit
  • J10 GitHub Pages 启用 — caldis.github.io/esp-harness/ 走 master /docsgh api
  • J11 Badges 收口 — 各 artifact README 顶部带 badge 条视觉一致性
  • J12 v1.6.0 tag + 本汇报 HTML v5 + CHANGELOG entry52d4ee9
K
联网 + 真实 OTA
8 tasks · 3 hr
tag v1.7.0 (本汇报)
硬件从此
能自己升级

v1.6 之前 ?ota 只是空架子 — 有 info/mark-valid/rollback, 但 partitions.csv 是单 factory 槽, 也没真正的下载路径. v1.7 把这条线打通: partitions 切到双 ota_0/ota_1 槽 + rollback gate, WiFi 加完整 STA 连接 + NVS 凭证持久化, ?ota download url= 接 esp_https_ota 流式拉取 + 整数百分点 EVT 进度上报. 顺手把困扰已久的 waveshare__qmi8658 upstream bug 收口为双层自动 patch: CMake inline (项目本地 / 离线可用) + toolkit retry (失败签名识别 + 自动 重试). 之后任何新机器 clone 即建, 不再需要手动 sed.

  • K1 qmi8658 自动 patch — esp_harness_apply_known_patches() CMake 函数 + patches.py toolkit retry 双层CMake+py
  • K2 peripherals/wifi_creds — NVS 凭证持久化 (namespace wifi_cred, 5 函数 API)init/set/get/has/forget
  • K3 wifi.c 扩展 — STA 连接 + event group + IP_GOT 门控 + 3 次自动重试 + wifi_get_status()~150 行新增
  • K4 wifi 命令重设计 — scan / connect ssid= pass= / disconnect / forget / status 五子命令save=1 自动持久化
  • K5 partitions.csv 双 OTA 布局 — ota_0/ota_1 各 5 M + storage 5 M + rollback gate sdkconfigCONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
  • K6 ?ota download url= 真实路径 — esp_https_ota 流式 + 整数百分点 EVT 上报 + 完成不自动重启AI 主导何时切槽
  • K7 端到端验证 — clean rebuild 65.5s 0 warnings / sim diff 13/13 identical / pytest 3/3 / manifest 17 cmds全过
  • K8 v1.7.0 tag + 本汇报 HTML v6 + CHANGELOG entry本提交
§ 05 — aurora-harness 公共 API

组件能给一个
新项目什么

完整的 30+ 函数 / 类型. 公共头位于 components/aurora-harness/include/harness/. 任何 ESP-IDF + LVGL 项目 vendor 此组件即用。

harness/console_protocol.h
console_protocol_init()
启动 serial 解析 task + 注册 ?ping/?reset/?help (含 ?help json)
console_protocol_register(&cmd)
注册一个 console_cmd_t. 静态存储, 程序生命周期内有效
console_reply_ok(fmt, ...)
console_reply_err(fmt, ...)
从 handler 内回复. printf 风格格式串
console_send_evt(fmt, ...)
主动 EVT 行 (异步事件, 不响应命令)
console_begin_payload(TAG, meta)
console_write_raw(buf, n)
console_end_payload(TAG)
多行 payload 帧 (JSON dump / 截图 base64 等), <TAG>_BEGIN / <TAG>_END 包裹
harness/scene_framework.h
scene_t (struct)
id / display_name / accent / description / tags / 6 个 lifecycle 钩子 (init / on_show / on_hide / frame / on_tilt / on_long_press / on_release) / user_data
scene_fw_init(root_obj)
挂载框架到根 LVGL 对象 + 启 33ms frame timer
scene_fw_register(&scene)
注册一个 scene. 上限 24, 满了打 ESP_LOGE
scene_fw_show(idx) / next() / prev()
切换场景, 280ms 淡入淡出
scene_fw_push_tilt(ax, ay, az)
把 IMU 读数喂给当前场景 (其它 scene 不打扰)
scene_fw_count / current_index / current / get(i)
introspection
harness/toast.h
harness_toast(text, ms)
浮层提示, 任意 task 安全 (lv_async_call 派遣). 默认 1500ms. 新调用替换旧 toast.
harness_toast_dismiss()
立即清掉. 用于 scene on_hide 礼貌清理
harness/progress.h — new in v1.4
harness_progress_show(text, percent)
浮层进度条 (label + bar). 首次调用创建, 后续 in-place 更新. 任意 task 安全.
harness_progress_dismiss()
显式收掉. 与 toast 不同, progress 没有自动 expire — 显式生命周期
harness/default_cmds.h — expanded v1.4
harness_default_register()
opt-in 注册全套默认命令: ?stat / scene / tap / swipe / ?dump. 一行覆盖所有 LVGL+console 项目应有的基础.
harness_record_frame()
每帧调一次喂 ?stat 的 fps 字段
harness/screenshot.h — new in v1.4
harness_screenshot_register()
注册 ?dump 命令 — LVGL 截屏 + 顶层合成 + 下采样 + base64. PSRAM 持久缓冲. harness_default_register 已自动调.
harness/bsp_iface.h — new in v1.4
bsp_display_lock(timeout_ms) → bool
bsp_display_unlock()
组件依赖的全部 BSP 符号。任何 Espressif-style BSP 自带; 自定义板提供同名实现即可。多板移植清单见 PORTING.md.
scene_fw_set_change_listener — new in v1.4
scene_fw_set_change_listener(cb)
注册一个 void (int idx, const scene_t *) 回调, 每次 scene_fw_show 完成后触发. 应用用它来同步 UI chrome (ui_shell 等), 让 cmd_scene 不必硬依赖应用层 widgets.
scene_fw_find_by_id(id) → int
按 scene id 字符串线性查找索引 (-1 = not found). cmd_scene 用于 scene halo 这种按名切换.
§ 06 — 本轮新增 scene

XIX Notify —
toast 原语的参考实现

每个新原语都该有一个最小可见示范, 让"怎么用"变成"复制粘贴"。 Notify 就是 harness_toast() 的 demo。 BOOT 循环 5 种 toast (1.5s 默认), USER 触发 3s 长 toast, 计数器跟踪触发次数, on_hide 时主动 dismiss 防 toast 跨 scene 漏出。

id
notify
tags
demo,toast,reference
description (manifest)
Reference demo for harness_toast(); BOOT cycles 5 variants, USER long-holds
§ 07 — 路线图状态

第一档清空,
下一档要解前置依赖

已完成 (v1.2/v1.3)

★★★
2 hr
Golden BMP diff + CI
sim diff + update-golden, per-scene thresholds, GitHub Actions ubuntu workflow.
DONE
★★★
1.5 hr
Sim 接更多 scene
11 → 12 scene 可 host 跑 (Halo / Grid / Bloom / Tilt / Pulse / Cell / Keys / Tone / System / Glow / Spin / Notify).
DONE
★★
30 min
scene <id> 切换
scene halo / scene survey 直接生效。顺手修 bsp_display_lock(0) 死锁.
DONE
★★★
2 hr
aurora-harness 组件化
console_protocol + scene_framework + toast + default_cmds 提进 ESP-IDF 组件, 完整 README + idf_component.yml.
DONE
★★
1 hr
esp-harness init 模板生成器
esp-harness init <name> 9 文件起一个新项目骨架, 直接 build/flash 跑得起来.
DONE

下一档 (中期, 需前置)

★★★
3 hr
真实 OTA over HTTPS
K5-K6 完成. partitions.csv 双 ota_0/ota_1 槽 + rollback gate, ?ota download url= 接 esp_https_ota 流式拉取, 整数百分点 EVT 进度. 完成不自动重启 — AI 控制何时切槽.
DONE v1.7
★★★
2 hr
WiFi STA 连接 + NVS 凭证持久化
K2-K4 完成. wifi connect ssid= pass= save=1 一行入网, event-group + IP_GOT 双门控防"假绿灯". NVS namespace wifi_cred 重启自动续连. 配网 UI 留待 v1.8 NimBLE peripheral.
DONE v1.7
★★
3 hr
WiFi 一次性配网 (NimBLE peripheral)
现在 NimBLE 只 observer 模式. 加 peripheral GATT 接收 SSID/PASS → NVS 私密 namespace. v1.7 的 wifi_creds API 已就位, 只差 BLE 配网 UI.
v1.8
★★
2 hr
cmd_scene / cmd_tap / swipe / cmd_dump 全部上提
H1-H3 完成. scene_change_listener 钩子解 ui_shell 耦合; screenshot.c 独立成模块. harness_default_register 一行注册全套.
DONE v1.4
★★
1 hr
aurora-harness 解 BSP 硬绑定 + 多板清单
H4 完成. 组件依赖收缩到 bsp_iface.h 的两个符号 (lock/unlock), PORTING.md 8 步检核表.
DONE v1.4
★★
1 hr
harness_progress() 进度条原语 + Scene XX Track
H5 完成. lv_layer_top 浮层 label+bar, 与 toast 对称的显式生命周期 API. Track 是 5s 下载模拟示范.
DONE v1.4
2 hr
esp-harness doctor + test (pytest integration)
H7-H8 完成. doctor 8 项依赖, test 跑 pytest 3 个 integration test 含 sim diff 回归. esp-harness test 入口.
DONE v1.4
1 hr
idf_component.yml registry 准备 + RELEASING.md
H9 完成. 元数据 + tags + targets + files.exclude. compote upload 步骤 + semver 规则 + 不删 API 政策都写入 RELEASING.md. 实际 upload 留给最终决定要发布的时刻.
DONE v1.4

长期 / 探索

8+ hr
把别的板子接进来
现在只跑过 Waveshare ESP32-S3-Touch-AMOLED-2.16. 接 ESP32-C6 / S3-WROOM / 其他屏, 验证 BSP 抽象是否真可移植.
future
12+ hr
Webcam 真实视觉回环
USB 摄像头对真屏拍, 截图反喂 LLM 做"AI 真的看见了" 闭环. 比 ?dump 更接近用户视角.
future
unknown
把 aurora-harness 发布到 IDF Component Registry
现在用 EXTRA_COMPONENT_DIRS 路径依赖. 发布后任何项目 idf_component.yml 一行就能引入.
future
§ 08 — 收尾

v1.4 之后, 想用这套
开个新 ESP-IDF + LVGL 项目
一条命令

esp-harness init my-thing