Files
story/docs/蓝牙配网_实现与烧录.md
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

6.7 KiB
Raw Permalink Blame History

蓝牙配网实现与烧录

实现依据为《蓝牙配网与账号绑定_完整精简版》。业务报文只保留 cmd、Wi-Fi 名称、Wi-Fi 密码和 bind_token;使用者的选择由平台完成,不增加蓝牙账号字段。

使用

  1. 登录客户平台,在“设备”页展开“通过蓝牙添加设备”。
  2. 新设备首次启动进入配网;以后长按圆屏底部3秒重新进入。
  3. 输入设备标签编号和配网密码,点击“发现附近设备”,选择 EchoEar- 加编号末六位的设备。
  4. 页面验证设备身份并显示型号,填写2.4GHz WPA2家庭Wi-Fi,选择使用者后发送。
  5. 60秒内短触设备屏幕确认。等待页面显示“配网和绑定成功”。

浏览器需要安全上下文和 Web Bluetooth;电脑/Android 支持该功能的 Chrome/Edge 可用,iPhone/iPad 当前需改用电脑。浏览器弹出系统设备选择器,不允许页面静默扫描。当前版本采用手动输入标签凭据,未实现相机扫描二维码。

蓝牙断开不代表失败:点击“查询绑定结果”确认云端状态。云端成功与设备保存成功分开显示。配网密码和令牌仅保存在内存/必要的设备断电恢复记录中,不发送到分析日志;账号登录密码不传给设备。

文件与接口

  • 前端:web/src/components/BLEProvisioning.tsx、web/src/ble/client.ts、web/src/ble/security2.ts。
  • 服务端:internal/onboarding/ble.go、迁移 000063_ble_binding。
  • 契约:openapi/ble-binding.yaml。
  • 固件:main/ble_setup.c(GATT/实体确认/断电恢复)、main/ble_cloud.c(工厂凭据/校时/设备签名)。
  • 工厂工具:tools/ble_factory.py;受控旧设备迁移命令:cmd/ble-device-migrate。

服务端新增三条 POST 接口:/api/v1/web/ble-bind-tokens、/api/v1/web/ble-bind-status、/api/v1/device/ble-bind。Cookie请求沿用同源和CSRF校验,设备请求使用已有DEVREQ1认证。令牌有效期5分钟、单次提交、按账号与设备隔离;并发或失去响应后重试不会产生重复绑定。

工厂凭据

每台设备需要已有生产登记的32字节设备认证密钥。配网工具生成独立的随机配网密码和SRP salt/verifier,浏览器只接触配网密码,不获得设备认证密钥。

python tools/ble_factory.py --device-id KP01-B43A451634A8 --model ECHOEAR-S3 --origin https://121.41.46.238 --key-version 1 --device-key-file <受控密钥文件> --output <新的私有输出目录>

输出的 ble_factory.bin 和 factory.csv 含设备密钥,必须作为私有材料保存,不能提交Git、上传页面或放入发布包。setup-label.json 是交付给设备持有者的配网标签,同样不要公开。Windows 请使用当前用户专属目录/ACL;POSIX 工具设置0600权限。

使用ESP-IDF v5.5.1 Protocomm Security2 patch1。兼容性以C固件 esp_srp.c 为准:哈希时保留salt和内层SHA512摘要的前导零,客户端公钥固定384字节;设备公钥按C实现实际字节数读取。不要直接依赖Python示例对整数前导零的裁剪行为。

构建和烧录

$env:PYTHONUTF8='1'
$env:PYTHONIOENCODING='utf-8'
$env:Path='C:\Users\19926\.espressif\python_env\idf5.5_py3.12_env\Scripts;'+$env:Path
. 'E:\Codex\toolchains\esp-idf-v5.5.1\export.ps1'
idf.py -D CMAKE_NINJA_FORCE_RESPONSE_FILE=ON build

保留16MB Flash、16MB PSRAM、80MHz配置。Windows需要response file以避免新增蓝牙依赖后的命令行长度限制。

ble_factory 是新增的独立NVS分区,固定 0xe4e000、大小 0x6000。原来的应用/语音模型/动画/NVS分区位置不变。首次升级先核对芯片和MAC,完整备份,再只写分区表、应用和该设备的工厂分区:

python -m esptool --chip esp32s3 --port COM6 write_flash 0x8000 build/partition_table/partition-table.bin 0x10000 build/VolcRTCDemo.bin 0xe4e000 <私有目录>/ble_factory.bin

不要擦除整片Flash,不要覆盖原Wi-Fi/平台NVS。已有受保护身份且不能迁移的设备应保持旧认证;迁移命令要求明确授权、精确设备UUID/原绑定UUID/MAC,并拒绝存在未结束通话的设备。它关闭当前绑定而不删除历史通话,旧身份和平台备份单独保留。

验证与范围

go test ./...
./scripts/test-onboarding-integration.ps1 -Packages onboarding,httpapi
cd web
node --test test/ble-security.test.mjs test/ble-client.test.mjs
npm run build

实体按键、Windows蓝牙栈、Wi-Fi实际联网和掉电恢复还需要真机验证,不能用编译或模拟测试代替。

本次交付到“Wi-Fi已保存、平台账号绑定成功”为止。火山供应商激活与语音会话是独立流程:迁移设备不会继续发送旧设备签名,也不会将“绑定成功”冒充“语音服务已开通”。新身份下的供应商激活/会话固件流程仍需另行接入;完成绑定后屏幕会停在联网/待开通提示。

2026-09-13 部署与真机记录

  • 线上版本:0.84.0-rc.ble-bind1,数据库迁移63完成;API、worker、callbacks和网页已更新,健康检查通过。客户入口:https://121.41.46.238/?section=devices。
  • 经设备持有者授权,将这台设备从旧绑定迁移为 KP01-B43A451634A8,型号 ECHOEAR-S3,蓝牙名称 EchoEar-1634A8。当前为待重新绑定状态,44条历史通话保留;没有替用户创建新账号绑定。
  • COM6实机确认ESP32-S3、16MB Flash、16MB PSRAM。升级前完整16MB备份SHA256:C2FD23938882E6F22C6D14AC1A2E51C517C3349B7CC84B1E66F3D17B4730A0AF。
  • 首版真机发生循环重启:显示程序与蓝牙工作任务争用片内内存,NimBLE初始化失败后进入旧Wi-Fi初始化并触发异常。修复为蓝牙两个工作任务栈及NimBLE主机堆使用PSRAM,并在蓝牙初始化失败时停留错误页面,不再回退旧Wi-Fi流程。
  • 修复固件应用SHA256:B22D541EB67E766631A29DAEF352D42C024A15974C2434BAA670853DD7143B1A,已仅重写应用分区并通过设备端哈希校验。启动时蓝牙初始化前片内空闲91623字节,最大连续块51200字节;启动任务正常退出。
  • 使用Windows真实蓝牙栈与网页同一份Security2实现完成SRP/AES加密握手,连续读取两次设备编号/型号和两次idle状态,均通过。
  • 软件验证:Go全量测试、真实隔离PostgreSQL/Redis的onboarding和httpapi集成测试、7项蓝牙前端测试、网页生产构建通过。线上设备签名校时与鉴权验证通过。
  • 待验收:用户登录、发送真实Wi-Fi、实体短触确认、设备实际联网并提交绑定,以及掉电恢复。上述步骤未完成前,不应把蓝牙通信成功当作整机配网绑定成功。