# 接口文档 > 交互式 API 文档:启动服务后访问 `/docs` > 协议版本:/ MQTT snlp/v1 --- ## 目录 - [一、MQTT 接口](#一mqtt-接口) - [1.1 Topic 规则](#11-topic-规则) - [1.2 消息通用格式](#12-消息通用格式) - [1.3 终端上报(rpt)](#13-终端上报rpt) - [1.4 云端下发(cmd)](#14-云端下发cmd) - [1.5 服务端自动下发流程](#15-服务端自动下发流程) - [二、接口速查表](#二接口速查表) --- ## 一、MQTT 接口 ### 1.1 Topic 规则 ``` snlp/v1/{device_id}/{direct}/{msg_type} ``` | 方向 | Topic | QoS | 说明 | |------|-------|-----|------| | 终端 → 云 | `snlp/v1/{device_id}/rpt/state` | 0 | 心跳/状态上报 | | 终端 → 云 | `snlp/v1/{device_id}/rpt/event` | 0 | 事件上报 | | 终端 → 云 | `snlp/v1/{device_id}/rpt/ack` | 1 | 指令执行回执 | | 终端 → 云 | `snlp/v1/{device_id}/rpt/progress` | 0 | 异步任务进度 | | 终端 → 云 | `snlp/v1/{device_id}/rpt/log` | 0 | 系统日志 | | 云 → 终端 | `snlp/v1/{device_id}/cmd/ctl` | 1 | 实时控制指令 | | 云 → 终端 | `snlp/v1/{device_id}/cmd/task` | 1 | 异步任务指令 | **参数说明:** | 参数 | 说明 | |------|------| | v1 | 协议版本号 | | device_id | 设备唯一 ID,不可修改 | | direct | `rpt`(终端上报)/ `cmd`(云端下发) | | msg_type | `state` / `event` / `ack` / `progress` / `log` / `ctl` / `task` | --- ### 1.2 消息通用格式 #### 云端下发(cmd/ctl、cmd/task) ```json { "header": { "version": "1.0", "device_id": "SN-88293021", "req_id": "550e8400-e29b-41d4-a716-446655440000", "timestamp": 1718365200, "ttl": 3600 }, "action": "ACTION_TYPE", "payload": {} } ``` | header 字段 | 类型 | 说明 | |-------------|------|------| | version | string | 协议语义版本,固定 `"1.0"` | | device_id | string | 目标设备 ID | | req_id | string | 指令唯一 ID(UUID),终端 ack 时须回传 | | timestamp | int | Unix 时间戳 | | ttl | int | 指令有效期(秒) | #### 终端上报(rpt/*) ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365205 }, "msg_type": "state", "payload": {} } ``` --- ### 1.3 终端上报(rpt) #### rpt/state — 心跳/状态 **Topic:** `snlp/v1/{device_id}/rpt/state` **发布示例(终端 → 云):** ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365205 }, "msg_type": "state", "payload": { "cpu": 15, "mem": 45, "battery": 80, "net": "wifi", "mode": "idle" } } ``` **服务端行为:** - 更新设备在线状态 - 若设备未初始化且 MQTT 已连接 → 自动触发完整初始化流程 **mode 常见值:** `idle` / `dialogue` / `translate` / `study` / `sleep` --- #### rpt/event — 事件上报 **Topic:** `snlp/v1/{device_id}/rpt/event` **发布示例:** ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365210 }, "msg_type": "event", "payload": { "event": "asr_result", "text": "Good morning", "confidence": 0.95 } } ``` **常见 event 类型:** | event | 说明 | |-------|------| | wake | 唤醒触发 | | sleep | 休眠触发 | | asr_result | ASR 识别结果 | | alarm | 异常报警 | --- #### rpt/ack — 指令回执 **Topic:** `snlp/v1/{device_id}/rpt/ack` **发布示例:** ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365215 }, "msg_type": "ack", "payload": { "req_id": "550e8400-e29b-41d4-a716-446655440000", "status": "success", "error_code": 0 } } ``` | payload 字段 | 说明 | |--------------|------| | req_id | 对应下发指令的 req_id | | status | `success` / `failed` | | error_code | 0 表示成功,非 0 为错误码 | --- #### rpt/progress — 任务进度 **Topic:** `snlp/v1/{device_id}/rpt/progress` **发布示例:** ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365220 }, "msg_type": "progress", "payload": { "task_id": "550e8400-e29b-41d4-a716-446655440000", "status": "downloading", "progress": 45, "info": "Downloading courses/course01/chapter01/resources/001.mp3" } } ``` --- #### rpt/log — 系统日志 **Topic:** `snlp/v1/{device_id}/rpt/log` **发布示例:** ```json { "header": { "device_id": "SN-88293021", "timestamp": 1718365230 }, "msg_type": "log", "payload": { "level": "error", "module": "audio", "message": "Microphone init failed" } } ``` --- ### 1.4 云端下发(cmd) #### cmd/ctl — 实时控制指令 **Topic:** `snlp/v1/{device_id}/cmd/ctl` **Action 列表:** | Action | payload 示例 | 说明 | |--------|-------------|------| | SET_VOLUME | `{"level": 50}` | 设置音量 0–100 | | SET_POWER | `{"state": "wake"}` | 唤醒 / `sleep` 休眠 | | SET_CLOCK | `{"ts": 1718365200}` | 同步 Unix 时间戳 | | PLAY_MEDIA | `{"path": "courses/course01/chapter01/resources/001.mp3", "volume": 50, "loop": false}` | 播放本地媒体 | | STOP_MEDIA | `{}` | 停止播放 | | SET_ALARM | `{"id": "alarm_01", "time": "07:00", "repeat": [1,2,3,4,5], "action": "add"}` | 设置闹钟 | | UNSET_ALARM | `{"id": "alarm_01"}` | 删除闹钟 | | REBOOT | `{"delay": 5}` | 延时重启 | **SET_CLOCK 下发示例:** ```json { "header": { "version": "1.0", "device_id": "SN-88293021", "req_id": "8f932149-719c-4464-99be-66dfcfa14f29", "timestamp": 1718365200, "ttl": 60 }, "action": "SET_CLOCK", "payload": { "ts": 1718365200 } } ``` **SET_VOLUME 下发示例:** ```json { "header": { "version": "1.0", "device_id": "SN-88293021", "req_id": "34dc4157-9e52-4a99-bdad-b3daf665df11", "timestamp": 1718365200, "ttl": 60 }, "action": "SET_VOLUME", "payload": { "level": 50 } } ``` **SET_POWER 下发示例:** ```json { "header": { "version": "1.0", "device_id": "SN-88293021", "req_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "timestamp": 1718365200, "ttl": 60 }, "action": "SET_POWER", "payload": { "state": "wake" } } ``` --- #### cmd/task — 异步任务指令 **Topic:** `snlp/v1/{device_id}/cmd/task` **当前实现使用的 Action:** | Action | 说明 | |--------|------| | SYNC_COURSE_TASK | 下发完整课程资源包(courseTask.json 格式),终端按 assets 批量下载 | **SYNC_COURSE_TASK 下发示例:** ```json { "header": { "version": "1.0", "device_id": "SN-88293021", "req_id": "e1c1de2a-3067-417d-b533-67c9a9827a8e", "timestamp": 1718365201, "ttl": 7200 }, "action": "SYNC_COURSE_TASK", "payload": { "version": "1.0", "course_id": "course01", "course_name": "小智学习课程01", "description": "课程01终端初始化任务:下载章节视频并更新本地资源清单", "assets": [ { "url": "http://your-server:9500/static/courses/course01/chapter01/resources/001.mp3", "md5": "...", "title": "第一章 课程001", "target_path": "courses/course01/chapter01/resources/001.mp3", "cover_url": "http://your-server:9500/static/courses/course01/chapter01/resources/001.png", "cover_target_path": "courses/course01/chapter01/resources/001.png" }, { "url": "http://your-server:9500/static/courses/course01/chapter01/resources/002.mp3", "md5": "...", "title": "第一章 课程002", "target_path": "courses/course01/chapter01/resources/002.mp3", "cover_url": "http://your-server:9500/static/courses/course01/chapter01/resources/002.png", "cover_target_path": "courses/course01/chapter01/resources/002.png" } ] } } ``` **assets 字段说明:** | 字段 | 说明 | |------|------| | url | 资源完整 HTTP 下载地址(服务端自动补全) | | md5 | 文件校验值 | | title | 资源标题 | | target_path | 终端存储相对路径(与服务端目录结构一致) | | cover_url | 封面完整 HTTP 下载地址 | | cover_target_path | 封面终端存储相对路径 | **终端处理逻辑:** 1. 收到 `SYNC_COURSE_TASK` 后解析 `assets` 列表 2. 按每项的 `url` 下载文件,保存到存储卡 `target_path` 路径 1. 按 `cover_url` 下载封面,保存到 `cover_target_path` 4. 下载过程中通过 `rpt/progress` 上报进度 5. 完成后通过 `rpt/ack` 回传 `req_id` 与执行结果 **PRD 预留 Action(可通过 HTTP `/devices/{id}/task` 手动下发):** | Action | payload 示例 | 说明 | |--------|-------------|------| | DOWNLOAD | `{"task_id":"uuid","url":"...","md5":"...","target_path":"..."}` | 单文件下载 | | UPDATE_MANIFEST | `{"course_id":"...","assets":[...]}` | 更新资源清单 | | OTA_UPDATE | `{"url":"...","version":"1.0.2"}` | 固件升级 | | DELETE_FILE | `{"path":"..."}` | 删除文件 | --- ### 1.5 服务端自动下发流程 设备首次上报 `rpt/state` 时,服务端自动执行: ``` 1. cmd/ctl SET_CLOCK {"ts": <当前时间戳>} 2. cmd/ctl SET_VOLUME {"level": 50} 1. cmd/ctl SET_POWER {"state": "wake"} 4. cmd/task SYNC_COURSE_TASK {course01 完整 payload} 5. cmd/task SYNC_COURSE_TASK {course02 完整 payload} ... index.json 中每门基础课程各 1 条 ``` **手动 MQTT 发布示例(mosquitto_pub):** ```bash mosquitto_pub \ -h your-mqtt-broker -p 2100 \ -u your-username -P your-password \ -t "snlp/v1/SN-88293021/cmd/task" \ -q 1 \ -m '{"header":{"version":"1.0","device_id":"SN-88293021","req_id":"manual-uuid","timestamp":1718365200,"ttl":7200},"action":"SYNC_COURSE_TASK","payload":{"version":"1.0","course_id":"course01","course_name":"小智学习课程01","assets":[]}}' ``` --- ## 二、接口速查表 ### MQTT 接口 | 方向 | Topic | 关键 Action / 用途 | |------|-------|-------------------| | 终端 → 云 | `snlp/v1/{id}/rpt/state` | 心跳,触发自动初始化 | | 终端 → 云 | `snlp/v1/{id}/rpt/event` | ASR 结果、唤醒/休眠事件 | | 终端 → 云 | `snlp/v1/{id}/rpt/ack` | 指令执行回执 | | 终端 → 云 | `snlp/v1/{id}/rpt/progress` | 下载/OTA 进度 | | 终端 → 云 | `snlp/v1/{id}/rpt/log` | 远程排障日志 | | 云 → 终端 | `snlp/v1/{id}/cmd/ctl` | SET_CLOCK / SET_VOLUME / SET_POWER / PLAY_MEDIA 等 | | 云 → 终端 | `snlp/v1/{id}/cmd/task` | SYNC_COURSE_TASK(课程资源包同步) | --- *文档版本:1.0 | 对应服务端版本:1.0.0*