FreeSCADA 2:基于.NET的开源 SCADA 系统

AI摘要FreeSCADA 2 是一款开源 SCADA 系统,基于微软技术栈构建,采用 .NET/C#/WPF/XAML 技术。它支持纯 XAML 语法定义矢量图形,并可将 XAML 属性直接绑定到标签值,实现动态数据可视化展示,内置 OPC、ModBus 和 SNMP 等多种通信协议驱动程序,在工业自动化领域具有广泛应用潜力。系统架构主要由 Designer 和 Run Time 两个核心模块以及其他辅助模块和插件组成。Designer 是用于创建和配置项目的开发工具,提供可视化界面,允许用户定义与数据源的链接、设置归档规则等;Run Time 负责项目的实际运行和监控,实现数据的实时采集、处理、存储、归档等功能。

项目简介

image

FreeSCADA 2 是一款基于微软技术栈的开源 SCADA(监控与数据采集)系统,采用 .NET/C#/WPF/XAML 等技术构建。它支持使用纯 XAML 语法定义矢量图形,并可将 XAML 属性直接绑定到标签值,实现动态数据的可视化展示。此外,还内置了 OPC、ModBus 和 SNMP 等多种通信协议的驱动程序,在工业自动化领域具有广泛应用潜力。

克隆项目

打开命令行工具,执行以下命令以克隆FreeSCADA项目到本地:

项目架构

  • 整体架构 :FreeSCADA 2 的架构主要由 Designer 和 Run Time 两个核心模块以及其他辅助模块和插件等组成。
    • Designer :是用于创建和配置项目的开发工具,提供了可视化界面,允许用户定义与数据源的链接、设置归档规则、声明报警及其预期用户反应、创建可视化方案和报告模板、设置报告生成计划等功能。例如,用户可以在 Designer 中通过简单的拖拽操作和配置,建立起与 PLC 等设备的连接,并设计出相应的监控画面和数据展示布局。
    • Run Time :负责项目的实际运行和监控,实现数据的实时采集、处理、存储、归档,以及报警生成、数据可视化、报告生成等功能。它能够将 Designer 中配置好的项目部署到实际运行环境中,并按照设定的规则进行数据采集和处理,同时以图形化的方式将数据展示给用户。例如,在工业生产过程中,Run Time 可以实时采集生产数据,并在界面上动态显示生产状态和相关参数,当出现异常情况时及时发出报警。
  • 数据流架构 :数据采集模块从各种设备和数据源中获取数据,然后通过数据处理模块进行清洗、转换和计算等操作,再将处理后的数据存储到数据库中。数据存储模块为数据查询和分析模块提供支持,以便用户能够快速检索和分析历史数据。同时,系统还会根据配置的规则生成相应的报警信息,并通过报警管理模块通知用户。在数据展示方面,系统利用 WPF 和 XAML 的强大功能,将实时数据和历史数据以图表、趋势图、仪表盘等多种形式直观地展示给用户。
  • 通信架构 :FreeSCADA 2 内置了多种通信协议的驱动程序,如 OPC、ModBus 和 SNMP 等,通过这些协议,系统能够与各种工业设备和系统进行通信,实现数据的采集和交互。此外,它还提供了通信插件机制,允许用户根据实际需求扩展和定制通信协议,以满足不同设备和场景的通信要求。

主要代码分析

image

核心模块代码

Designer 模块

位于项目的 Designer 目录下,其核心代码主要包括 MainForm.cs 等文件。MainForm.cs 是 Designer 的主窗口代码,实现了界面的初始化、菜单和工具栏事件处理、项目加载和保存等功能。例如,在项目加载过程中,它会读取项目的配置文件,解析项目的结构和各个组件的配置信息,并在界面上进行相应的显示和初始化。

RunTime 模块

主要代码集中在 Runtime 目录中,MainForm.cs 是其核心文件之一,负责 RunTime 的启动、初始化和运行时管理。它会加载项目的配置,启动数据采集和处理线程,初始化通信协议驱动等,并在运行过程中实时监控系统的状态和数据变化,确保系统的稳定运行。

Common模块

Common 模块是 FreeSCADA 2 的核心基础模块,它为整个系统提供了通用的接口、数据模型、工具类和配置管理等功能,是其他模块(如 Designer、Run Time 等)正常运行所依赖的基石。它就像是一个公共工具箱,里面包含了各种各样的工具和资源,供系统的不同部分在需要时调用和使用。

主要功能与代码细节

  • 接口定义
    • 数据接口 :Common 模块定义了一系列与数据相关的接口,比如 IDataSource 接口。这个接口规定了数据源的基本操作规范,包括数据的读取、写入、连接和断开等方法。例如,Read 方法用于从数据源读取数据,Write 方法用于向数据源写入数据。这些接口使得不同类型的设备和协议驱动(如 OPC、ModBus 等)能够以统一的方式进行数据交互。当开发者需要添加一个新的数据源驱动时,只需实现 IDataSource 接口,就可以确保它能够与系统的其他部分无缝集成。
    • 通信接口ICommunicationDriver 是通信相关的接口,它规定了通信驱动的基本行为,例如建立通信连接、发送和接收数据等。这使得系统能够轻松地扩展对不同通信协议的支持。例如,如果要添加一个新的无线通信协议驱动,开发者可以基于 ICommunicationDriver 接口进行实现,而无需修改系统的其他核心逻辑。
  • 数据模型
    • 标签数据模型(Tag) :在 Common 模块中,标签(Tag)是数据的基本单位。Tag 类定义了标签的属性,如名称、数据类型、描述、当前值、质量(表示数据的可靠性,如好、坏、可疑等)、时间戳等。例如,一个温度传感器的标签可能有名称为 “TemperatureSensor1”,数据类型为浮点数,当前值为 25.5℃,质量为 “Good”,时间戳为当前系统时间。这些标签数据模型为系统中的数据采集、存储、处理和可视化提供了统一的数据结构。
  • 工具类
    • 日志工具类(Logger) :日志记录对于系统的调试、监控和维护至关重要。Logger 类提供了方便的日志记录功能,包括记录不同级别的日志(如信息、警告、错误等)。例如,当系统成功连接到一个设备时,可以记录一条信息级别的日志;当数据采集出现异常时,记录一条错误级别的日志。这有助于开发者快速定位问题所在,了解系统的运行状态。
  • 配置管理
    • 环境类(Env),它实现了IEnvironment接口。这个类主要用于管理和初始化FreeSCADA环境,包括版本信息、命令、主窗口、项目、环境模式、日志记录、脚本管理以及通信和可视化插件等。Env类使用了单例模式,确保在整个应用程序中只有一个Env实例。

在系统中的作用与与其他模块的交互

  • 在系统中的作用 :Common 模块是整个 FreeSCADA 2 系统的 “粘合剂”。它为其他模块提供了统一的接口规范、数据模型和工具,确保了系统的各个部分能够以协调一致的方式工作。没有 Common 模块,其他模块之间就难以进行有效的通信和数据共享。
  • 与其他模块的交互 :Designer 模块在创建和配置项目时,会频繁地调用 Common 模块中的接口和工具类。例如,在定义标签时,会使用 Tag 类来设置标签的属性;在配置通信协议时,会参考 ICommunicationDriver 接口的规范。Run Time 模块在运行项目时,会根据 ProjectConfig 类中的配置信息来初始化数据源和通信连接,并利用 DataProcessorUtils 类对采集到的数据进行处理。同时,Run Time 模块也会通过 Logger 类记录运行过程中的各种事件和状态信息。

数据采集

Communication 目录下,包含了各种通信协议驱动的实现代码。比如在 FreeSCADA 2 的 Communication.OPCPlug 模块中,ICommunicationDriver 接口发挥着关键作用,它定义了通信驱动的基本规范,使得 OPCPlug 模块能够与系统其他部分高效协同,实现数据的精准传递。

IChannel Interface

定义了通道(Channel)的基本功能和属性,如名称(Name)、插件标识(PluginId)、值(Value)、是否只读(IsReadOnly)、状态标志(StatusFlags)等。

提供了事件,如PropertyChangedValueChanged,用于通知其他部分通道属性或值的变化。

是一个契约,规定了通道类需要实现的成员。

BaseChannel Abstract Class

实现了IChannel接口,提供了通道的基本功能和公共实现。

包含了通道的核心属性和方法,如获取通道名称、类型、值,以及更新值和状态的方法。

提供了抽象方法DoUpdate()和虚方法DoUpdate(object value)DoUpdate(object value, DateTime externalTime, ChannelStatusFlags status),供子类根据具体通信协议实现数据更新逻辑。

具备线程安全机制,使用lock关键字确保在多线程环境下数据的一致性和完整性。

是一个抽象基类,不能直接实例化,需要由子类继承并实现抽象方法。

OPCBaseChannel Class

继承自BaseChannel抽象类,是针对OPC(OLE for Process Control)协议通信的具体实现。

包含了与OPC服务器通信相关的属性,如OPC通道名称(OpcChannel)、OPC服务器名称(OpcServer)、OPC主机(OpcHost)、连接组(opcConnection)和OPC句柄(opcHandle)。

重写了Value属性的set访问器,在设置新值时,会通过OPC连接将值写入OPC服务器,并调用基类的DoUpdate方法更新本地值。

提供了ConnectDisconnect方法,用于与OPC服务器建立和断开连接。

重写了DoUpdate方法,目前为空,需要根据具体OPC通信逻辑进行实现。

数据流向

数据从OPC服务器流向OPCBaseChannel:

OPCBaseChannel通过Connect方法与OPC服务器建立连接,并获取到OPC句柄opcHandle

当需要从OPC服务器读取数据时,OPCBaseChannel通过其内部的OPC连接(opcConnection)从OPC服务器读取数据。

读取到的数据会更新到OPCBaseChannelValue属性中。

更新Value属性会触发基类的FireValueChanged方法,进而引发PropertyChangedValueChanged事件,通知其他订阅者数据已更新。

数据从OPCBaseChannel流向OPC服务器:

OPCBaseChannelValue属性被设置时,如果通道不是只读的,并且与OPC服务器的连接已建立,它会通过opcConnection.WriteChannel(opcHandle, value)将新值写入OPC服务器。

同时,它会调用基类的DoUpdate方法更新本地值和状态。

数据在OPCBaseChannel内部流动:

通道的状态(StatusFlags)可以通过StatusFlags属性设置,这会更新modifyTime并触发FireValueChanged方法,进而引发相关事件。

通道的重置操作(Reset方法)会将值恢复为默认值,并更新状态和时间。

数据从OPCBaseChannel流向其他部分:

通过PropertyChanged事件,当通道的ValueModifyTimeStatusStatusFlags属性发生变化时,会通知其他订阅者(如用户界面或数据处理模块),使它们能够获取到最新的数据。

通过ValueChanged事件,当通道的值发生变化时,会通知其他订阅者,使它们能够对值的变化做出响应。

总结

这三个类的关系和数据流向如下:

IChannel定义了通道的契约,BaseChannel实现了这个契约并提供了通用功能,OPCBaseChannel继承自BaseChannel并实现了针对OPC协议的具体功能。

数据从OPC服务器流向OPCBaseChannel,更新其值和状态;OPCBaseChannel内部处理数据的更新和状态变化,并通过事件将数据变化通知给其他部分。

这种设计通过接口和抽象类实现了代码的复用和扩展性,使得可以方便地添加对其他通信协议的支持,只需继承BaseChannel并实现相应的通信逻辑即可。

自定义控件

VisualControls.FS2EasyControls 模块是 FreeSCADA 2 系统中用于提供可视化控件的核心组件库,旨在为用户提供更丰富、便捷的图形化界面元素,用于直观地展示和操作工业自动化过程中的各类数据。这些控件涵盖了从基本的数据显示(如数值、文本)、状态指示(如指示灯、报警器),到复杂的交互式图表(如趋势图、棒图)等多种类型,是实现系统人机交互界面(HMI)的关键。

IVisualControlsPlug 接口在 FS2EasyControls 中的实现

接口方法实现

数据源绑定

BindDataSource 方法:这是实现控件与数据源关联的核心方法。它接收数据源标识符(如标签名称)和数据绑定规则(如数据类型转换、数据更新频率等)作为参数。FS2EasyControls 模块中的每个可视化控件都通过这个方法与 FreeSCADA 2 系统中的特定数据(如从 OPC 服务器、ModBus 设备等采集的数据)建立联系。

例如,对于一个用于显示温度的数字显示屏控件,通过 BindDataSource 方法将其与表示温度传感器数据的标签 “Temperature.Sensor1” 绑定。在绑定过程中,可以指定数据类型为浮点数,更新频率为每秒一次等规则。这样,控件就能够实时获取该温度数据的变化,并在界面上进行相应更新。

数据更新与刷新

UpdateData 方法:用于将最新的数据从数据源拉取到控件,并触发控件的刷新操作。当系统中的数据(如通过 Communication 模块从设备采集到的新数据)发生变化时,FS2EasyControls 模块会调用控件的 UpdateData 方法。该方法内部会根据控件的类型和绑定规则,对数据进行适当的处理(如数值修约、单位转换等),然后更新控件的显示内容。

比如,在一个模拟压力表控件中,当 UpdateData 方法被调用并接收到新的压力值数据时,它会根据压力值计算指针的旋转角度,重新绘制压力表的图形界面,使指针指向对应的压力刻度位置,从而直观地反映当前压力的变化情况。

用户交互响应

OnUserInteraction 方法:用于处理用户与控件之间的交互操作,如点击按钮、调整滑块、输入文本等。当用户对可视化控件进行操作时,FS2EasyControls 模块会捕捉到这些操作事件,并通过 OnUserInteraction 方法进行相应处理。

例如,在一个用于控制电机启停的按钮控件中,当用户点击启动按钮时,OnUserInteraction 方法会识别这个点击事件,然后根据预先定义的控制逻辑(如向 PLC 发送电机启动命令),通过 FreeSCADA 2 系统的通信模块将控制指令发送到相应的设备。同时,它还可以更新按钮本身的显示状态(如改变按钮颜色为绿色表示电机已启动)。

数据封装与传递

数据封装

在 FS2EasyControls 模块中,数据从数据源传递到控件时,会按照 FreeSCADA 2 系统统一的数据模型(如 Common 模块中的 Tag 类)进行封装。控件接收到的数据包含数据值、质量(如好、坏、可疑等)、时间戳等关键信息。例如,从 OPC 服务器获取的流量数据 “FlowMeter1” 会封装为一个 Tag 对象,其 Value 属性为当前流量值(如 120m³/h),Quality 属性为数据质量(假设为 “Good”),TimeStamp 属性为数据更新时间。

数据传递流程

当系统中的数据源(如通过 OPCPlug 模块连接的 OPC 服务器)有数据更新时,数据首先会按照 ICommunicationDriver 的规范传递到 FreeSCADA 2 的数据处理层。然后,数据处理层根据可视化界面的配置(如哪个控件绑定了该数据源),调用 FS2EasyControls 模块中相应控件的 UpdateData 方法。控件接收到数据后,根据自身类型和绑定规则进行处理,并更新显示内容。同时,控件在处理数据过程中,也可以将一些状态信息(如数据是否在正常范围内、是否触发报警等)反馈给系统,以便系统进行进一步的处理(如生成报警信息推送等)。

纪小年

Jing

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理