Come posso eseguire una query sui dati non elaborati da uno storico Proficy?
Domanda
Come posso recuperare i dati grezzi delle serie storiche da un Proficy Historian / iHistorian?
Idealmente, chiederei dati per un tag particolare tra due date.
Soluzione
Esistono diverse modalità di campionamento che puoi sperimentare.
- Raw
- interpolata ??li>
- Lab
- Trend
- calcolato
Queste modalità sono disponibili utilizzando tutte le seguenti API.
- API utente (ihuapi.dll)
- SDK (ihsdk.dll)
- OLEDB (iholedb.dll)
- API di accesso client (Proficy.Historian.ClientAccess.API)
Di questi, la modalità di campionamento delle tendenze è probabilmente ciò che desideri poiché è specificamente progettata per la creazione di grafici / trend. Anche lab e interpolati possono essere utili.
Leggi il libro elettronico per maggiori informazioni su ciascuna modalità di campionamento. Sul mio computer è memorizzato come C: \ Programmi \ GE Fanuc \ Proficy Historian \ Docs \ iHistorian.chm
e ho installato la versione 3.5. Prestare particolare attenzione alle seguenti sezioni.
- Utilizzo del provider OLE DB Historian
- Argomenti avanzati | Recupero
Ecco come è possibile costruire un OLEDB per eseguire il campionamento delle tendenze.
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'
La visualizzazione dei metodi equivalenti utilizzando l'API utente e l'SDK è complessa (in particolare con l'API utente) poiché richiede molta installazione nel codice per ottenere l'installazione. L'API di accesso client è più recente e utilizza WCF dietro le quinte.
Comunque, ci sono alcune limitazioni con il metodo OLEDB.
- Nonostante ciò che la documentazione dice che non non è mai stato in grado di far funzionare i parametri delle query native. Questo è uno showstopper se si desidera utilizzarlo con SQL Server Reporting Services, ad esempio.
- Non è possibile scrivere campioni nell'archivio o in alcun modo apportare modifiche alla configurazione di Historian tra cui l'aggiunta / modifica di tag, la scrittura di messaggi, ecc.
- In alcuni casi può essere un po 'lento.
- Non è previsto il crosstabbing di più tagname nelle colonne e quindi il trasferimento di campioni in modo che esista un valore per ogni combinazione data / ora e tag. La modalità di campionamento dell'andamento ti porta a metà strada, ma non è ancora a campi incrociati e in realtà non carica campioni grezzi. Quindi, anche l'API utente e l'SDK non possono farlo.
Altri suggerimenti
Un mio collega ha messo insieme questo:
In web.config:
<add name="HistorianConnectionString"
providerName="ihOLEDB.iHistorian.1"
connectionString="
Provider=ihOLEDB.iHistorian;
User Id=;
Password=;
Data Source=localhost;"
/>
Nel livello dati:
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];
}
}
Aggiornamento:
Funzionava bene, ma abbiamo riscontrato un problema con i tag che non si aggiornano molto spesso. Se il tag non si aggiornava vicino all'inizio o alla fine della data di inizio e della data di fine richieste, le tendenze sembrerebbero negative. Peggio ancora, c'erano ancora casi in cui non c'erano punti espliciti durante la finestra richiesta - non avremmo avuto nessun dato indietro.
Ho risolto questo problema facendo tre domande:
- Il valore precedente prima della data di inizio
- I punti tra startDate e endDate
- Il valore successivo dopo la data di fine
Questo è un modo potenzialmente inefficiente per farlo ma funziona:
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];
}
}
E sì, lo so, quelle query dovrebbero essere parametrizzate.
Michael - in IP21 c'è un "Interpolato" tabella, nonché la tabella "attuale" tabella dei punti dati. Anche Proficy ha questo?
Abbiamo scritto una DLL wrapper simile a questa:
[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
);
....
Alcune note indicano che iFIX verificherà se la DLL viene caricata all'avvio, quindi è necessario eseguire operazioni come caricare / scaricare dinamicamente la DLL in modo che altre applicazioni non si arrestino in modo anomalo. Lo abbiamo fatto cancellando / aggiungendo le chiavi di registro al volo.
Un altro è se si esegue il polling di 10.000 campioni e 1 dei campioni è corrotto, eliminerà tutti i 10.000 campioni. È necessario implementare un gestore dati non valido che verrà avviato su entrambi i lati dei dati errati e incrementato in passaggi per ottenere tutti i dati su entrambi i lati del campione errato.
Esistono diversi file di intestazione C che contengono tutti i codici di errore e l'intestazione della funzione per la DLL.