private OSIPIDataSource CreateNewDataSource(string keyName) { string[] parts = keyName.Split('.'); string instanceName = parts[0]; string serverName = parts[1]; if (!PIOutputAdapter.Instances.TryGetValue(serverName, out PIOutputAdapter adapterInstance) || !adapterInstance.Initialized || adapterInstance.IsDisposed) { return(null); } DataSet metadata = adapterInstance.DataSource; OSIPIDataSource dataSource = new OSIPIDataSource { InstanceName = instanceName, Metadata = metadata, KeyName = keyName, PrefixRemoveCount = adapterInstance.TagNamePrefixRemoveCount, Connection = new PIConnection() }; dataSource.Connection.ServerName = serverName; dataSource.Connection.UserName = adapterInstance.UserName; dataSource.Connection.Password = adapterInstance.Password; dataSource.Connection.ConnectTimeout = adapterInstance.ConnectTimeout; dataSource.Connection.Open(); // On successful connection, kick off a thread to start meta-data ID to OSI-PI point ID mapping new Thread(_ => { foreach (DataRow row in metadata.Tables["ActiveMeasurements"].Rows) { string[] idParts = row["ID"].ToString().Split(':'); if (idParts.Length != 2) { continue; } ulong metadataID = ulong.Parse(idParts[1]); if (!MetadataIDToPIPoint.TryGetValue(metadataID, out PIPoint point)) { if (TryFindPIPoint(dataSource.Connection, GetPITagName(row["PointTag"].ToString(), dataSource.PrefixRemoveCount), row["AlternateTag"].ToString(), out point)) { MetadataIDToPIPoint[metadataID] = point; } } } }) .Start(); return(dataSource); }
/// <summary> /// Starts a query that will read data source values, given a set of point IDs and targets, over a time range. /// </summary> /// <param name="startTime">Start-time for query.</param> /// <param name="stopTime">Stop-time for query.</param> /// <param name="interval">Interval from Grafana request.</param> /// <param name="decimate">Flag that determines if data should be decimated over provided time range.</param> /// <param name="targetMap">Set of IDs with associated targets to query.</param> /// <returns>Queried data source data in terms of value and time.</returns> protected override IEnumerable <DataSourceValue> QueryDataSourceValues(DateTime startTime, DateTime stopTime, string interval, bool decimate, Dictionary <ulong, string> targetMap) { Dictionary <int, ulong> idMap = new Dictionary <int, ulong>(); PIPointList points = new PIPointList(); foreach (KeyValuePair <ulong, string> target in targetMap) { ulong metadataID = target.Key; string pointTag = target.Value; if (!MetadataIDToPIPoint.TryGetValue(metadataID, out PIPoint point)) { if (TryFindPIPoint(Connection, Metadata, GetPITagName(pointTag, PrefixRemoveCount), out point)) { MetadataIDToPIPoint[metadataID] = point; } } if ((object)point != null) { points.Add(point); idMap[point.ID] = metadataID; } } // Start data read from historian using (IEnumerator <AFValue> dataReader = ReadData(startTime, stopTime, points).GetEnumerator()) { while (dataReader.MoveNext()) { AFValue currentPoint = dataReader.Current; if (currentPoint == null) { continue; } yield return(new DataSourceValue { Target = targetMap[idMap[currentPoint.PIPoint.ID]], Time = (currentPoint.Timestamp.UtcTime.Ticks - m_baseTicks) / (double)Ticks.PerMillisecond, Value = Convert.ToDouble(currentPoint.Value), Flags = ConvertStatusFlags(currentPoint.Status) }); } } }
private IEnumerable<AFValue> ReadData(AFTime startTime, AFTime endTime, PIPointList points) { try { return new TimeSortedValueScanner { Points = points, StartTime = startTime, EndTime = endTime //DataReadExceptionHandler = ex => OnProcessException(MessageLevel.Warning, ex) } .Read(); } catch { // Removed cached data source on read failure if (DataSources.TryRemove(KeyName, out _)) MetadataIDToPIPoint.Clear(); throw; } }