[英]How do I query raw data from a Proficy Historian?
How can I retrieve raw time-series data from a Proficy Historian/iHistorian? 如何从Proficy Historian / iHistorian检索原始时间序列数据?
Ideally, I would ask for data for a particular tag between two dates. 理想情况下,我会要求两个日期之间的特定标签的数据。
There are several different sampling modes you can experiment with. 您可以尝试几种不同的采样模式。
These modes are available using all of the following APIs. 使用以下所有API可以使用这些模式。
Of these the trend sampling mode is probably what you want since it is specifically designed for charting/trending. 其中趋势采样模式可能是您想要的,因为它专门用于制图/趋势。 Though, lab and interpolated may be useful as well.
虽然,实验室和插值也可能有用。
Read the electronic book for more information on each sampling mode. 有关每种采样模式的更多信息,请阅读电子书。 On my machine it is stored as
C:\\Program Files\\GE Fanuc\\Proficy Historian\\Docs\\iHistorian.chm
and I have version 3.5 installed. 在我的机器上,它存储为
C:\\Program Files\\GE Fanuc\\Proficy Historian\\Docs\\iHistorian.chm
,我安装了3.5版本。 Pay particular attention to the following sections. 请特别注意以下部分。
Here is how you can construct an OLEDB to do trend sampling. 以下是如何构建OLEDB以进行趋势采样。
set
SamplingMode = 'Trend',
StartTime = '2010-07-01 00:00:00',
EndTime = '2010-07-02 00:00:00',
IntervalMilliseconds = 1h
select
timestamp,
value,
quality
from
ihRawData
where
tagname = 'YOUR_TAG'
Showing the equivalent methods using the User API and the SDK are complex (more so with the User API) since they require a lot of plumbing in the code to get setup. 使用User API和SDK显示等效方法很复杂(使用User API更是如此)因为它们需要在代码中进行大量管道才能进行设置。 The Client Access API is newer and uses WCF behind the scenes.
Client Access API更新,并在后台使用WCF。
By the way, there are a few limitations with the OLEDB method though. 顺便说一句,OLEDB方法有一些限制。
A coworker of mine put this together: 我的同事把它放在一起:
In web.config: 在web.config中:
<add name="HistorianConnectionString"
providerName="ihOLEDB.iHistorian.1"
connectionString="
Provider=ihOLEDB.iHistorian;
User Id=;
Password=;
Data Source=localhost;"
/>
In the data layer: 在数据层中:
public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate)
{
using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection())
{
cn.ConnectionString = webConfig.ConnectionStrings.ConnectionStrings["HistorianConnectionString"];
cn.Open();
string queryString = string.Format(
"set samplingmode = rawbytime\n select value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' and value > 0 order by timestamp",
tagName.Replace("'", "\""), startDate, endDate);
System.Data.OleDb.OleDbDataAdapter adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
DataSet ds = new DataSet();
adp.Fill(ds);
return ds.Tables[0];
}
}
Update: 更新:
This worked well but we ran into an issue with tags that don't update very often. 这很好用,但我们遇到了一个问题,这个问题不经常更新。 If the tag didn't update near the start or end of the requested startDate and endDate, the trends would look bad.
如果标记未在请求的startDate和endDate的开头或结尾附近更新,则趋势看起来会很糟糕。 Worse, still were cases where there were no explicit points during the window requested--we'd get no data back.
更糟糕的是,仍然是在请求的窗口期间没有明确点的情况 - 我们没有得到任何数据。
I resolved this by making three queries: 我通过三个查询来解决这个问题:
This is a potentially inefficient way to do it but It Works: 这是一种潜在的低效方法,但它可行:
public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate)
{
DataSet ds = new DataSet();
string queryString;
System.Data.OleDb.OleDbDataAdapter adp;
using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection())
{
cn.ConnectionString = proficyConn.ConnectionString;
cn.Open();
// always get a start value
queryString = string.Format(
"set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
tagName.Replace("'", "\""), startDate.AddMinutes(-1), startDate);
adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
adp.Fill(ds);
// get the range
queryString = string.Format(
"set samplingmode = rawbytime\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
tagName.Replace("'", "\""), startDate, endDate);
adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
adp.Fill(ds);
// always get an end value
queryString = string.Format(
"set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp",
tagName.Replace("'", "\""), endDate.AddMinutes(-1), endDate);
adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn);
adp.Fill(ds);
return ds.Tables[0];
}
}
And yes, I know, those queries should be parameterized. 是的,我知道,这些查询应该参数化。
Michael--in IP21 there is an "Interpolated" table, as well as the "actual" data point table. Michael - 在IP21中有一个“Interpolated”表,以及“实际”数据点表。 Does Proficy have that as well?
Proficy也有这个吗?
We wrote a wrapper DLL that looked like this like this: 我们编写了一个如下所示的包装DLL:
[DllImport("IHUAPI.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ihuReadRawDataByTime@24")]
public static extern int ihuReadRawDataByTime(int serverhandle, string tagname, ref IHU_TIMESTAMP startTime, ref IHU_TIMESTAMP endTime, ref int noOfSamples, ref IHU_DATA_SAMPLE* dataValues);
...
private int _handle;
public HistorianTypes.ErrorCode ReadRawByTime(string tagName, DateTime startTime, DateTime endTime,
out double[] timeStamps, out double[] values, out IhuComment [] comments)
{
var startTimeStruct = new IhuApi.IHU_TIMESTAMP(); //Custom datetime to epoch extension method
var endTimeStruct = new IhuApi.IHU_TIMESTAMP();
int lRet = 0;
int noOfSamples = 0;
startTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(startTime));
endTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(endTime));
IhuApi.IHU_DATA_SAMPLE* dataSample = (IhuApi.IHU_DATA_SAMPLE*)new IntPtr(0);
try {
lRet = IhuApi.ihuReadRawDataByTime
(
_handle, // the handle returned from the connect
tagName, // the single tagname to retrieve
ref startTimeStruct, // start time for query
ref endTimeStruct, // end time for query
ref noOfSamples, // will be set by API
ref dataSample // will be allocated and populated in the user API
);
....
Some notes are that iFIX will check if the DLL is loaded on startup so you need to do things like dynamically load/unload the DLL so that other applications don't crash. 一些注意事项是iFIX将检查DLL是否在启动时加载,因此您需要执行诸如动态加载/卸载DLL以使其他应用程序不会崩溃的操作。 We did this by deleting/adding registry keys on the fly.
我们通过动态删除/添加注册表项来完成此操作。
Another one is if you poll 10,000 samples and 1 of the samples are corrupted it will drop all 10,000 samples. 另一个是如果您轮询10,000个样本并且其中一个样本已损坏,则会丢弃所有10,000个样本。 You need to implement a bad data handler that will start at either side of the bad data and increment in steps to get all data either side of the bad sample.
您需要实现一个错误的数据处理程序,该处理程序将从错误数据的任一侧开始,并逐步递增以获取错误样本的任何一侧的所有数据。
There are several C header files that contain all of the error codes and the function header for the DLL. 有几个C头文件包含DLL的所有错误代码和函数头。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.