# 平台注册火山与设备取参 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 初始化和实际通话。已有设备先备份运行凭据,不能把测试用凭据写入实物。