# 蓝牙配网实现与烧录 实现依据为《蓝牙配网与账号绑定_完整精简版》。业务报文只保留 `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,浏览器只接触配网密码,不获得设备认证密钥。 ```powershell 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示例对整数前导零的裁剪行为。 ## 构建和烧录 ```powershell $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,完整备份,再只写分区表、应用和该设备的工厂分区: ```powershell 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,并拒绝存在未结束通话的设备。它关闭当前绑定而不删除历史通话,旧身份和平台备份单独保留。 ## 验证与范围 ```powershell 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、实体短触确认、设备实际联网并提交绑定,以及掉电恢复。上述步骤未完成前,不应把蓝牙通信成功当作整机配网绑定成功。