869 lines
16 KiB
Markdown
869 lines
16 KiB
Markdown
# PLC Control 接口说明
|
||
|
||
本文档基于当前服务端路由与处理器代码整理,覆盖 HTTP API 和 WebSocket 实时消息。
|
||
|
||
## 基本信息
|
||
|
||
- 服务端默认提供静态 UI:`/ui`
|
||
- HTTP API 前缀:`/api`
|
||
- 公共实时 WebSocket:`/ws/public`
|
||
- 客户端专属 WebSocket:`/ws/client/{client_id}`
|
||
|
||
## 通用错误响应
|
||
|
||
接口失败时通常返回:
|
||
|
||
```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`
|
||
|
||
获取所有已启用数据源及其连接状态。
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "uuid",
|
||
"name": "PLC-1",
|
||
"protocol": "opcua",
|
||
"endpoint": "opc.tcp://127.0.0.1:4840",
|
||
"security_policy": null,
|
||
"security_mode": null,
|
||
"enabled": true,
|
||
"created_at": "2026-03-20 10:00:00.000",
|
||
"updated_at": "2026-03-20 10:00:00.000",
|
||
"is_connected": true,
|
||
"last_error": null,
|
||
"last_time": "2026-03-20 10:05:00.000"
|
||
}
|
||
]
|
||
```
|
||
|
||
### POST `/api/source`
|
||
|
||
创建数据源。
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{
|
||
"name": "PLC-1",
|
||
"endpoint": "opc.tcp://127.0.0.1:4840",
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{ "id": "uuid" }
|
||
```
|
||
|
||
### PUT `/api/source/{source_id}`
|
||
|
||
更新数据源。请求体字段均可选:
|
||
|
||
```json
|
||
{
|
||
"name": "PLC-1",
|
||
"endpoint": "opc.tcp://127.0.0.1:4840",
|
||
"enabled": true,
|
||
"security_policy": "None",
|
||
"security_mode": "None",
|
||
"username": "user",
|
||
"password": "pass"
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/source/{source_id}`
|
||
|
||
删除数据源。成功响应:`204 No Content`
|
||
|
||
### POST `/api/source/{source_id}/reconnect`
|
||
|
||
手动重连指定数据源。
|
||
|
||
```json
|
||
{ "ok_msg": "Source reconnected successfully" }
|
||
```
|
||
|
||
### POST `/api/source/{source_id}/browse`
|
||
|
||
从 OPC UA 源浏览节点并写入本地 `node` 表。
|
||
|
||
```json
|
||
{ "ok_msg": "Browse completed", "total_nodes": 123 }
|
||
```
|
||
|
||
### GET `/api/source/{source_id}/node-tree`
|
||
|
||
获取指定数据源的节点树(含 `children` 递归嵌套)。
|
||
|
||
---
|
||
|
||
## Point
|
||
|
||
### GET `/api/point`
|
||
|
||
分页获取点位列表,同时返回实时监测值。
|
||
|
||
查询参数:
|
||
|
||
- `source_id`:可选,按数据源过滤
|
||
- `equipment_id`:可选,按设备过滤
|
||
- `page`:页码
|
||
- `page_size`:每页条数(`-1` 表示全量)
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"data": [
|
||
{
|
||
"point": {
|
||
"id": "uuid",
|
||
"node_id": "uuid",
|
||
"name": "Temperature",
|
||
"equipment_id": "uuid",
|
||
"signal_role": "run",
|
||
"created_at": "2026-03-20 10:00:00.000",
|
||
"updated_at": "2026-03-20 10:00:00.000"
|
||
},
|
||
"point_monitor": {
|
||
"point_id": "uuid",
|
||
"timestamp": "2026-03-20 10:05:00.000",
|
||
"quality": "good",
|
||
"value": 12.3,
|
||
"value_type": "float",
|
||
"value_text": "12.3"
|
||
}
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"page_size": 100
|
||
}
|
||
```
|
||
|
||
### GET `/api/point/{point_id}`
|
||
|
||
获取单个点位。
|
||
|
||
### GET `/api/point/{point_id}/history`
|
||
|
||
获取点位最近历史样本(进程内存环形缓冲,重启后清空)。
|
||
|
||
查询参数:`limit`(可选,默认 `120`,最大 `1000`)
|
||
|
||
```json
|
||
[
|
||
{
|
||
"timestamp": "2026-03-20 10:05:00.000",
|
||
"quality": "good",
|
||
"value": 12.3,
|
||
"value_text": "12.3",
|
||
"value_number": 12.3
|
||
}
|
||
]
|
||
```
|
||
|
||
### PUT `/api/point/{point_id}`
|
||
|
||
更新点位元数据,字段均可选:
|
||
|
||
```json
|
||
{
|
||
"name": "Temperature",
|
||
"description": "Room temperature",
|
||
"unit": "°C",
|
||
"equipment_id": "uuid",
|
||
"signal_role": "run"
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/point/{point_id}`
|
||
|
||
删除单个点位。
|
||
|
||
### POST `/api/point/batch`
|
||
|
||
根据节点批量创建点位。
|
||
|
||
```json
|
||
{ "node_ids": ["uuid1", "uuid2"] }
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success_count": 2,
|
||
"failed_count": 0,
|
||
"failed_node_ids": [],
|
||
"created_point_ids": ["uuid3", "uuid4"]
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/point/batch`
|
||
|
||
批量删除点位。
|
||
|
||
```json
|
||
{ "point_ids": ["uuid1", "uuid2"] }
|
||
```
|
||
|
||
### PUT `/api/point/batch/set-equipment`
|
||
|
||
批量设置点位的设备绑定和信号角色。
|
||
|
||
```json
|
||
{
|
||
"point_ids": ["uuid1", "uuid2"],
|
||
"equipment_id": "uuid",
|
||
"signal_role": "run"
|
||
}
|
||
```
|
||
|
||
### PUT `/api/point/batch/set-tags`
|
||
|
||
批量设置点位的标签(`tag_id`,传 `null` 可清除绑定)。
|
||
|
||
```json
|
||
{
|
||
"point_ids": ["uuid1", "uuid2"],
|
||
"tag_id": "uuid"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{ "ok_msg": "Point tags updated successfully", "updated_count": 2 }
|
||
```
|
||
|
||
### POST `/api/point/value/batch`
|
||
|
||
批量写点。
|
||
|
||
请求头:`X-Write-Key: <key>`
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{ "point_id": "uuid", "value": 12.3 }
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Equipment
|
||
|
||
### GET `/api/equipment`
|
||
|
||
分页获取设备列表,包含每台设备绑定的点位数量。
|
||
|
||
查询参数:`page`、`page_size`(`-1` 全量)、`keyword`(可选,按 code/name 模糊搜索)
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"data": [
|
||
{
|
||
"id": "uuid",
|
||
"unit_id": "uuid",
|
||
"code": "E01",
|
||
"name": "投煤器1",
|
||
"kind": "coal_feeder",
|
||
"description": null,
|
||
"created_at": "2026-03-20 10:00:00.000",
|
||
"updated_at": "2026-03-20 10:00:00.000",
|
||
"point_count": 5
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"page_size": 20
|
||
}
|
||
```
|
||
|
||
### POST `/api/equipment`
|
||
|
||
创建设备。
|
||
|
||
```json
|
||
{
|
||
"unit_id": "uuid",
|
||
"code": "E01",
|
||
"name": "投煤器1",
|
||
"kind": "coal_feeder",
|
||
"description": null
|
||
}
|
||
```
|
||
|
||
响应:`201 Created`
|
||
|
||
```json
|
||
{ "id": "uuid", "ok_msg": "Equipment created successfully" }
|
||
```
|
||
|
||
### PUT `/api/equipment/{equipment_id}`
|
||
|
||
更新设备,字段均可选:
|
||
|
||
```json
|
||
{
|
||
"unit_id": "uuid",
|
||
"code": "E01",
|
||
"name": "投煤器1",
|
||
"kind": "coal_feeder",
|
||
"description": null
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/equipment/{equipment_id}`
|
||
|
||
删除设备。成功响应:`204 No Content`
|
||
|
||
### GET `/api/equipment/{equipment_id}/points`
|
||
|
||
获取指定设备下所有绑定点位。
|
||
|
||
### PUT `/api/equipment/batch/set-unit`
|
||
|
||
批量将设备绑定到控制单元。
|
||
|
||
```json
|
||
{
|
||
"equipment_ids": ["uuid1", "uuid2"],
|
||
"unit_id": "uuid"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Unit(控制单元)
|
||
|
||
### GET `/api/unit`
|
||
|
||
分页获取控制单元列表。
|
||
|
||
查询参数:`page`、`page_size`、`keyword`(可选)
|
||
|
||
响应字段包含:`id`、`code`、`name`、`enabled`、`run_time_sec`、`stop_time_sec`、`acc_time_sec`、`bl_time_sec`、`require_manual_ack_after_fault`
|
||
|
||
### 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
|
||
}
|
||
```
|
||
|
||
响应:`201 Created`
|
||
|
||
```json
|
||
{ "id": "uuid", "ok_msg": "Unit created successfully" }
|
||
```
|
||
|
||
### GET `/api/unit/{unit_id}`
|
||
|
||
获取单个控制单元。
|
||
|
||
### PUT `/api/unit/{unit_id}`
|
||
|
||
更新控制单元,字段均可选。
|
||
|
||
### DELETE `/api/unit/{unit_id}`
|
||
|
||
删除控制单元。成功响应:`204 No Content`
|
||
|
||
### GET `/api/unit/{unit_id}/runtime`
|
||
|
||
获取控制单元的当前运行时状态(内存中,不持久化)。
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"unit_id": "uuid",
|
||
"state": "running",
|
||
"auto_enabled": true,
|
||
"accumulated_run_sec": 3600000,
|
||
"current_run_elapsed_sec": 60000,
|
||
"current_stop_elapsed_sec": 0,
|
||
"distributor_run_elapsed_sec": 0,
|
||
"fault_locked": false,
|
||
"flt_active": false,
|
||
"comm_locked": false,
|
||
"manual_ack_required": false,
|
||
"last_tick_at": "2026-03-25 10:00:00.000"
|
||
}
|
||
```
|
||
|
||
`state` 枚举值:`stopped` / `running` / `distributor_running` / `fault_locked` / `comm_locked`
|
||
|
||
注意:时间字段单位为毫秒(ms)。
|
||
|
||
### GET `/api/unit/{unit_id}/detail`
|
||
|
||
获取控制单元及其下所有设备和点位的完整嵌套结构。
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"code": "U01",
|
||
"name": "1号机组",
|
||
"enabled": true,
|
||
"equipments": [
|
||
{
|
||
"id": "uuid",
|
||
"code": "E01",
|
||
"name": "投煤器1",
|
||
"kind": "coal_feeder",
|
||
"points": [
|
||
{
|
||
"id": "uuid",
|
||
"name": "启动命令",
|
||
"signal_role": "start_cmd",
|
||
"equipment_id": "uuid"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Event(系统事件)
|
||
|
||
### GET `/api/event`
|
||
|
||
分页获取系统控制事件记录。
|
||
|
||
查询参数:
|
||
|
||
- `unit_id`:可选,按控制单元过滤
|
||
- `event_type`:可选,按事件类型过滤
|
||
- `page`、`page_size`
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"data": [
|
||
{
|
||
"id": "uuid",
|
||
"event_type": "equipment.start_command_sent",
|
||
"level": "info",
|
||
"unit_id": "uuid",
|
||
"equipment_id": "uuid",
|
||
"message": "Start command sent to equipment ...",
|
||
"payload": {},
|
||
"created_at": "2026-03-25 10:00:00.000"
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"page_size": 20
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Control(控制命令)
|
||
|
||
所有控制命令在执行前会校验:信号质量、REM 状态、FLT 状态、单元通讯锁、单元故障锁。
|
||
|
||
### POST `/api/control/equipment/{equipment_id}/start`
|
||
|
||
向设备发送启动脉冲命令(写 HIGH → 延迟 300ms → 写 LOW)。
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"ok_msg": "Equipment start command sent",
|
||
"equipment_id": "uuid",
|
||
"unit_id": "uuid",
|
||
"command_role": "start_cmd",
|
||
"command_point_id": "uuid",
|
||
"pulse_ms": 300
|
||
}
|
||
```
|
||
|
||
失败(设备未处于可启动状态)返回 `403 Forbidden`。
|
||
|
||
### POST `/api/control/equipment/{equipment_id}/stop`
|
||
|
||
向设备发送停止脉冲命令。响应结构同上。
|
||
|
||
### POST `/api/control/unit/{unit_id}/start-auto`
|
||
|
||
启动指定控制单元的自动控制循环。单元须已启用(`enabled = true`)。
|
||
|
||
```json
|
||
{ "ok_msg": "Auto control started", "unit_id": "uuid" }
|
||
```
|
||
|
||
### POST `/api/control/unit/{unit_id}/stop-auto`
|
||
|
||
停止自动控制循环。设备当前状态保持不变,不会自动停机。
|
||
|
||
```json
|
||
{ "ok_msg": "Auto control stopped", "unit_id": "uuid" }
|
||
```
|
||
|
||
### POST `/api/control/unit/batch-start-auto`
|
||
|
||
批量启动所有已启用(`enabled = true`)控制单元的自动控制。已在运行、故障锁或通讯锁的单元将跳过。
|
||
|
||
```json
|
||
{
|
||
"started": ["uuid1", "uuid2"],
|
||
"skipped": ["uuid3"]
|
||
}
|
||
```
|
||
|
||
### POST `/api/control/unit/batch-stop-auto`
|
||
|
||
批量停止所有自动控制中的控制单元。
|
||
|
||
```json
|
||
{ "stopped": ["uuid1", "uuid2"] }
|
||
```
|
||
|
||
### POST `/api/control/unit/{unit_id}/ack-fault`
|
||
|
||
人工确认故障,解除故障锁定。要求:`fault_locked = true` 且 `flt_active = false`(故障信号已消失)。
|
||
|
||
```json
|
||
{ "ok_msg": "Fault acknowledged", "unit_id": "uuid" }
|
||
```
|
||
|
||
---
|
||
|
||
## Tag(标签)
|
||
|
||
### GET `/api/tag`
|
||
|
||
分页获取标签列表。
|
||
|
||
查询参数:`page`、`page_size`
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"data": [
|
||
{
|
||
"id": "uuid",
|
||
"name": "主蒸汽",
|
||
"description": null,
|
||
"created_at": "2026-03-20 10:00:00.000",
|
||
"updated_at": "2026-03-20 10:00:00.000"
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"page_size": 20
|
||
}
|
||
```
|
||
|
||
### POST `/api/tag`
|
||
|
||
创建标签,可同时绑定点位。
|
||
|
||
```json
|
||
{
|
||
"name": "主蒸汽",
|
||
"description": null,
|
||
"point_ids": ["uuid1", "uuid2"]
|
||
}
|
||
```
|
||
|
||
响应:`201 Created`
|
||
|
||
```json
|
||
{ "id": "uuid", "ok_msg": "Tag created successfully" }
|
||
```
|
||
|
||
### GET `/api/tag/{tag_id}`
|
||
|
||
获取标签下所有绑定点位。
|
||
|
||
响应:点位对象数组。
|
||
|
||
### PUT `/api/tag/{tag_id}`
|
||
|
||
更新标签,字段均可选(`point_ids` 传入时全量替换绑定关系):
|
||
|
||
```json
|
||
{
|
||
"name": "主蒸汽",
|
||
"description": "描述",
|
||
"point_ids": ["uuid1"]
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/tag/{tag_id}`
|
||
|
||
删除标签。成功响应:`204 No Content`
|
||
|
||
---
|
||
|
||
## Page(自定义页面)
|
||
|
||
### GET `/api/page`
|
||
|
||
获取所有页面,按 `created_at` 排序。
|
||
|
||
查询参数:`name`(可选,模糊搜索)
|
||
|
||
响应:Page 对象数组。
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "uuid",
|
||
"name": "总览",
|
||
"data": { "slot_key": "point-uuid" },
|
||
"created_at": "2026-03-20 10:00:00.000",
|
||
"updated_at": "2026-03-20 10:00:00.000"
|
||
}
|
||
]
|
||
```
|
||
|
||
`data` 为 `{ slot_key: point_id }` 映射,用于页面布局与点位绑定。
|
||
|
||
### POST `/api/page`
|
||
|
||
创建页面。
|
||
|
||
```json
|
||
{
|
||
"name": "总览",
|
||
"data": { "slot_a": "uuid1", "slot_b": "uuid2" }
|
||
}
|
||
```
|
||
|
||
响应:`201 Created`
|
||
|
||
```json
|
||
{ "id": "uuid", "ok_msg": "Page created successfully" }
|
||
```
|
||
|
||
### GET `/api/page/{page_id}`
|
||
|
||
获取单个页面。
|
||
|
||
### PUT `/api/page/{page_id}`
|
||
|
||
更新页面,字段均可选:
|
||
|
||
```json
|
||
{
|
||
"name": "总览",
|
||
"data": { "slot_a": "uuid1" }
|
||
}
|
||
```
|
||
|
||
### DELETE `/api/page/{page_id}`
|
||
|
||
删除页面。成功响应:`204 No Content`
|
||
|
||
---
|
||
|
||
## Log(运行日志)
|
||
|
||
### GET `/api/logs`
|
||
|
||
读取服务端日志文件内容(默认取最新 `app.log*` 文件尾部 200 行)。
|
||
|
||
查询参数:
|
||
|
||
- `file`:可选,指定文件名(仅允许 `app.log` 前缀)
|
||
- `cursor`:可选,上次返回的字节偏移量;传入时增量读取 cursor 之后的内容
|
||
- `tail_lines`:可选,不传 cursor 时返回的尾部行数(默认 200,最大 2000)
|
||
- `max_bytes`:可选,单次最多返回字节数(默认 64 KB,最大 512 KB)
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"file": "app.log",
|
||
"cursor": 204800,
|
||
"lines": ["2026-03-25 10:00:00 INFO ..."],
|
||
"truncated": false,
|
||
"reset": false
|
||
}
|
||
```
|
||
|
||
- `truncated`:`true` 表示本次未读完,可用新 cursor 继续请求
|
||
- `reset`:`true` 表示文件已轮转(cursor > 文件大小),已从头读取
|
||
|
||
### GET `/api/logs/stream`
|
||
|
||
以 **SSE**(Server-Sent Events)流式推送日志增量,每 800 ms 检查一次文件变化。
|
||
|
||
查询参数:`file`、`cursor`(可选,默认从文件末尾开始)、`max_bytes`(默认 32 KB)
|
||
|
||
事件格式:
|
||
|
||
```
|
||
event: log
|
||
data: { "file": "app.log", "cursor": 204800, "lines": [...], "truncated": false, "reset": false }
|
||
|
||
event: error
|
||
data: log stream read failed
|
||
```
|
||
|
||
---
|
||
|
||
## WebSocket
|
||
|
||
### 连接地址
|
||
|
||
- 公共广播:`/ws/public`
|
||
- 客户端专属:`/ws/client/{client_id}`
|
||
|
||
### 服务端主动推送消息
|
||
|
||
#### `PointNewValue`
|
||
|
||
点位实时值更新:
|
||
|
||
```json
|
||
{
|
||
"type": "PointNewValue",
|
||
"data": {
|
||
"point_id": "uuid",
|
||
"timestamp": "2026-03-20 10:05:00.000",
|
||
"quality": "good",
|
||
"value": 12.3,
|
||
"value_type": "float",
|
||
"value_text": "12.3"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `EventCreated`
|
||
|
||
系统事件创建(控制操作、故障、状态变更等):
|
||
|
||
```json
|
||
{
|
||
"type": "EventCreated",
|
||
"data": {
|
||
"id": "uuid",
|
||
"event_type": "equipment.start_command_sent",
|
||
"level": "info",
|
||
"unit_id": "uuid",
|
||
"equipment_id": "uuid",
|
||
"message": "...",
|
||
"created_at": "2026-03-25 10:00:00.000"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `UnitRuntimeChanged`
|
||
|
||
控制单元运行时状态变更(每 500ms tick 后广播):
|
||
|
||
```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
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `PointSetValueBatchResult`
|
||
|
||
批量写点结果回调:
|
||
|
||
```json
|
||
{
|
||
"type": "PointSetValueBatchResult",
|
||
"data": {
|
||
"success": true,
|
||
"err_msg": null,
|
||
"success_count": 1,
|
||
"failed_count": 0,
|
||
"results": []
|
||
}
|
||
}
|
||
```
|
||
|
||
### 客户端发送消息
|
||
|
||
#### 写权限认证
|
||
|
||
```json
|
||
{
|
||
"type": "auth_write",
|
||
"data": { "key": "your-write-key" }
|
||
}
|
||
```
|
||
|
||
#### 批量写点
|
||
|
||
```json
|
||
{
|
||
"type": "point_set_value_batch",
|
||
"data": {
|
||
"items": [
|
||
{ "point_id": "uuid", "value": 12.3 }
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 备注
|
||
|
||
- 运行时状态(`/runtime`)存储在内存中,服务重启后重置。
|
||
- 历史曲线数据(`/history`)同样是内存环形缓冲,重启后清空。
|
||
- 控制单元时间配置字段(`run_time_sec` 等)单位为秒,运行时 elapsed 字段单位为毫秒。
|
||
- 自动控制启动后,状态机以 500ms 为周期运行,实时状态通过 WebSocket `UnitRuntimeChanged` 推送。
|