15 KiB
投煤器布料机远程监控与控制功能实现方案
1. 目标
基于当前 plc_control 项目,扩展出面向投煤器与布料机的业务化远程监控与控制能力,满足以下目标:
- 实时监控投煤器、布料机运行状态
- 支持远程手动启停
- 支持投煤器自动定时运行
- 支持投煤累计触发布料机自动运行
- 支持故障锁定、人工复位、通讯异常冻结
- 支持通过配置适配不同现场,不改代码完成项目复用
2. 现有系统能力盘点
当前项目已经具备较好的通用工业采集平台基础:
- OPC UA 数据源接入与自动重连
- 节点浏览、批量建点、点位实时订阅
- 点位批量写入能力
- 设备
equipment模型 - 点位到设备绑定
equipment_id - 点位信号角色字段
signal_role - WebSocket 实时推送
- 前端设备、点位、日志、趋势图基础界面
- 页面配置
page能力 - 进程内事件总线
event.rs
现状更接近“通用点位监控平台”,还不是“投煤器/布料机业务控制系统”。
3. 与需求的差距
需求文档要求的软件能力,当前尚未落地的核心部分如下:
- 缺少“控制单元”概念,无法表达一组投煤器对应一组布料机
- 缺少业务配置模型,无法配置
RunTime、StopTime、AccTime、BLTime - 缺少设备业务类型约束,尚未明确区分投煤器、布料机
- 缺少设备归属单元字段,尚未形成
unit -> equipment -> point的业务链路 - 缺少业务信号角色规范,尚未标准化
REM/RUN/FLT/STA/STP - 缺少自动控制状态机
- 缺少故障锁定与人工确认恢复流程
- 缺少通讯异常冻结与恢复后重同步机制
- 缺少脉冲写入封装,当前只有通用批量写点
- 缺少单元总览、设备详情、控制面板、报警面板等业务界面
- 缺少统一事件持久化与后续报警模型
4. 推荐实现思路
推荐在现有平台上“增量扩展”,而不是重写:
- 保留现有
source/node/point/equipment通用底座 - 新增面向业务控制的配置表和运行态管理
- 将控制逻辑放在 Rust 服务端,复用当前 OPC UA 连接和写点能力
- 前端增加业务页面,不破坏现有通用点位管理页面
- 基于现有
event.rs扩展事件体系,而不是再造一套事件机制
这样做的好处是:
- 现有 OPC UA、点位、设备、WebSocket 基础都能继续复用
- 后续不同现场只需要换设备映射和参数
- 手动调试仍然可以通过现有点位/设备页面完成
- 未来做报警、审计、统计时可以直接复用统一事件体系
5. 命名与模型设计
5.1 命名原则
建议区分“代码命名”和“表命名”:
- 代码模型名保留语义完整性,如
ControlUnit - 数据库表名尽量简洁,如
unit
不建议使用 group 作为表名,原因是语义过泛,后续容易与权限分组、界面分组、标签分组等概念冲突。
5.2 设备分类
继续复用 equipment 表中的 kind 字段,约定:
coal_feeder:投煤器distributor:布料机
5.3 点位角色规范
继续复用 point.signal_role,建议统一枚举值:
- 状态点:
remrunfltiiq - 控制点:
start_cmdstop_cmd - 可选扩展:
estopmode_automode_manualreset_cmd
这样每台设备都可以通过“设备 + 点位角色”完成映射,而不是在代码里写死点名。
5.4 新增 unit 表
建议新增 unit 表,对应代码模型 ControlUnit,表示一个业务控制单元。
建议字段:
idcodenamedescriptionenabledrun_time_secstop_time_secacc_time_secbl_time_secrequire_manual_ack_after_faultcreated_atupdated_at
5.5 设备直接归属 Unit
当前业务前提下,一台设备只属于一个控制单元,不会跨单元复用,因此不建议单独建立关系表。
更合适的方式是直接在 equipment 表新增:
unit_id
这样模型会更简单:
- 一个
unit对多台equipment - 一台
equipment只属于一个unit equipment.kind用于区分coal_feeder和distributor
如果后续现场出现“一台设备可挂多个单元”或“单元内设备编排顺序复杂”的需求,再演进成关系表会更合适。第一阶段不建议设计过重。
5.6 Unit 运行态放内存
unit 运行态不建议优先落数据库,建议由控制引擎保存在内存中。
建议维护的内存运行态字段:
stateaccumulated_run_seccurrent_run_elapsed_seccurrent_stop_elapsed_secdistributor_run_elapsed_secfault_lockedcomm_lockedmanual_ack_requiredlast_tick_at
状态值建议:
stoppedrunningdistributor_runningfault_lockedcomm_locked
原因:
- 这些字段变化频率高,不适合高频写库
- 服务重启后直接恢复旧控制态并不安全
- 更合理的方式是重启后重新读取
REM/RUN/FLT/Q并重建运行态 - 通讯恢复或服务重启后不自动补发控制命令,更符合工业控制安全原则
如后续确实需要“断电恢复上下文”或运行分析,再补充轻量级快照能力即可,但不是第一阶段必须项。
5.7 统一 event 表,预留 alarm 表
建议不要命名为 control_event,而是使用统一的 event 表。
原因:
- 当前不仅有控制事件,后续还会有配置事件、通讯事件、数据源事件
event更适合作为统一审计与业务时间线- 现有
event.rs已经是进程内事件总线,命名保持一致更自然
建议 event 表记录:
- 手动启动/停止
- 自动启动/停止
- 故障锁定
- 人工解除故障锁定
- 通讯异常/恢复
- 数据源创建、更新、删除
- 控制参数变更
- 关键状态切换
关键字段建议:
idevent_typelevelunit_idequipment_idsource_idmessagepayloadcreated_at
同时建议未来单独设计 alarm 表,而不是把报警状态硬塞进 event 表。
原因:
- 报警通常有独立生命周期:触发、确认、恢复、清除
- 报警需要独立字段,如
severity、active、acked、acked_by、acked_at、cleared_at - 把报警硬塞到
event中会让通用事件表越来越臃肿
因此推荐边界是:
event:记录“发生了什么”alarm:记录“需要被告警管理的异常”
第一阶段可以先只落 event 表,alarm 表先在方案中预留,不急着实现。
6. 控制逻辑设计
6.1 手动控制
手动控制前置校验:
REM == 1FLT == 0- 通讯正常
- 未处于故障锁定
- 如有急停点,
ESTOP == 0
控制命令统一走脉冲写入:
- 写入
1 - 延时
200-500ms - 写回
0
服务端需要封装 pulse_write(point_id, high_ms),前端不能直接拼两次写点。
6.2 自动控制状态机
每个 unit 独立维护状态机。
STOPPED
- 累计停止时间
- 若
stop_elapsed >= StopTime,尝试启动投煤器 - 成功后切换到
RUNNING
RUNNING
- 累计运行时间
accumulated_run_sec += delta- 若
run_elapsed >= RunTime,尝试停止投煤器,切换回STOPPED - 若
accumulated_run_sec >= AccTime,进入布料机触发流程
DISTRIBUTOR_RUNNING
- 校验布料机
REM/FLT/通讯 - 启动布料机
- 等待
RUN == 1反馈 - 计时
BLTime - 停止布料机
- 累计时间清零
- 回到
STOPPED或回到自动节拍起点
6.3 故障机制
任意设备检测到 FLT == 1:
- 停止该单元自动控制
- 标记
fault_locked = true - 禁止再次自动发命令
- 发送并持久化关键事件
当 FLT 从 1 -> 0 恢复:
- 不自动解锁
- 标记
manual_ack_required = true - 等待人工在界面点击“解除故障锁定”
6.4 通讯异常机制
当质量位异常或 OPC 连接中断:
- 标记
comm_locked = true - 冻结全部控制动作
- 前端按钮灰化
- 不允许任何自动/手动写入
通讯恢复后:
- 重新读取
REM/RUN/FLT - 重同步运行态
- 不自动补发控制命令
- 发送并持久化恢复事件
- 等待人工操作或下一次自动触发
7. 事件体系设计
7.1 继续复用 src/event.rs
建议不要另起一套业务事件中心,而是在现有 src/event.rs 上扩展。
当前它已经承担两类职责:
- 控制类内部事件分发
- 遥测类高频事件分发
推荐继续保留这个结构:
AppEvent作为统一进程内事件枚举- 高频遥测事件继续走内存和 WebSocket
- 低频且有审计价值的事件选择性落库到
event表
7.2 哪些事件适合落库
适合落库的:
SourceCreateSourceUpdateSourceDelete- 自动控制启动/停止
- 手动启动/停止命令发送
- 故障锁定
- 人工确认恢复
- 通讯异常/恢复
- 参数配置变更
- 单元状态切换
不适合直接落库的:
PointNewValue- 高频实时遥测
- 细碎的内部轮询过程
7.3 推荐扩展方向
建议在 AppEvent 中逐步增加业务事件,例如:
AutoControlStartedAutoControlStoppedEquipmentStartCommandSentEquipmentStopCommandSentFaultLockedFaultAckedCommLockedCommRecoveredUnitStateChanged
这样后续无论是写日志、落库、推送 WebSocket、做报警触发,都可以基于同一个事件入口。
8. 后端改造方案
8.1 新增模块
建议新增:
src/handler/control.rssrc/service/control.rssrc/control/engine.rssrc/control/runtime.rssrc/control/validator.rs
职责划分:
handler:HTTP 接口service:数据库读写control/engine:状态机与调度control/runtime:内存运行态缓存与同步control/validator:控制前置校验
8.2 新增接口
建议新增接口:
GET /api/control/unitPOST /api/control/unitPUT /api/control/unit/{id}GET /api/control/unit/{id}POST /api/control/unit/{id}/start-autoPOST /api/control/unit/{id}/stop-autoPOST /api/control/unit/{id}/ack-faultPOST /api/control/equipment/{id}/startPOST /api/control/equipment/{id}/stopGET /api/events
说明:
- 设备手动控制必须走业务接口,不建议继续直接暴露给页面做原始点位写入
- 原
/api/point/value/batch保留给调试或底层工具能力 - 事件查询接口可以直接面向统一
event表
8.3 控制引擎运行方式
建议服务启动后增加一个后台任务:
- 每
500ms或1s扫描所有启用的unit - 从内存读取运行态缓存
- 从当前点位监控数据中取
REM/RUN/FLT/Q - 驱动状态机执行
控制引擎不要直接查 OPC,应复用当前 connection_manager 已维护的实时点值。
8.4 关键复用点
可直接复用当前已有能力:
connection_manager的点位实时缓存get_point_monitor_data_read_guard- 批量写点能力
- WebSocket 实时推送
event.rs的统一事件入口unit_id + equipment.kind + point.signal_role的业务映射关系
9. 前端改造方案
建议在现有通用页面之外新增业务页面,避免混杂。
9.1 新增页面
- 单元总览页
- 单元详情页
- 设备控制面板
- 事件记录页
- 报警页
- 参数配置页
9.2 单元总览页内容
每个 unit 展示:
- 单元名称
- 自动/手动状态
- 当前状态机状态
- 投煤器运行状态
- 布料机运行状态
- 当前累计运行时间
- 故障锁定状态
- 通讯状态
并提供按钮:
- 启动自动
- 停止自动
- 故障确认/解除锁定
9.3 设备控制页内容
针对单台投煤器/布料机提供:
- REM/RUN/FLT/Q/II 实时显示
- 启动按钮
- 停止按钮
- 通讯异常、故障锁定提示
- 最近事件
9.4 趋势、事件与报警
复用已有趋势图能力:
- 电流
II趋势 - 运行状态变化曲线
- 事件时间线
后续报警页面基于独立 alarm 表实现:
- 当前活动报警
- 已确认报警
- 已恢复报警
- 报警确认操作
10. 分阶段实施建议
第一阶段:最小可用版
目标:先让系统具备业务闭环,但不追求复杂页面。
内容:
- 新增
unit表 - 为
equipment增加unit_id - 约定设备
kind和点位signal_role - 新增手动控制接口
- 实现脉冲写入
- 实现故障锁定与通讯冻结
- 实现自动控制状态机
- 基于
event.rs落统一event表 - 前端增加一个“控制单元”面板和事件列表
交付后即可验证:
- 单台投煤器启停
- 单元级自动启停
- 累计触发布料机运行
- 故障恢复后人工确认
- 关键操作和状态切换可追溯
第二阶段:增强版
内容:
- 单元总览页
- 单元详情页
- 参数在线编辑
- 更丰富的趋势图
- WebSocket 业务事件推送
- 报警规则与
alarm表 - 报警确认与恢复流程
第三阶段:现场适配版
内容:
- 导入导出配置
- 项目模板
- 配置校验工具
- 启停联锁自检
- 操作权限控制
11. 建议优先落地顺序
从当前代码基础出发,建议按下面顺序开发:
- 补齐业务数据模型和数据库迁移
- 新增
unit表并为equipment增加unit_id - 规范
equipment.kind与point.signal_role - 实现服务端脉冲写入能力
- 实现手动控制接口
- 实现
unit自动控制状态机 - 扩展
event.rs并实现统一event表持久化 - 实现故障锁定、通讯冻结、人工确认
- 增加前端业务页面
- 第二阶段再引入独立
alarm表
12. 对当前代码的具体落点
基于现有代码,建议主要改动点如下:
- src/model.rs
- 增加
ControlUnit模型 - 为
Equipment增加unit_id - 后续增加
EventRecord、AlarmRecord模型
- 增加
- src/event.rs
- 扩展
AppEvent业务事件类型 - 增加低频关键事件的持久化逻辑
- 扩展
- src/main.rs
- 注册控制相关路由
- 启动控制引擎后台任务
- src/handler/point.rs
- 保留底层写点接口,不直接承载业务控制
- src/handler/equipment.rs
- 继续作为设备基础资料管理
- web/index.html
- 增加业务控制页面入口或独立面板
- web/js/app.js
- 增加控制单元页面事件绑定
13. 本次结论
当前项目不需要推倒重来,可以直接演进成投煤器与布料机远程监控控制系统。
最合理的路径是:
- 以现有 OPC UA 与点位平台为底座
- 数据库使用简洁表名
unit、event - 代码层保留语义化命名,如
ControlUnit、AppEvent - 在
equipment上直接增加unit_id - 在服务端以内存运行态实现状态机和脉冲控制
- 在现有 src/event.rs 上扩展统一事件体系
- 第一阶段先做统一
event,第二阶段再拆分独立alarm
如果进入下一步开发,建议先做“第一阶段最小可用版”。