百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

C#通过API接口读取KingSCADA实时库数据

suiw9 2024-12-01 04:01 75 浏览 0 评论

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

在实际项目中数据采集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; //用户名:KVAdministrator

string m_strPassword; //用户密码:F93E1D6FA158C4D2153BC7F4B36CCD86

private 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); //获得选中变量的变量ID

List<BrkTagData> ValueArray = new List<BrkTagData>();

List<int> ErrorCodeArray = new List<int>();

int ErrorCode = m_Con.TagGetTagValues(TagIDArray, out ValueArray, out ErrorCodeArray); //由变量(ID)TagIDArray获得变量值ValueArray

if (ErrorCode != 0)

{

 MessageBox.Show("Get Tag Data Failed");

 return;

}

//从ValueArray列表中解析出变量值

// add by zhichao.yao 12/8/2017

for (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/2017

if (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实时数据库读取数据的实现过程,关于文档中其他函数的相关功能,后续有时间继续学习验证。

相关推荐

10款超实用JavaScript音频库(js播放音频代码)

HTML5提供了一种新的音频标签实现和规范用一个简单的HTML对象而无需音频插件来控制音频。这只是一个简单的整合这些新的HTML5音频特征及使用JavaScript来创建各种播放控制。下面将介绍10款...

Howler.js,一款神奇的 JavaScript 开源网络音频工具库

o...

PROFINET转Modbus网关——工业协议融合的智能枢纽

三格电子SG-PNh750-MOD-221,无缝连接Profinet与Modbus,赋能工业物联产品概述...

简单实用的Modbus类库,支持从站和DTU

一、简介...

[西门子PLC] S7-200 SMART PROFINET :通过GSD组态PLC设备

从S7-200SMARTV2.5版本开始,S7-200SMART开始支持做PROFINETIO通信的智能设备。从而,两个S7-200SMART之间可以进行PROFINETI...

Modbus(RTU / TCP)有什么异同(modbus tcp和tcp)

Modbus是一种广泛使用的工业自动化通信协议,它支持设备之间的数据交换。Modbus协议有两个主要的变体:ModbusRTU(二进制模式)和ModbusTCP(基于TCP/IP网络的模式)。尽管...

Modbus通信调试步骤详解(modbus调试工具怎么用)

Modbus通信调试步骤详解  Modbus通信分为串口和以太网,无论是串口还是以太网,只要是标准Modbus,就可以用Modbus模拟器进行调试。按以下几步进行调试。...

理解Intel手册汇编指令(intel 汇编指令手册)

指令格式...

「西门子PLC」S7-200 SMART的Modbus RTU通讯

S7-200SMART集成的RS485端口(端口0)以及SBCM01RS485/232信号板(端口1)两个通信端口可以同时做MODBUSRTU主站,或者一个做MODBUSRTU主站一个做MO...

InfiniBand网络运维全指南:从驱动安装到故障排查

一、InfiniBand网络概述InfiniBand(直译为“无限带宽”技术,缩写为IB)是一种用于高性能计算的计算机网络通信标准,具有极高的吞吐量和极低的延迟,用于计算机与计算机之间的数据互连。它...

一加回归 OPPO,背后的秘密不可告人

有这样一个手机品牌,它诞生于互联网品牌。在大众群体看来,它的身世似乎模糊不清,许多人以为它是国外品牌。它的产品定位是极客群体,深受国内发烧友,甚至国外极客玩家喜爱。...

[西门子PLC] S7-200SMART快速高效的完成Modbus通信程序的设计

一、导读Modbus通信是一种被广泛应用的通信协议,在变频器、智能仪表还有其他一些智能设备上都能见到它的身影。本文呢,就把S7-200SMART系列PLC当作Modbus主站,把...

狂肝10个月手搓GPU,他们在我的世界中玩起我的世界,梦想成真

梦晨衡宇萧箫发自凹非寺量子位|公众号QbitAI自从有人在《我的世界》里用红石电路造出CPU,就流传着一个梗:...

[西门子PLC] 博途TIA portal SCL编程基础入门:1-点动与自锁

一、S7-SCL编程语言简介...

工作原理系列之:Modbus(modbus工作过程)

MODBUS是一种在自动化工业中广泛应用的高速串行通信协议。该协议是由Modion公司(现在由施耐德电气公司获得)于1979年为自己的可编程逻辑控制器开发的。该协议充当了PLCS和智能自动化设备之间的...

取消回复欢迎 发表评论: