Proficy Historianの生データをクエリするにはどうすればよいですか?
質問
Proficy Historian / iHistorianから未加工の時系列データを取得するにはどうすればよいですか?
理想的には、2つの日付の間に特定のタグのデータを要求します。
解決
さまざまなサンプリングモードを試すことができます。
- 生
- 補間
- ラボ
- トレンド
- 計算済み
これらのモードは、次のすべてのAPIを使用して使用できます。
- ユーザーAPI(ihuapi.dll)
- SDK(ihsdk.dll)
- OLEDB(iholedb.dll)
- クライアントアクセスAPI(Proficy.Historian.ClientAccess.API)
これらのうち、チャート/トレンド用に特別に設計されているため、トレンドサンプリングモードがおそらく必要です。ただし、ラボと補間も同様に役立つ場合があります。
各サンプリングモードの詳細については、電子書籍をお読みください。私のマシンでは、 C:\ Program Files \ GE Fanuc \ Proficy Historian \ Docs \ iHistorian.chm
として保存されており、バージョン3.5がインストールされています。以下のセクションに特に注意してください。
- Historian OLE DBプロバイダーの使用
- 高度なトピック|検索
これは、トレンドサンプリングを行うための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'
User APIとSDKを使用して同等のメソッドを表示するのは、セットアップを取得するために多くの配管を必要とするため、複雑です(User APIの場合はさらに複雑です)。クライアントアクセスAPIはより新しく、舞台裏でWCFを使用しています。
ところで、OLEDBメソッドにはいくつかの制限があります。
- ドキュメントに書かれていることにもかかわらず、私はネイティブのクエリパラメータを機能させることができなかった 。たとえば、SQL Server Reporting Servicesで使用する場合、これは非常に優れています。
- サンプルをアーカイブに書き込むことや、タグの追加/変更、メッセージの書き込みなどを含むHistorianの構成を変更することはできません。
- 場合によっては少し遅くなることがあります。
- 複数のタグ名を列にクロスタブしてから、サンプルを繰り越して各タイムスタンプとタグの組み合わせに値が存在するようにすることはできません。トレンドサンプリングモードでは、途中まで到達しますが、クロスタブは実行されず、実際の生サンプルはロードされません。この場合も、ユーザーAPIとSDKはこれを実行できません。
他のヒント
私の同僚がこれをまとめました:
web.config内:
<add name="HistorianConnectionString"
providerName="ihOLEDB.iHistorian.1"
connectionString="
Provider=ihOLEDB.iHistorian;
User Id=;
Password=;
Data Source=localhost;"
/>
データレイヤー内:
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];
}
}
更新:
これはうまく機能しましたが、あまり頻繁に更新されないタグの問題に遭遇しました。要求されたstartDateとendDateの開始または終了近くでタグが更新されなかった場合、傾向は悪く見えます。さらに悪いことに、要求されたウィンドウの間に明示的なポイントがなかった場合もありました。データが返されませんでした。
3つのクエリを作成してこれを解決しました:
- 開始日より前の の値
- startDateとendDateの間のポイント
- endDateの後の 次の値
これは潜在的に非効率的な方法ですが、機能します:
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];
}
}
そして、はい、それらのクエリはパラメータ化する必要があります。
マイケル-IP21には、「補間」があります。表、および「実際の」データポイントテーブル。 Proficyにも同様の機能がありますか?
次のようなラッパー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
);
....
注意点として、iFIXは起動時にDLLがロードされているかどうかを確認するため、他のアプリケーションがクラッシュしないようにDLLを動的にロード/アンロードする必要があります。そのために、レジストリキーをその場で削除/追加しました。
もう1つは、10,000個のサンプルをポーリングし、そのうちの1つが破損している場合、10,000個すべてのサンプルがドロップされることです。不良データのいずれかの側で開始し、段階的に増分して不良サンプルの両側のすべてのデータを取得する不良データハンドラを実装する必要があります。
すべてのエラーコードとDLLの関数ヘッダーを含むCヘッダーファイルがいくつかあります。