feat: core tests, bug fixes, API docs rewrite, HTTP compat routes
- Fix state_machine reset_state_progress: reset sequence index before validation to prevent out-of-bounds error on state transitions - Fix video transformer test: use ±1 tolerance for OpenCV interpolation - Add core integration tests (service_manager, dependencies, messages) - Add HTTP compat routes (/index.html, POST /api/wifi/scan, hotspot aliases) - Rewrite clients/docs/API.md to match actual implementation - Fix BLE unused imports warning - CEO task planning for next round (ConfigReload, playlist snapshot) cargo check: 0 warnings, cargo test: 22/22 passed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,378 +2,312 @@
|
||||
|
||||
## 基础信息
|
||||
|
||||
- **Base URL**: `http://<device-ip>:8080/api`
|
||||
- **协议**: HTTP/1.1
|
||||
- **格式**: JSON
|
||||
- **编码**: UTF-8
|
||||
- Base URL: `http://<device-ip>:8080`
|
||||
- API 前缀: `/api`
|
||||
- 编码: `UTF-8`
|
||||
- 认证: 当前版本无认证
|
||||
|
||||
## 认证
|
||||
## 响应约定
|
||||
|
||||
当前版本暂不需要认证(局域网内使用)。未来版本将支持 Token 认证。
|
||||
- 控制类/写操作接口统一返回:
|
||||
|
||||
---
|
||||
|
||||
## 播放控制 API
|
||||
|
||||
### 播放
|
||||
```http
|
||||
POST /api/play
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "play"
|
||||
"status": "ok",
|
||||
"message": "开始播放"
|
||||
}
|
||||
```
|
||||
|
||||
### 暂停
|
||||
```http
|
||||
POST /api/pause
|
||||
```
|
||||
- 失败时返回:
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "pause"
|
||||
"status": "error",
|
||||
"message": "错误描述"
|
||||
}
|
||||
```
|
||||
|
||||
### 停止
|
||||
- 查询类接口直接返回业务 JSON,不包裹 `ok` 字段。
|
||||
|
||||
## Web UI
|
||||
|
||||
### 控制台页面
|
||||
|
||||
```http
|
||||
POST /api/stop
|
||||
GET /
|
||||
GET /index.html
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "stop"
|
||||
}
|
||||
- 当前实现为内嵌单文件 Web UI。
|
||||
- 暂无独立静态资源目录服务;页面所需 CSS/JS 已内嵌在 HTML 中。
|
||||
|
||||
## WebSocket
|
||||
|
||||
### 连接地址
|
||||
|
||||
```text
|
||||
ws://<device-ip>:8080/ws
|
||||
```
|
||||
|
||||
### 下一个
|
||||
```http
|
||||
POST /api/next
|
||||
```
|
||||
### 服务端事件
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "next"
|
||||
}
|
||||
```
|
||||
- `status_update`
|
||||
- `config_update`
|
||||
- `state_update`
|
||||
- `ble_update`
|
||||
|
||||
### 上一个
|
||||
```http
|
||||
POST /api/previous
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "previous"
|
||||
}
|
||||
```
|
||||
|
||||
### 跳转到指定视频
|
||||
```http
|
||||
POST /api/goto/:index
|
||||
```
|
||||
|
||||
**参数**:
|
||||
- `index` (path): 视频索引(从 0 开始)
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "goto",
|
||||
"index": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 状态机控制 API
|
||||
|
||||
### 触发状态切换
|
||||
```http
|
||||
POST /api/trigger/:name
|
||||
```
|
||||
|
||||
**参数**:
|
||||
- `name` (path): 触发器名称(如 "happy", "sad", "angry")
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "trigger",
|
||||
"name": "happy"
|
||||
}
|
||||
```
|
||||
|
||||
### 切换场景
|
||||
```http
|
||||
POST /api/scene/:index
|
||||
```
|
||||
|
||||
**参数**:
|
||||
- `index` (path): 场景索引(从 0 开始)
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "scene",
|
||||
"index": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 状态查询 API
|
||||
## 播放控制
|
||||
|
||||
### 获取播放状态
|
||||
|
||||
```http
|
||||
GET /api/status
|
||||
```
|
||||
|
||||
**响应**:
|
||||
响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"status": {
|
||||
"playing": true,
|
||||
"current_index": 0,
|
||||
"current_state": "idle",
|
||||
"current_scene": 0,
|
||||
"playlist_length": 10
|
||||
}
|
||||
"running": true,
|
||||
"paused": false,
|
||||
"in_transition": false,
|
||||
"current_index": 0,
|
||||
"playlist_length": 3,
|
||||
"current_video": "intro"
|
||||
}
|
||||
```
|
||||
|
||||
### 获取配置
|
||||
### 播放
|
||||
|
||||
```http
|
||||
POST /api/play
|
||||
```
|
||||
|
||||
### 暂停
|
||||
|
||||
```http
|
||||
POST /api/pause
|
||||
```
|
||||
|
||||
### 下一个
|
||||
|
||||
```http
|
||||
POST /api/next
|
||||
```
|
||||
|
||||
### 上一个
|
||||
|
||||
```http
|
||||
POST /api/previous
|
||||
```
|
||||
|
||||
### 跳转到指定视频
|
||||
|
||||
```http
|
||||
POST /api/goto/:index
|
||||
```
|
||||
|
||||
- `index`: 从 `0` 开始的视频索引
|
||||
|
||||
### 获取播放列表
|
||||
|
||||
```http
|
||||
GET /api/playlist
|
||||
```
|
||||
|
||||
### 切换场景
|
||||
|
||||
```http
|
||||
POST /api/scene/:name
|
||||
```
|
||||
|
||||
- `name`: 场景名称字符串,不是数字索引
|
||||
|
||||
### 触发状态机事件
|
||||
|
||||
```http
|
||||
POST /api/trigger/:name
|
||||
POST /api/trigger/:name/:value
|
||||
```
|
||||
|
||||
- `value` 为可选路径参数
|
||||
|
||||
## 配置
|
||||
|
||||
### 获取完整配置
|
||||
|
||||
```http
|
||||
GET /api/config
|
||||
```
|
||||
|
||||
**响应**:
|
||||
### 获取显示配置
|
||||
|
||||
```http
|
||||
GET /api/config/display
|
||||
```
|
||||
|
||||
### 更新配置
|
||||
|
||||
```http
|
||||
POST /api/config
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
- 请求体为完整配置 JSON
|
||||
- 服务端会先校验,再写回配置文件,并向管理层发送热重载请求
|
||||
|
||||
## 视频文件管理
|
||||
|
||||
### 获取视频列表
|
||||
|
||||
```http
|
||||
GET /api/videos
|
||||
```
|
||||
|
||||
响应示例:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "demo.mp4",
|
||||
"size": 1048576
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 上传视频
|
||||
|
||||
```http
|
||||
POST /api/videos/upload
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
- 表单字段名:`file`
|
||||
- 支持多文件上传
|
||||
|
||||
### 删除视频
|
||||
|
||||
```http
|
||||
DELETE /api/videos/:filename
|
||||
```
|
||||
|
||||
## WiFi
|
||||
|
||||
### 获取 WiFi 状态
|
||||
|
||||
```http
|
||||
GET /api/wifi/status
|
||||
```
|
||||
|
||||
响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"config": {
|
||||
"device_name": "ShowenV2",
|
||||
"render_width": 1920,
|
||||
"render_height": 1080,
|
||||
"scenes": [...]
|
||||
}
|
||||
"connected": true,
|
||||
"ssid": "MyWiFi",
|
||||
"ip": "192.168.1.10"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WiFi 管理 API
|
||||
|
||||
### 扫描 WiFi
|
||||
|
||||
```http
|
||||
GET /api/wifi/scan
|
||||
POST /api/wifi/scan
|
||||
```
|
||||
|
||||
**响应**:
|
||||
响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"networks": [
|
||||
{
|
||||
"ssid": "MyWiFi",
|
||||
"signal": -50,
|
||||
"security": "WPA2"
|
||||
}
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"ssid": "MyWiFi",
|
||||
"signal": -50,
|
||||
"security": "WPA2"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 连接 WiFi
|
||||
|
||||
```http
|
||||
POST /api/wifi/connect
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"ssid": "MyWiFi",
|
||||
"password": "password123"
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "connect",
|
||||
"ssid": "MyWiFi"
|
||||
}
|
||||
```
|
||||
|
||||
### 断开 WiFi
|
||||
```http
|
||||
POST /api/wifi/disconnect
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "disconnect"
|
||||
}
|
||||
```
|
||||
|
||||
### 开启热点
|
||||
|
||||
```http
|
||||
POST /api/wifi/ap/start
|
||||
POST /api/wifi/hotspot/start
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**响应**:
|
||||
请求体可选:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "hotspot_start"
|
||||
"ssid": "showen",
|
||||
"password": "12345678"
|
||||
}
|
||||
```
|
||||
|
||||
### 关闭热点
|
||||
|
||||
```http
|
||||
POST /api/wifi/ap/stop
|
||||
POST /api/wifi/hotspot/stop
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"action": "hotspot_stop"
|
||||
}
|
||||
```
|
||||
## BLE
|
||||
|
||||
---
|
||||
### 获取 BLE 状态
|
||||
|
||||
## Web UI
|
||||
|
||||
### 访问 Web 控制界面
|
||||
```http
|
||||
GET /
|
||||
GET /api/ble/status
|
||||
```
|
||||
|
||||
返回 HTML 控制界面。
|
||||
响应示例:
|
||||
|
||||
---
|
||||
|
||||
## WebSocket API
|
||||
|
||||
### 连接
|
||||
```
|
||||
ws://<device-ip>:8080/ws
|
||||
```
|
||||
|
||||
### 消息格式
|
||||
```json
|
||||
{
|
||||
"type": "status_update",
|
||||
"data": {
|
||||
"playing": true,
|
||||
"current_index": 0
|
||||
}
|
||||
"running": true,
|
||||
"embedded": true,
|
||||
"device_name": "showen"
|
||||
}
|
||||
```
|
||||
|
||||
### 消息类型
|
||||
- `status_update`: 状态更新
|
||||
- `config_update`: 配置更新
|
||||
- `error`: 错误消息
|
||||
### BLE 兼容启动接口
|
||||
|
||||
---
|
||||
```http
|
||||
POST /api/ble/start
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
## 错误响应
|
||||
请求体可选:
|
||||
|
||||
所有 API 在出错时返回:
|
||||
```json
|
||||
{
|
||||
"ok": false,
|
||||
"error": "错误描述"
|
||||
"device_name": "showen"
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP 状态码**:
|
||||
- `200 OK`: 成功
|
||||
- `400 Bad Request`: 请求参数错误
|
||||
- `404 Not Found`: 资源不存在
|
||||
- `500 Internal Server Error`: 服务器错误
|
||||
### BLE 兼容停止接口
|
||||
|
||||
---
|
||||
|
||||
## 示例代码
|
||||
|
||||
### JavaScript (Fetch API)
|
||||
```javascript
|
||||
// 播放
|
||||
fetch('http://192.168.1.100:8080/api/play', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => console.log(data));
|
||||
|
||||
// 获取状态
|
||||
fetch('http://192.168.1.100:8080/api/status')
|
||||
.then(res => res.json())
|
||||
.then(data => console.log(data.status));
|
||||
```http
|
||||
POST /api/ble/stop
|
||||
```
|
||||
|
||||
### Python (requests)
|
||||
```python
|
||||
import requests
|
||||
## 与旧文档的差异说明
|
||||
|
||||
# 播放
|
||||
response = requests.post('http://192.168.1.100:8080/api/play')
|
||||
print(response.json())
|
||||
|
||||
# 获取状态
|
||||
response = requests.get('http://192.168.1.100:8080/api/status')
|
||||
print(response.json()['status'])
|
||||
```
|
||||
|
||||
### Swift (URLSession)
|
||||
```swift
|
||||
// 播放
|
||||
let url = URL(string: "http://192.168.1.100:8080/api/play")!
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
|
||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
// 处理响应
|
||||
}.resume()
|
||||
```
|
||||
|
||||
### Kotlin (OkHttp)
|
||||
```kotlin
|
||||
// 播放
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder()
|
||||
.url("http://192.168.1.100:8080/api/play")
|
||||
.post(RequestBody.create(null, ByteArray(0)))
|
||||
.build()
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
// 处理响应
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2026-03-12
|
||||
**维护者**: ShowenV2 团队
|
||||
- 不存在 `/api/stop`
|
||||
- 不存在 `/api/wifi/disconnect`
|
||||
- `/api/scene/:name` 使用场景名,不使用数字索引
|
||||
- 查询接口直接返回业务对象,不再包裹 `{ "ok": true, ... }`
|
||||
|
||||
Reference in New Issue
Block a user