feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
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.
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
# 平台注册火山与设备取参
|
||||
|
||||
2026-09-15 · 新流程:平台代注册,绑定直接下发凭据;设备本地初始化 SDK 后直接 chat/start,不再登记 boot_id 或上报初始化回执。第 3、4 节仅供旧固件兼容,新设备不要实现。
|
||||
|
||||
## 1. 业务分工
|
||||
|
||||
平台在 ble-bind 请求中绑定老人、调用火山 DynamicRegister,保存物理设备的专属密钥和 RTCAppID,拿齐配置后才返回成功。后台任务保留作恢复兜底,与请求处理共用同一注册记录,不重复注册。设备不拿 product_secret,不调用 DynamicRegister。
|
||||
|
||||
物理设备只注册一次。重新绑定老人不重复注册;聊天时的 bot_id 跟随老人变化。注册超时不等于失败,平台标记待核对,不自动重复消耗注册流程。
|
||||
|
||||
## 2. 绑定时直接返回 5 个字段
|
||||
|
||||
`POST https://82.157.201.114/api/v1/device/ble-bind`
|
||||
|
||||
输入:`{"bind_token":"<原令牌>"}`。
|
||||
|
||||
成功 data(不再包含 voice_status / voice):
|
||||
|
||||
```json
|
||||
{
|
||||
"status":"success",
|
||||
"instance_id":"<实例>",
|
||||
"product_key":"<产品>",
|
||||
"device_name":"<火山设备名>",
|
||||
"device_secret":"<本设备的火山密钥>",
|
||||
"RTCAppID":"<应用ID>"
|
||||
}
|
||||
```
|
||||
|
||||
success 必须带齐以上字段;设备保存它们和 Wi-Fi 后再向小程序报告 success。无需另调取参接口等待 ready。开机读取本地凭据初始化 SDK,聊天请求只需 device_id 和 session_id。
|
||||
|
||||
设备请求超时设 45 秒,平台取参等待上限 35 秒。HTTP 504 / VOICE_REGISTRATION_TIMEOUT 表示等待超时;502 / VOICE_REGISTRATION_FAILED 表示失败或结果未确认;503 / VOICE_REGISTRATION_PAUSED 表示服务暂停;502 / VOICE_CONFIG_INVALID 表示配置不完整;409 / VOICE_MIGRATION_REQUIRED 表示旧设备需补交凭据。它们都不返回成功或空配置,也不删除已完成的绑定。网络超时、5xx 保留原 bind_token 和 X-Request-ID 重试,刷新时间、nonce 和签名;注册结果不确定时由平台核对,不盲目重复注册。
|
||||
|
||||
若等待期间解绑,返回 409 / BINDING_CHANGED,不下发凭据。成功响应丢失后,即使原令牌已过期,只要原绑定仍有效,也能用原令牌重新取得相同配置。
|
||||
|
||||
以下是**可选恢复接口,正常绑定不需要调用**:
|
||||
|
||||
`POST https://82.157.201.114/api/v1/device/voice-config`
|
||||
|
||||
输入:`{}`。可在绑定后直接调用,不要求先完成本次 boot 登记。
|
||||
|
||||
成功 data 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"voice_status":"ready",
|
||||
"voice":{
|
||||
"instance_id":"<实例>",
|
||||
"product_key":"<产品>",
|
||||
"device_name":"<火山设备名>",
|
||||
"device_secret":"<本设备的火山密钥>",
|
||||
"RTCAppID":"<应用ID>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
preparing 时每 5 秒重试;paused、reconcile_required 时提示平台处理;migration_required 见第 5 节。非 ready 时 voice=null。解绑后返回 409 DEVICE_UNBOUND,不下发旧凭据。
|
||||
|
||||
## 3. 旧固件兼容:开机获取 SDK 配置(新设备不调用)
|
||||
|
||||
设备照常完成 time-challenges → register 后,调用:
|
||||
|
||||
`POST https://82.157.201.114/api/v1/device/voice-runtime`
|
||||
|
||||
输入:
|
||||
|
||||
```json
|
||||
{"boot_id":"<本次已登记的开机UUID>"}
|
||||
```
|
||||
|
||||
输出 data 中有:
|
||||
|
||||
| 字段 | 用途 |
|
||||
|---|---|
|
||||
| voice_status / voice | 与 voice-config 相同的状态和 5 个字段 |
|
||||
| state | 当前绑定和激活状态 |
|
||||
| command | ready 时的配置命令;未就绪时可为 null |
|
||||
| command.payload.config_b64 | Base64URL 编码的配置,下例为解码后的内容 |
|
||||
| command.payload.config_mac | 现有 CFG1 配置签名 |
|
||||
| call_contract | 旧兼容字段,不据此切回旧聊天接口 |
|
||||
|
||||
```json
|
||||
{
|
||||
"contract_version":"ONBOARDING-1.1",
|
||||
"device_id":"KP01-020000260914",
|
||||
"activation_id":"<平台激活任务UUID>",
|
||||
"config_version":1,
|
||||
"binding_generation":1,
|
||||
"expires_at_ms":1789459200000,
|
||||
"iot":{
|
||||
"instance_id":"<实例>",
|
||||
"product_key":"<产品>",
|
||||
"device_name":"<火山设备名>",
|
||||
"device_secret":"<本设备的火山密钥>",
|
||||
"RTCAppID":"<应用ID>"
|
||||
},
|
||||
"bot_id":"<兼容的默认值,实际聊天仍用chat/start返回值>"
|
||||
}
|
||||
```
|
||||
|
||||
校验 `config_mac=小写hex(HMAC_SHA256(烧录设备密钥, UTF8("CFG1\n"+config_b64)))`,再 Base64URL 解码 config_b64 并解析 JSON。核对 device_id、binding_generation 与 state 一致,expires_at_ms 未过期。新固件沿用此封装,不再提取 product_secret。
|
||||
|
||||
preparing 时自动等待,每 5 秒再次请求;不要把 preparing 当成需要解绑。获取配置后保存 5 个语音字段,以及 activation_id、config_version,再初始化 RTC SDK。
|
||||
|
||||
## 4. 旧固件兼容:SDK 初始化完成通知(新设备不调用)
|
||||
|
||||
`POST https://82.157.201.114/api/v1/device/activation-acks`
|
||||
|
||||
输入:
|
||||
|
||||
```json
|
||||
{"activation_id":"<上一步UUID>","config_version":1,"local_generation":1}
|
||||
```
|
||||
|
||||
activation_id、config_version 使用最新配置原值,local_generation 可使用 config_version。输出 data 中 accepted=true 表示平台已记录配置保存和 SDK 初始化完成;不是说用户已经完成第一次聊天。
|
||||
|
||||
随后每次聊天调用 chat/start,结合平台下发的凭据,用 SDK 获取 RTC 房间并收发音频。聊天结束继续调用 chat/end。
|
||||
|
||||
新设备不再调用 activation-attempts,也不发送 SDK_REGISTER activation-results。旧结果接口保留用于尚未上报完成的旧固件任务恢复。
|
||||
|
||||
## 5. 已注册旧设备的一次性迁移
|
||||
|
||||
旧固件可能只把火山密钥保存在本机,平台只有“已注册”记录。此时返回 migration_required,**不能重新注册这台设备**。
|
||||
|
||||
更新后的固件读取本机原凭据,调用:
|
||||
|
||||
`POST https://82.157.201.114/api/v1/device/voice-credentials`
|
||||
|
||||
输入:
|
||||
|
||||
```json
|
||||
{
|
||||
"instance_id":"<本机原实例>",
|
||||
"product_key":"<本机原产品>",
|
||||
"device_name":"<本机原火山设备名>",
|
||||
"device_secret":"<本机原火山密钥>",
|
||||
"RTCAppID":"<本机原应用ID>"
|
||||
}
|
||||
```
|
||||
|
||||
输出 data:`{"accepted":true}`。然后重新调用 voice-runtime。
|
||||
|
||||
平台只接受本设备已完成注册、身份匹配的旧凭据;相同内容重试不会重复写入,不允许覆盖平台已有的不同凭据。如果旧设备密钥已丢失,或注册结果不确定,需要运维核对,不能伪造凭据或盲目注册。
|
||||
|
||||
## 6. 接入与发布说明
|
||||
|
||||
以上设备 HTTP 接口均使用已有 DEVREQ1 请求头和 `{ok,code,request_id,server_time_ms,data}` 外层。设备凭据不经过小程序/蓝牙,不打印日志。平台凭据沿用既有加密存储格式。
|
||||
|
||||
后端 API 和 worker 已部署新服务器,旧 IP 暂时转发到新服务器。尚需用受控实物验证真实火山注册、设备持久化、SDK 初始化和实际通话。已有设备先备份运行凭据,不能把测试用凭据写入实物。
|
||||
Reference in New Issue
Block a user