ARTICLE · 1017723
又一个WPF上位机模版,终于有人做了背压设计.
做上位机采集的时候,真正麻烦的是画界面。
设备多了之后,轮询调度、队列缓冲和UI刷新,任何一个地方处理不好,都会出现问题。
最近我在 GitHub 刷到一个 WPF 上位机,有点特别分享给大家。
它叫edge-acq,是一个把协议采集和界面分开的一套通用上位机。

可以接入串口、TCP、Modbus TCP/RTU,多台设备采集到的数据都进入有界队列中。
界面只负责从队列里取数据,不管底层用的是什么协议。
协议可以替换,UI 不用跟着改。
在HostStation.Protocols中,Serial、TCP负责传输,Modbus负责协议适配。

协议部分做了分层。
RTU 的 CRC、TCP 的 MBAP 头都已封装完毕。

采集也分成了两层。
AcquisitionSession 负责一个设备,AcquisitionHub 负责对多个 Session 进行统一管理。

协议层使用统一的接口IProtocolAdapter来实现:

所以后面要扩展 OPC UA、MQTT,也可以继续按这个接口增加适配器,上层拿到的还是统一的 TagSample。
多设备采集还有一套背压机制。
BoundedSampleQueue 有三种策略:

曲线用 DropOldest,队列满了就丢最旧的数据,优先保证画面是最新的。
告警用Block,宁可让生产端慢一些,也不主动丢样本。
压测的时候用 DropNewest,可以方便看到在高负载下到底丢了多少数据。
项目还准备了三种不同的配置:

也就是:
曲线队列有2048个,单个设备最多可以达到200个采样/秒。
告警队列有4096条,最大采样率为50个/秒。
压力测试可以达到每秒 1000 个样本。
丢掉多少条数据,也会直接记录:

后面做压测或者排查卡顿时,直接看 Dropped 就行。
每台设备单独限流,不会让一台热设备占满整个队列。
如果某台设备每秒灌入 1000 个采样,共享队列很快就会被塞满。
DeviceRateLimiter 给每个会话单独设置令牌桶,超过限制后就把速度压下来,其他设备的数据仍然可以正常进入队列。
这种情况在现场很常见:一台设备不断上报,最后把其他设备全堵住。
按设备限流之后,就不用担心冷设备一直拿不到处理机会。
设备断线后,会按照指数退避自动重连。
RTU 被拔线、TCP 网络中断都是常事。
连接失败后,重试间隔会从几秒开始逐渐增加,不会一直在后台空转。
断线期间再配合有界队列,内存也不会不断往上涨。
对于长期无人值守的采集站来说,设备自己断线重连,不需要安排人守着,这一点还是很实用的。
界面使用 MVVM,曲线由程序自己绘制。
设备、曲线和告警分成三个 Tab,数据都来自 Core 的采集队列。
工具栏只有启动和停止两个主要操作,用起来并不复杂。
选好通讯方式,点击启动之后,设备就会进入监控状态,当前的采集情况也会直接显示在界面上。

采集到的数据可以切到曲线页查看。曲线使用 Canvas 和 Polyline 绘制,没有引入第三方图表库,数据变化看起来也比较直观。

如果设备掉线,或者采集值超过 Hi/Lo 限值,界面会根据 Quality 触发告警,对应的信息可以直接在告警页里查看。

ModbusAdapter 还带有仿真寄存器,像 A.HR40001 这样的点位,不接真实硬件也能演示。
手头没有 PLC,一样可以先把界面跑起来看看。
目前项目还处于早期阶段,但是工程配置已经比较齐全了。
Linux 负责运行 Core 和协议测试,Windows 负责编译界面,publish 脚本也可以直接生成 Release 版本。
本地运行也很容易
想试一下的话,clone 到本地。
git clone https://github.com/agentthink/edge-acq.git再执行 build 就行。
dotnet build src/HostStation.App/HostStation.App.csproj -c Release打开软件,选择好串口或者TCP,点击启动采集,曲线和告警就会开始更新。
如果要更深入了解架构的话,可以看一下README和backpressure文档。
对这类上位机项目感兴趣的朋友们可以下载试一试。
开源地址:https://github.com/agentthink/edge-acq