plc_control/API.md

567 lines
9.7 KiB
Markdown

# PLC Control API
本文档基于当前后端代码整理,覆盖 HTTP API、SSE 日志流和 WebSocket 实时消息。
## 基本信息
- UI: `/ui`
- HTTP API 前缀: `/api`
- 公共 WebSocket: `/ws/public`
- 客户端专属 WebSocket: `/ws/client/{client_id}`
- 日志 SSE: `/api/logs/stream`
## 通用错误响应
失败时通常返回:
```json
{
"err_code": 400,
"err_msg": "Invalid JSON format",
"err_detail": null
}
```
常见状态码:
- `400 Bad Request`: 参数非法或业务前置条件不满足
- `403 Forbidden`: 控制条件不满足或无写入权限
- `404 Not Found`: 资源不存在
- `500 Internal Server Error`: 服务端内部错误
## Source
### GET `/api/source`
获取数据源列表及连接状态。
### POST `/api/source`
创建数据源。
请求示例:
```json
{
"name": "PLC-1",
"protocol": "opcua",
"endpoint": "opc.tcp://127.0.0.1:4840",
"enabled": true
}
```
### PUT `/api/source/{source_id}`
更新数据源,字段均可选。
### DELETE `/api/source/{source_id}`
删除数据源。成功返回 `204 No Content`
### POST `/api/source/{source_id}/reconnect`
手动重连数据源。
### POST `/api/source/{source_id}/browse`
从 OPC UA 数据源浏览节点并写入本地 `node` 表。
### GET `/api/source/{source_id}/node-tree`
获取数据源节点树。
## Point
### GET `/api/point`
分页获取点位列表,同时返回实时监测值。
查询参数:
- `source_id`
- `equipment_id`
- `page`
- `page_size`
### GET `/api/point/{point_id}`
获取单个点位。
### GET `/api/point/{point_id}/history`
获取最近历史样本。历史数据保存在进程内环形缓冲区,服务重启后清空。
查询参数:
- `limit`: 默认 `120`,最大 `1000`
### PUT `/api/point/{point_id}`
更新点位元数据。
可更新字段:
```json
{
"name": "Temperature",
"description": "Room temperature",
"unit": "C",
"tag_id": "uuid",
"equipment_id": "uuid",
"signal_role": "run"
}
```
说明:
- 点位变更设备绑定或信号角色后,会唤醒相关控制单元任务,使控制引擎尽快使用最新映射。
### DELETE `/api/point/{point_id}`
删除单个点位。
说明:
- 删除后会同步通知相关控制单元刷新配置。
### POST `/api/point/batch`
根据节点批量创建点位。
### DELETE `/api/point/batch`
批量删除点位。
说明:
- 删除后会同步通知相关控制单元刷新配置。
### PUT `/api/point/batch/set-equipment`
批量设置点位设备绑定和信号角色。
```json
{
"point_ids": ["uuid1", "uuid2"],
"equipment_id": "uuid",
"signal_role": "run"
}
```
说明:
- 更新前后关联到的控制单元都会被唤醒,避免控制引擎继续使用旧映射。
### PUT `/api/point/batch/set-tags`
批量设置点位标签。
### POST `/api/point/value/batch`
批量写点。
请求头:
- `X-Write-Key: <key>`
请求示例:
```json
{
"items": [
{ "point_id": "uuid", "value": 12.3 }
]
}
```
## Equipment
### GET `/api/equipment`
分页获取设备列表,包含点位数量和已绑定信号角色点。
### GET `/api/equipment/{equipment_id}`
获取单个设备。
### GET `/api/equipment/{equipment_id}/points`
获取设备下所有点位。
### POST `/api/equipment`
创建设备。
说明:
- 如果设备绑定了控制单元,创建成功后会唤醒对应控制单元。
### PUT `/api/equipment/{equipment_id}`
更新设备。
说明:
- 如果设备更换了 `unit_id`、`kind` 或其他控制相关配置,旧单元和新单元都会被唤醒。
### PUT `/api/equipment/batch/set-unit`
批量调整设备所属控制单元。
说明:
- 批量更新前关联到的旧单元,以及更新后关联到的新单元,都会收到唤醒通知。
### DELETE `/api/equipment/{equipment_id}`
删除设备。成功返回 `204 No Content`
说明:
- 删除后会唤醒原所属控制单元。
## Unit
### GET `/api/unit`
分页获取控制单元列表,返回单元基础信息、运行时快照和设备摘要。
### POST `/api/unit`
创建控制单元。
请求示例:
```json
{
"code": "U01",
"name": "1号机组",
"description": null,
"enabled": true,
"run_time_sec": 60,
"stop_time_sec": 30,
"acc_time_sec": 3600,
"bl_time_sec": 10,
"require_manual_ack_after_fault": true
}
```
约束:
- `run_time_sec > 0`
- `stop_time_sec > 0`
- `acc_time_sec > 0`
- `bl_time_sec > 0`
- `acc_time_sec > run_time_sec`
### PUT `/api/unit/{unit_id}`
更新控制单元,字段均可选。
约束:
- 如果更新后涉及时长字段,仍然必须满足上面的全部约束。
### DELETE `/api/unit/{unit_id}`
删除控制单元。成功返回 `204 No Content`
### GET `/api/unit/{unit_id}`
获取单个控制单元及其设备摘要。
### GET `/api/unit/{unit_id}/detail`
获取控制单元完整详情,包括设备和点位列表。
### GET `/api/unit/{unit_id}/runtime`
获取控制单元当前运行时状态。
响应字段:
```json
{
"unit_id": "uuid",
"state": "running",
"auto_enabled": true,
"accumulated_run_sec": 3600000,
"display_acc_sec": 3600000,
"fault_locked": false,
"flt_active": false,
"comm_locked": false,
"manual_ack_required": false
}
```
`state` 枚举:
- `stopped`
- `running`
- `distributor_running`
- `fault_locked`
- `comm_locked`
说明:
- `accumulated_run_sec``display_acc_sec` 单位都是毫秒。
- 运行时状态保存在内存中,服务重启后重置。
## Event
### GET `/api/event`
分页获取系统事件。
查询参数:
- `unit_id`
- `event_type`
- `page`
- `page_size`
常见事件类型:
- `unit.auto_control_started`
- `unit.auto_control_stopped`
- `unit.fault_locked`
- `unit.fault_acked`
- `unit.comm_locked`
- `unit.comm_recovered`
- `equipment.start_command_sent`
- `equipment.stop_command_sent`
## Control
所有控制命令在执行前都会校验:
- 信号质量
- REM 状态
- FLT 状态
- 单元 `auto_enabled`
- 单元 `comm_locked`
- 单元 `fault_locked`
- 单元 `manual_ack_required`
### POST `/api/control/equipment/{equipment_id}/start`
发送设备启动脉冲命令。
### POST `/api/control/equipment/{equipment_id}/stop`
发送设备停止脉冲命令。
### POST `/api/control/unit/{unit_id}/start-auto`
启动单元自动控制。
前置条件:
- 单元已启用
- `fault_locked = false`
- `comm_locked = false`
- `manual_ack_required = false`
成功响应:
```json
{ "ok_msg": "Auto control started", "unit_id": "uuid" }
```
### POST `/api/control/unit/{unit_id}/stop-auto`
停止单元自动控制。
### POST `/api/control/unit/batch-start-auto`
批量启动所有已启用单元的自动控制。
会跳过以下单元:
- 已经 `auto_enabled = true`
- `fault_locked = true`
- `comm_locked = true`
- `manual_ack_required = true`
说明:
- 单个启动和批量启动现在使用相同的阻断规则。
### POST `/api/control/unit/batch-stop-auto`
批量停止自动控制。
### POST `/api/control/unit/{unit_id}/ack-fault`
人工确认故障。
前置条件:
- `fault_locked = true`
- `flt_active = false`
## Tag
### GET `/api/tag`
分页获取标签列表。
### POST `/api/tag`
创建标签。
### GET `/api/tag/{tag_id}`
获取标签下已绑定点位。
### PUT `/api/tag/{tag_id}`
更新标签。
### DELETE `/api/tag/{tag_id}`
删除标签。成功返回 `204 No Content`
## Page
### GET `/api/page`
获取自定义页面列表。
### POST `/api/page`
创建页面。
### GET `/api/page/{page_id}`
获取单个页面。
### PUT `/api/page/{page_id}`
更新页面。
### DELETE `/api/page/{page_id}`
删除页面。成功返回 `204 No Content`
## Log
### GET `/api/logs`
读取日志文件内容。默认读取最新的 `app.log*` 文件。
查询参数:
- `file`: 指定文件名,仅允许 `app.log*`
- `cursor`: 增量读取位置
- `tail_lines`: 默认 `200`,最大 `2000`
- `max_bytes`: 默认 `64KB`,最大 `512KB`
响应示例:
```json
{
"file": "app.log",
"cursor": 204800,
"lines": ["2026-03-25 10:00:00 INFO ..."],
"truncated": false,
"reset": false
}
```
字段说明:
- `truncated = true`: 当前还有未读完内容,可继续用新 `cursor` 拉取
- `reset = true`: 文件被截断或读取起点被重置
### GET `/api/logs/stream`
通过 SSE 推送日志增量。
查询参数:
- `file`
- `cursor`
- `max_bytes`
默认行为:
- 如果没有传 `file`,服务端会始终跟随最新的 `app.log*`
- 如果日志轮转到了新文件,流会自动切换到新文件,并推送一条 `reset = true` 的日志事件
事件示例:
```text
event: log
data: { "file": "app.log.1", "cursor": 1024, "lines": ["..."], "truncated": false, "reset": true }
event: error
data: log stream read failed
```
## WebSocket
### 服务端推送消息
#### `PointNewValue`
点位实时值更新。
#### `EventCreated`
系统事件创建。
#### `UnitRuntimeChanged`
控制单元运行时状态更新。
```json
{
"type": "UnitRuntimeChanged",
"data": {
"unit_id": "uuid",
"state": "running",
"auto_enabled": true,
"fault_locked": false,
"comm_locked": false,
"manual_ack_required": false,
"accumulated_run_sec": 3600000,
"display_acc_sec": 3600000
}
}
```
#### `PointSetValueBatchResult`
批量写点结果回调。
### 客户端消息
#### `auth_write`
```json
{
"type": "auth_write",
"data": { "key": "your-write-key" }
}
```
#### `point_set_value_batch`
```json
{
"type": "point_set_value_batch",
"data": {
"items": [
{ "point_id": "uuid", "value": 12.3 }
]
}
}
```
## 备注
- 控制引擎现在会在每轮单元循环中重新加载设备和角色映射,而不是只在任务启动时加载一次。
- 设备和点位的控制相关配置变更后,会主动唤醒对应单元任务,使新配置尽快生效。
- 日志流默认跟随最新日志文件,适配日志轮转场景。