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款...
- 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和智能自动化设备之间的...
你 发表评论:
欢迎- 一周热门
-
-
Linux:Ubuntu22.04上安装python3.11,简单易上手
-
宝马阿布达比分公司推出独特M4升级套件,整套升级约在20万
-
MATLAB中图片保存的五种方法(一)(matlab中保存图片命令)
-
别再傻傻搞不清楚Workstation Player和Workstation Pro的区别了
-
Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
-
如何提取、修改、强刷A卡bios a卡刷bios工具
-
Element Plus 的 Dialog 组件实现点击遮罩层不关闭对话框
-
MacOS + AList + 访达,让各种云盘挂载到本地(建议收藏)
-
日本组合“岚”将于2020年12月31日停止团体活动
-
SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索
-
- 最近发表
-
- 10款超实用JavaScript音频库(js播放音频代码)
- Howler.js,一款神奇的 JavaScript 开源网络音频工具库
- PROFINET转Modbus网关——工业协议融合的智能枢纽
- 简单实用的Modbus类库,支持从站和DTU
- [西门子PLC] S7-200 SMART PROFINET :通过GSD组态PLC设备
- Modbus(RTU / TCP)有什么异同(modbus tcp和tcp)
- Modbus通信调试步骤详解(modbus调试工具怎么用)
- 理解Intel手册汇编指令(intel 汇编指令手册)
- 「西门子PLC」S7-200 SMART的Modbus RTU通讯
- InfiniBand网络运维全指南:从驱动安装到故障排查
- 标签列表
-
- dialog.js (57)
- importnew (44)
- windows93网页版 (44)
- yii2框架的优缺点 (45)
- tinyeditor (45)
- qt5.5 (60)
- windowsserver2016镜像下载 (52)
- okhttputils (51)
- android-gif-drawable (53)
- 时间轴插件 (56)
- docker systemd (65)
- slider.js (47)
- android webview缓存 (46)
- pagination.js (59)
- loadjs (62)
- openssl1.0.2 (48)
- velocity模板引擎 (48)
- pcre library (47)
- zabbix微信报警脚本 (63)
- jnetpcap (49)
- pdfrenderer (43)
- fastutil (48)
- uinavigationcontroller (53)
- bitbucket.org (44)
- python websocket-client (47)