11 KiB
PLC Control API
本文档基于当前后端代码整理,覆盖 HTTP API、SSE 日志流和 WebSocket 实时消息。
基本信息
- UI:
/ui - HTTP API 前缀:
/api - 公共 WebSocket:
/ws/public - 客户端专属 WebSocket:
/ws/client/{client_id} - 日志 SSE:
/api/logs/stream
通用错误响应
失败时通常返回:
{
"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
创建数据源。
请求示例:
{
"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_idequipment_idpagepage_size
GET /api/point/{point_id}
获取单个点位。
GET /api/point/{point_id}/history
获取最近历史样本。历史数据保存在进程内环形缓冲区,服务重启后清空。
查询参数:
limit: 默认120,最大1000
PUT /api/point/{point_id}
更新点位元数据。
可更新字段:
{
"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
批量设置点位设备绑定和信号角色。
{
"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>
请求示例:
{
"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
创建控制单元。
请求示例:
{
"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 > 0stop_time_sec > 0acc_time_sec > 0bl_time_sec > 0acc_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
获取控制单元当前运行时状态。
响应字段:
{
"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,
"rem_local": false
}
rem_local 说明:
true: 单元下存在设备 REM 信号为本地模式(REM=0,信号质量正常)rem_local = true时,自动控制会被强制停止,且禁止重新启动,直到所有 REM 恢复远程
state 枚举:
stoppedrunningdistributor_runningfault_lockedcomm_locked
说明:
accumulated_run_sec和display_acc_sec单位都是毫秒。- 运行时状态保存在内存中,服务重启后重置。
Event
GET /api/event
分页获取系统事件。
查询参数:
unit_idevent_typepagepage_size
常见事件类型:
unit.auto_control_startedunit.auto_control_stoppedunit.fault_lockedunit.fault_ackedunit.comm_lockedunit.comm_recoveredunit.rem_local— 设备切换为本地模式,自动控制已停止(warn)unit.rem_recovered— 设备切换回远程模式,自动控制需手动重新启动(warn)equipment.start_command_sentequipment.stop_command_sent
Control
所有控制命令在执行前都会校验:
- 信号质量
- REM 状态(REM=0 时拒绝手动指令)
- FLT 状态
- 单元
auto_enabled - 单元
comm_locked - 单元
fault_locked - 单元
manual_ack_required - 单元
rem_local(自动控制启动时额外校验)
POST /api/control/equipment/{equipment_id}/start
发送设备启动脉冲命令。
POST /api/control/equipment/{equipment_id}/stop
发送设备停止脉冲命令。
POST /api/control/unit/{unit_id}/start-auto
启动单元自动控制。
前置条件:
- 单元已启用
fault_locked = falsecomm_locked = falsemanual_ack_required = falserem_local = false(有设备处于本地模式时不允许启动)
成功响应:
{ "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 = truecomm_locked = truemanual_ack_required = truerem_local = true
说明:
- 单个启动和批量启动现在使用相同的阻断规则。
POST /api/control/unit/batch-stop-auto
批量停止自动控制。
POST /api/control/unit/{unit_id}/ack-fault
人工确认故障。
前置条件:
fault_locked = trueflt_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,最大2000max_bytes: 默认64KB,最大512KB
响应示例:
{
"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 推送日志增量。
查询参数:
filecursormax_bytes
默认行为:
- 如果没有传
file,服务端会始终跟随最新的app.log* - 如果日志轮转到了新文件,流会自动切换到新文件,并推送一条
reset = true的日志事件
事件示例:
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
控制单元运行时状态更新。
{
"type": "UnitRuntimeChanged",
"data": {
"unit_id": "uuid",
"state": "running",
"auto_enabled": true,
"fault_locked": false,
"flt_active": false,
"comm_locked": false,
"manual_ack_required": false,
"rem_local": false,
"accumulated_run_sec": 3600000,
"display_acc_sec": 3600000
}
}
PointSetValueBatchResult
批量写点结果回调。
客户端消息
auth_write
{
"type": "auth_write",
"data": { "key": "your-write-key" }
}
point_set_value_batch
{
"type": "point_set_value_batch",
"data": {
"items": [
{ "point_id": "uuid", "value": 12.3 }
]
}
}
备注
- 控制引擎现在会在每轮单元循环中重新加载设备和角色映射,而不是只在任务启动时加载一次。
- 设备和点位的控制相关配置变更后,会主动唤醒对应单元任务,使新配置尽快生效。
- 日志流默认跟随最新日志文件,适配日志轮转场景。
- REM 信号为本地模式(REM=0)时,手动控制指令(start/stop)和自动控制启动均被拒绝;若自动控制正在运行,引擎会立即停止并记录
unit.rem_local事件。REM 恢复远程后记录unit.rem_recovered(warn),自动控制需操作员手动重新启动。