C

雅轩聊科技 2024-10-23 20:27:20

哈喽,你好啊,我是雷工!

在实际项目中数据采集SCADA系统的数据时比较多的是通过OPC接口,但OPC常常是需要另外按点位收费的,

随着与信息化平台交互的频繁,常常需要用到通过API访问实时数据。

在KingSCADA中为了能够让用户通过接口方式访问SCADA运行数据并执行相关操作,KingSCADA运行态开放了运行系统实时库处理接口,第三方用户可以通过kxTVAPI模块与KingSCADA运行系统建立通讯,获取相关数据。

这里记录学习《KingSCADA C# 实时库API详细设计手册》以及C#的Demo时的相关笔记。

01 效果演示

示例演示C#通过API接口读取KingSCADA实时数据库的内存变量数值。

02 VS实现步骤

2.1、创建项目

用VS创建一个新项目,命名为KingSCADA_API;

2.2、添加空件

①GroupBox控件

在窗体中添加两个GroupBox控件分别用来显示服务器信息和变量管理两个区域。

②Label控件

添加几个标签设置对应的输入框标签说明;

③TextBox控件

添加几个TextBox控件用于输入服务器IP,端口,用户名,密码,设置变量值,订阅范围,变量ID等输入框。

④Button控件

添加几个Button控件用来做连接,断开,获取所有变量,获取变量值等按钮。

⑤TreeView控件

添加一个TreeView控件,用来显示读取到的变量信息及数据值信息。

2.3、添加引用

在解决方案-引用添加引用,引入所需的dll文件。

2.4、编写代码

①准备

private Connection m_Con = null; //客户端连接服务器类private ArrayList TagList;string m_strServerPort; //服务器端口string m_strUserName; //用户名:KVAdministratorstring m_strPassword; //用户密码:F93E1D6FA158C4D2153BC7F4B36CCD86private static Dictionary<int, string> m_mapTagIDItemIndex = new Dictionary<int, string>();private static Dictionary<int, ListViewItem> m_mapListIndex = new Dictionary<int, ListViewItem>();KXTVClientInfo ClientInfo = new KXTVClientInfo();

②构造函数

public Form1(){ InitializeComponent(); if (m_Con == null) {try{ m_Con = new Connection();}catch (Exception ex){ m_Con = null; MessageBox.Show("Can not create KSCADAServer object with exception " + ex.ToString()); return;} } TagList = new ArrayList();}

③Loda

private void Form1_Load(object sender, EventArgs e){ Control.CheckForIllegalCrossThreadCalls = false; listView1.Visible = true; tvTagInfo.Visible = false; cbbAlarmType.SelectedIndex = 0;}

④连接服务器

/// <summary>/// 连接服务器/// </summary>private void btConnect_Click(object sender, EventArgs e){ if (m_Con == null) {try{ m_Con = new Connection();}catch (System.Exception ex){ m_Con = null; MessageBox.Show("Can not create KSCADAServer object with exception " + ex.ToString()); return;} } m_Con.Initialize(); //连接前要使用Initialize函数初始化连接句柄 //初始化连接参数 ConnectionOption option = new ConnectionOption(); option.ServerName = tbServer.Text; //服务器名 option.ServerPort = (System.String)tbPort.Text; //服务器端口 option.ConnectionFlags = 0x00000002; //协议、安全等选项固定2 option.NetUserFlag = 0x00; //网络用户标记固定0 option.UserName = tbUser.Text;//用户名 option.Password = tbPassword.Text; //密码 option.NetworkTimeout = 0x00; //网络超时0 option.Reserved1 = 0x00000001;//保留字节固定为1 //连接服务器 try {m_Con.Connect(option, ClientInfo); //调用连接服务器函数 } catch (Exception ex) {MessageBox.Show("Can not connect to server(" + tbServer.Text + "with excepiton " + ex.ToString());return; } try {m_Con.OnBlobTagFieldChange += new Connection.BlobTagFieldChangeHandler(OnBlobTagFieldChange); //注册回调函数 } catch (Exception ex) {MessageBox.Show("Failed to register OnTagFieldChange with excepiton " + ex.ToString());return; } MessageBox.Show("连接成功!");}

⑤断开连接服务器

/// <summary>/// 断开连接服务器/// </summary>private void btDiscon_Click(object sender, EventArgs e){ if (m_Con == null) {return; } if (m_Con.IsConnected) {m_Con.Disconnect();m_Con = null; } MessageBox.Show("断开连接成功!");}

⑥获取变量信息

/// <summary>/// 获得变量信息(变量名和变量ID)/// </summary>private void btnGetTagList_Click(object sender, EventArgs e){ listView1.Visible = true; tvTagInfo.Visible = false; if (m_Con == null) {return; } int ItemNum = m_mapListIndex.Count; if (ItemNum != 0) {foreach (KeyValuePair<int, ListViewItem> kv in m_mapListIndex){ this.listView1.Items.Remove(kv.Value);}m_mapListIndex.Clear(); } int m_mapTagIDItemIndexNum = m_mapTagIDItemIndex.Count; if (m_mapTagIDItemIndexNum != 0) {m_mapTagIDItemIndex.Clear(); } List<string> TagNameArray = new List<string>(); List<int> TagIDArray = new List<int>(); List<int> ErrorCodeArray = new List<int>(); int ErrorCode = m_Con.TagGetAllTagName(out TagNameArray); //获得工程中的所有变量名 if (ErrorCode != 0) {MessageBox.Show("Get Tag List Failed");return; } ErrorCode = m_Con.TagGetTagIDbyName(TagNameArray, out TagIDArray, out ErrorCodeArray); //由变量名获得变量ID if (ErrorCode != 0) {MessageBox.Show("Get Tag ID Failed");return; } //把变量名和变量ID添加到listView1中 this.listView1.Items.Clear(); int SizeOfArray = TagIDArray.Count; this.listView1.BeginUpdate(); for (int i = 0; i < SizeOfArray; i++) {ListViewItem liv = new ListViewItem();liv.Text = TagNameArray[i];string temp;string temp1 = " ";temp = TagIDArray[i].ToString("D");liv.SubItems.Add(temp);liv.SubItems.Add(temp1);liv.Focused = true;this.listView1.Items.Add(liv);m_mapTagIDItemIndex.Add(TagIDArray[i], TagNameArray[i]);m_mapListIndex.Add(TagIDArray[i], this.listView1.Items[i]); } this.listView1.EndUpdate(); //MessageBox.Show("Get Tag List success");//modify by zhichao.yao}

⑦获取变量值

/// <summary>/// 获得选中变量的变量值/// </summary>private void btnGetTagValue_Click(object sender, EventArgs e){ if (m_Con == null) {return; } ListViewItem pos = this.listView1.TopItem; if (pos == null) {MessageBox.Show("No items were selected!"); } else {int TagNum = this.listView1.CheckedItems.Count;int[] TagIDs = new int[TagNum];List<int> TagIDArray = new List<int>();for (int i = 0; i < this.listView1.CheckedItems.Count; i++){ int.TryParse(this.listView1.CheckedItems[i].SubItems[1].Text, out TagIDs[i]);}TagIDArray.AddRange(TagIDs); //获得选中变量的变量IDList<BrkTagData> ValueArray = new List<BrkTagData>();List<int> ErrorCodeArray = new List<int>();int ErrorCode = m_Con.TagGetTagValues(TagIDArray, out ValueArray, out ErrorCodeArray); //由变量(ID)TagIDArray获得变量值ValueArrayif (ErrorCode != 0){ MessageBox.Show("Get Tag Data Failed"); return;}//从ValueArray列表中解析出变量值// add by zhichao.yao 12/8/2017for (int i = 0; i < TagNum; i++){ string strTagValue; byte TagDataType = ValueArray[i].FieldValue.Type; //变量值类型,由变量值类型解析出变量值 switch (TagDataType) {case VALUE_TYPE_BOOL.value: //bool型 if (ValueArray[i].FieldValue.bitVal != null) {if (ValueArray[i].FieldValue.bitVal == Convert.ToBoolean(1)){ strTagValue = "TRUE";}else{ strTagValue = "FALSE";} } else {strTagValue = ""; } break;case VALUE_TYPE_I1.value: //一字节整数 if (ValueArray[i].FieldValue.i1Val != null) {strTagValue = ValueArray[i].FieldValue.i1Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_UI1.value: //一字节无符号整数 if (ValueArray[i].FieldValue.ui1Val != null) {strTagValue = ValueArray[i].FieldValue.ui1Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_I2.value: //两字节整数 if (ValueArray[i].FieldValue.i2Val != null) {strTagValue = ValueArray[i].FieldValue.i2Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_UI2.value: //两字节无符号整数 if (ValueArray[i].FieldValue.ui2Val != null) {strTagValue = ValueArray[i].FieldValue.ui2Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_I4.value: //四字节整数 if (ValueArray[i].FieldValue.i4Val != null) {strTagValue = ValueArray[i].FieldValue.i4Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_UI4.value: //四字节无符号整数 if (ValueArray[i].FieldValue.ui4Val != null) {strTagValue = ValueArray[i].FieldValue.ui4Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_I8.value: //八字节整数 if (ValueArray[i].FieldValue.i8Val != null) {strTagValue = ValueArray[i].FieldValue.i8Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_UI8.value: //八字节无符号整数 if (ValueArray[i].FieldValue.ui8Val != null) {strTagValue = ValueArray[i].FieldValue.ui8Val.ToString("D"); } else {strTagValue = ""; } break;case VALUE_TYPE_R4.value: //单精度浮点数 if (ValueArray[i].FieldValue.r4Val != null) {strTagValue = ValueArray[i].FieldValue.r4Val.ToString("F"); } else {strTagValue = ""; } break;case VALUE_TYPE_R8.value: //双精度浮点数 if (ValueArray[i].FieldValue.r8Val != null) {strTagValue = ValueArray[i].FieldValue.r8Val.ToString(); } else {strTagValue = ""; } break;case VALUE_TYPE_STR.value: //ASCII字符串 if (ValueArray[i].FieldValue.strVal != null) {strTagValue = ValueArray[i].FieldValue.strVal.ToString(); } else {strTagValue = ""; } break;case VALUE_TYPE_WSTR.value: //Unicode字符串 if (ValueArray[i].FieldValue.wstrVal != null) {strTagValue = ValueArray[i].FieldValue.wstrVal.ToString(); } else {strTagValue = ""; } break;case VALUE_TYPE_FILETIME.value: //文件时间 if (ValueArray[i].FieldValue.ftVal != null) {strTagValue = ValueArray[i].FieldValue.ftVal.ToString(); } else {strTagValue = ""; } break;case VALUE_TYPE_TIMESTAMP.value: //时间戳 if (ValueArray[i].FieldValue.tsVal != null) {strTagValue = ValueArray[i].FieldValue.tsVal.ToString(); } else {strTagValue = ""; } break;default: Debug.Assert(false); return; } // add end by zhichao.yao 12/8/2017 if (m_mapTagIDItemIndex.ContainsKey(TagIDs[i])) {this.listView1.CheckedItems[i].SubItems[2].Text = strTagValue; }} } MessageBox.Show("获取变量值成功!");}

⑧回调函数

/// <summary>/// 变量域数据变化回调函数具体实现/// </summary>public int OnBlobTagFieldChange(Sorba.BlobStream FieldValueBlob, Sorba.Context context){ listView1.Visible = true; tvTagInfo.Visible = false; List<BrkTagPubData> FieldValueArray = new List<BrkTagPubData>(); int Count = 0; m_Con.KXTVBlobtoKXTVTAGDATAArray(FieldValueBlob, FieldValueArray, ref Count); //把BlobSteam流数据转化为变量发布数据列表 if (Count <= 0) {return KXTVAPIErrorCode.ERR_INVALID_DATA; } else {for (int Index = 0; Index < Count; Index++){ //FieldValueArray[Index].FieldID == KXTVTagFieldID.KXTVFIELD_Value 的BrkTagPubData数据对应的是变量值域发布数据; // add by zhichao.yao 12/8/2017 if (FieldValueArray[Index].FieldID == KXTVFIELD_Value.value) {int TagID = FieldValueArray[Index].TagID;string strTagValue;byte TagDataType = FieldValueArray[Index].FieldValue.Type;switch (TagDataType){ case VALUE_TYPE_BOOL.value:if (FieldValueArray[Index].FieldValue.bitVal != null){ if (FieldValueArray[Index].FieldValue.bitVal == Convert.ToBoolean(1)) {strTagValue = "TRUE"; } else {strTagValue = "FALSE"; }}else{ strTagValue = "";}break; case VALUE_TYPE_I1.value:if (FieldValueArray[Index].FieldValue.i1Val != null){ strTagValue = FieldValueArray[Index].FieldValue.i1Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_UI1.value:if (FieldValueArray[Index].FieldValue.ui1Val != null){ strTagValue = FieldValueArray[Index].FieldValue.ui1Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_I2.value:if (FieldValueArray[Index].FieldValue.i2Val != null){ strTagValue = FieldValueArray[Index].FieldValue.i2Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_UI2.value:if (FieldValueArray[Index].FieldValue.ui2Val != null){ strTagValue = FieldValueArray[Index].FieldValue.ui2Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_I4.value:if (FieldValueArray[Index].FieldValue.i4Val != null){ strTagValue = FieldValueArray[Index].FieldValue.i4Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_UI4.value:if (FieldValueArray[Index].FieldValue.ui4Val != null){ strTagValue = FieldValueArray[Index].FieldValue.ui4Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_I8.value:if (FieldValueArray[Index].FieldValue.i8Val != null){ strTagValue = FieldValueArray[Index].FieldValue.i8Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_UI8.value:if (FieldValueArray[Index].FieldValue.ui8Val != null){ strTagValue = FieldValueArray[Index].FieldValue.ui8Val.ToString("D");}else{ strTagValue = "";}break; case VALUE_TYPE_R4.value:if (FieldValueArray[Index].FieldValue.r4Val != null){ strTagValue = FieldValueArray[Index].FieldValue.r4Val.ToString("F");}else{ strTagValue = "";}break; case VALUE_TYPE_R8.value:if (FieldValueArray[Index].FieldValue.r8Val != null){ strTagValue = FieldValueArray[Index].FieldValue.r8Val.ToString();}else{ strTagValue = "";}break; case VALUE_TYPE_STR.value:if (FieldValueArray[Index].FieldValue.strVal != null){ strTagValue = FieldValueArray[Index].FieldValue.strVal.ToString();}else{ strTagValue = "";}break; case VALUE_TYPE_WSTR.value:if (FieldValueArray[Index].FieldValue.wstrVal != null){ strTagValue = FieldValueArray[Index].FieldValue.wstrVal.ToString();}else{ strTagValue = "";}break; case VALUE_TYPE_FILETIME.value:if (FieldValueArray[Index].FieldValue.ftVal != null){ strTagValue = FieldValueArray[Index].FieldValue.ftVal.ToString();}else{ strTagValue = "";}break; case VALUE_TYPE_TIMESTAMP.value:if (FieldValueArray[Index].FieldValue.tsVal != null){ strTagValue = FieldValueArray[Index].FieldValue.tsVal.ToString();}else{ strTagValue = "";}break; default:Debug.Assert(false);return KXTVAPIErrorCode.ERR_INVALID_DATA;}// add end by zhichao.yao 12/8/2017if (m_mapTagIDItemIndex.ContainsKey(TagID)){ m_mapListIndex[TagID].SubItems[2].Text = strTagValue;} }}return KXTVAPIErrorCode.ERR_OK; }}03 KingSCADA实现

3.1、创建变量

在建点-数据词典处创建几个内存变量用于测试;

3.2、设置属性

创建测试点位时在属性页要注意勾选【允许其他应用访问】,不然会导致异常。

3.3、创建界面

创建一个界面,连接测试点位,运行状态修改点位值,观察VS测试程序读取数值是否与之一致。

04 运行测试

将KingSCADA测试程序与VS测试程序分别运行起来,操作按钮,看是否能够正常连接KingSCADA并正确显示数据。

05 后记

以上为C#通过API接口连接KingSCADA实时数据库读取数据的实现过程,关于文档中其他函数的相关功能,后续有时间继续学习验证。

0 阅读:0

雅轩聊科技

简介:感谢大家的关注