01 · 这套软件是怎么跑起来的

先说这软件是干什么的

工厂里有台设备(锅炉、注塑机、水处理线),上面一堆传感器和阀门。要让操作工看得见、点得动,就得有个触摸屏界面 —— 这就是 HMI(Human Machine Interface,人机界面)。

以前做这种界面要一行行写代码。鲲鹏恒控让你拖控件:从图元库拖一个按钮、一个仪表盘到画布上,设置它绑哪个点位,界面就做好了,一键编译交给现场跑。

组态 = "拖拖拉拉把界面配出来",不用写代码。这是工控行业的行话。

两个阶段:组态期 和 运行期

这是理解整套代码最重要的一个区分,后面每一章都建立在这上面。

组态期(做工程的时候) 运行期(工程在现场跑的时候)
谁在用 工程师坐在电脑前 操作工站在触摸屏前
在干什么 拖控件、连设备、配点表、写脚本 看界面、点按钮、读数据
数据在哪 磁盘上的工程文件 内存里的实时库
对应的程序 Hmi.Shell + Hmi.Automation Hmi.Backend + Hmi.RuntimeCore.Host

同一个工程,两个阶段共用同一份数据模型。 这是这套软件的设计要点 —— 组态期你在编辑器里看到的预览,和运行期现场看到的,是同一套渲染器画出来的,所以所见即所得。

一张图看懂数据怎么流动

   ┌──────────────┐   改    ┌───────────────┐
   │   组态器界面   │───────>│   工程文件      │
   │ (WPF + 网页)  │        │ project.json   │
   │  Hmi.Shell    │<───────│ tags.json      │
   └──────────────┘   读    │ *.screen.json  │
                            └───────┬───────┘
                                    │ 运行期加载
                                    v
   ┌────────────────────────────────────────────────┐
   │              运行内核(一个进程)                  │
   │                                                │
   │  ┌──────────┐   写    ┌───────────┐            │
   │  │  采集循环  │───────>│  实时库     │            │
   │  │  Hmi.Drivers│      │  Hmi.Core  │            │
   │  └─────┬─────┘       └─────┬─────┘            │
   │        │                   │ 变化分发          │
   │        │             ┌─────┴─────┬──────────┐  │
   │        │             v           v          v  │
   │        │        ┌────────┐ ┌────────┐ ┌───────┐│
   │        │        │ 报警引擎 │ │ 历史库  │ │ 界面  ││
   │        │        └────────┘ └────────┘ └───────┘│
   └────────┼───────────────────────────────────────┘
            │
            v
      ┌───────────┐
      │ PLC / 现场 │   Modbus、西门子 S7、三菱、欧姆龙…
      │   设备     │
      └───────────┘

读这张图只要记住四句话:

  1. 组态器改的是磁盘上的工程文件,不碰运行态。
  2. 运行内核启动时把工程文件读进内存,变成实时库里的点。
  3. 采集循环不停地从 PLC 读数据,写进实时库。
  4. 实时库一有变化就分发出去 —— 界面刷新、报警判定、历史落库都靠这条线。

后端在这套东西里的位置

本仓库 src/ 下全是后端,分四层(完整清单见程序集速查表):

层 干什么 有哪些
内核层 数据放在哪 Hmi.Core
领域库层 各管一摊的专业能力 Hmi.Project Hmi.Drivers Hmi.Scripting Hmi.Historian Hmi.Alarms Hmi.Security
组合层 把领域库拼成能用的整体 Hmi.Automation Hmi.Backend Hmi.ScriptRuntime
宿主层 把上面这些跑起来 Hmi.Shell Hmi.HostBridge Hmi.Mcp.Host Hmi.RuntimeCore.Host Hmi.Supervisor

前端不在 src/ 里 —— 前端是一堆纯 HTML/JS 文件,跑在 WebView2 里,通过 Hmi.HostBridge 和后端对话(见第 17 章)。

一个具体例子:点一下按钮,背后发生了什么

现场界面上有个"启动"按钮,操作工按下去:

1. 前端捕获 click 事件                    ← 纯 JS
2. 前端 postMessage 发一条 RPC 给后端
3. Hmi.HostBridge 收到,路由到对应处理函数
4. 处理函数把值写进实时库                  ← Hmi.Core
5. 采集循环发现"有值要下发",通过驱动写给 PLC ← Hmi.Drivers
6. PLC 里的电机真的转起来了
7. 电机状态回读 → 写回实时库 → 分发 → 界面指示灯变绿

整条链路涉及 4 个程序集。本书后面的章节就是逐个拆开讲它们。

⚠ 注意第 4 步和第 5 步的区别:往实时库写值只是"改内存",真正下发到 PLC 是采集循环干的。 所以遇到"值写进去了但设备没动",要先查采集循环有没有在跑。

小结

  • 记住组态期 / 运行期这个区分,后面所有章节都建立在这上面
  • 数据流向:工程文件 → 实时库 → 分发 → 界面/报警/历史,另一头连着 PLC
  • 后端四层:内核 → 领域库 → 组合 → 宿主

下一步:第 02 章 名词表先把术语过一遍,或者直接看第 03 章按你的目标选路线。