protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_connection != null) { m_connection.Disconnected -= m_connection_Disconnected; m_connection.Dispose(); m_connection = null; } m_dataPipe?.Dispose(); if ((object)m_eventTimer != null) { m_eventTimer.Elapsed -= m_eventTimer_Elapsed; m_eventTimer.Dispose(); } } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
static void Main(string[] args) { var dataArchive = new PIServers().DefaultPIServer; var points = GetOrCreatePIPoints(dataArchive, new string[] { "New York_Pressure", "New York_Temperature", "New York_Humidity" }, "AFSDKWS_"); //Create data pipe PIDataPipe pipe = new PIDataPipe(AFDataPipeType.Snapshot); pipe.AddSignups(points); var counter = 0; do { while (!Console.KeyAvailable) { CheckPipeEvents(pipe, ref counter); } ; } while (Console.ReadKey(true).Key != ConsoleKey.Escape); pipe.Close(); pipe.Dispose(); }
// Free the resource public void Dispose() { StopListening(); if (_AFPipe != null) { _AFPipe.Dispose(); } if (_PIPipe != null) { _PIPipe.Dispose(); } }
/// <summary> /// Disconnects from the configured PI server if a connection is open /// </summary> protected override void AttemptDisconnection() { m_eventTimer.Enabled = false; if ((object)m_dataPoints != null) { m_dataPoints.Clear(); m_dataPoints = null; } if ((object)m_dataPipe != null) { m_dataPipe.Dispose(); m_dataPipe = null; } if ((object)m_connection != null) { m_connection.Dispose(); m_connection = null; } }
public void PIDataPipeExample() { // Create point list containing our lab point and two known sinusoid points PIPointList pointList = new PIPointList(); pointList.Add(PIPoint.FindPIPoint(myPIServer, "sinusoid")); pointList.Add(PIPoint.FindPIPoint(myPIServer, "sinusoidu")); _eventPipe = new PIDataPipe(AFDataPipeType.Snapshot); _eventPipe.AddSignups(pointList); // Configure a timer to read the pipe every five seconds for updates Timer eventPipeTimer = new Timer(new TimerCallback(ReadPipe), null, 0, 100); // Block until user wants to exit Console.WriteLine("Press Enter to terminate"); Console.ReadLine(); // Disable timer eventPipeTimer.Dispose(); // Dispose of event pipe lock (_eventPipe) { _eventPipe.Dispose(); } }
private void getSnapshot(object obj) { List <PIPoint> p = obj as List <PIPoint>; SetDataGridCallback _dataGridCallback = new SetDataGridCallback(SetDataTable); PIDataPipe pipe = new PIDataPipe(AFDataPipeType.Archive); pipe.AddSignups(p); //_dt.Rows.Clear(); _dt = new DataTable(); _dt.Columns.Add("Tag", typeof(string)); _dt.Columns.Add("Timestamp", typeof(DateTime)); _dt.Columns.Add("Value", typeof(object)); _dt.Columns.Add("UOM", typeof(string)); _dt.Columns.Add("Annotation", typeof(string)); _dt.Columns.Add("CheckBox", typeof(bool)); _dt.Columns.Add("Message", typeof(string)); PIPointList piPointList = new PIPointList(); piPointList.AddRange(p); AFValues afValues = new AFValues(); foreach (var piPoint in piPointList) { afValues.Add(piPoint.CurrentValue()); } foreach (var afValue in afValues) { _dt.Rows.Add(afValue.PIPoint.Name, (DateTime)afValue.Timestamp.LocalTime, afValue.Value, afValue.PIPoint.GetAttribute(PICommonPointAttributes.EngineeringUnits), afValue.GetAnnotation(), false, string.Empty); } this.Invoke(_dataGridCallback, _dt); while (chkShowSnapshot.Checked == true) { AFListResults <PIPoint, AFDataPipeEvent> pipeConstants = pipe.GetUpdateEvents(5000); foreach (AFDataPipeEvent pipeEvent in pipeConstants) { foreach (DataRow row in _dt.Rows) { if (row["Tag"] == pipeEvent.Value.PIPoint.Name) { row["Timestamp"] = pipeEvent.Value.Timestamp.LocalTime; row["Value"] = pipeEvent.Value.Value; row["UOM"] = pipeEvent.Value.PIPoint.GetAttribute(PICommonPointAttributes.EngineeringUnits); row["Annotation"] = pipeEvent.Value.GetAnnotation(); } } } if (this.dataGrid.InvokeRequired) { this.Invoke(_dataGridCallback, _dt); } else { dataGrid.DataSource = _dt; dataGrid.Refresh(); } } ; pipe.Close(); pipe.Dispose(); }
public static void Run(PIServer piserver) { //Constructs a new PIDataPipe to signup for events on a list of PIPoint objects PIDataPipe piDP_A = new PIDataPipe(AFDataPipeType.TimeSeries); try { //List of PIPoints var ptListNames = new List <string> { "sinusoid", "CDT158", "CDT158Testt" }; var ptList = PIPoint.FindPIPoints(piserver, ptListNames.AsEnumerable()); //Find Tags Available in the DataArchive foreach (var val in ptListNames) { if ((PIPoint.TryFindPIPoint(piserver, val, out PIPoint point) == false)) { Console.WriteLine("Tag Has been DELETED: {0}", val.ToString()); } } Console.ReadLine(); //PIDataPipe1 //Moved below line above try block //PIDataPipe piDP_A = new PIDataPipe(AFDataPipeType.TimeSeries); //Take Returns a specified number of contiguous elements from the start of a sequence. var errPIa = piDP_A.AddSignups(ptList.Take(2).ToList()); var observerpiA = new Pipe_Observer("observerpiA"); // registering an Iobserver for ADDataPipeEvent with the PIDataPipe. All the AFDataPipeEvents received by the data pipe will // be sent to the IObserver. piDP_A.Subscribe(observerpiA); //using 3 minutes time to gracefully exiting and showing how dispose is working in finally block DateTime start = DateTime.Now; while (true && DateTime.Now.Subtract(start).Minutes < 3) { bool hasMorePiA; //Get updates.... Trigger retrival of new events var PIa = piDP_A.GetObserverEvents(100, out hasMorePiA); // out hasMorePiA - Indicates whether there could be more events in the pipe. hasMorePiA is set to true whenever the number of result // events reach maxEventCountPerServer for any one PI Data Archive within the pipe. if (hasMorePiA == true) { Console.WriteLine("the number of result events reach maxEventCountPerServer for any one PI Data Archive within the pipe"); } // while (hasMorePiA) ; } } catch (Exception ex) { Logs Err = new Logs(); Err.MyLogFile(ex); Console.WriteLine("An Error has occured for details please check the Log File:'" + ex.Message + "'"); Console.ReadLine(); } finally { //close – which will terminate the data pipes connection to the PI Servers associated with the monitored PI Point Object //Dispose - which will terminate the data pipes connection to the PI Servers associated with the monitored PI Point Object. //This method also releases the resources used by the PIDataPipe piDP_A.Close(); piDP_A.Dispose(); } }
}//GetDataFromPipe private void KillDataPipe() { //This method properly destroys the data pipe and should be called on shutdown. snapshotPipe.Close(); snapshotPipe.Dispose(); }//KillDataPipe
internal void Execute(string command, PIPointList pointsList, AFTime st, AFTime et, AFTimeSpan summaryDuration, string[] times, string addlparam1, PIServer myServer) { try { Console.WriteLine(); switch (command) { case "snap": { var sb = new StringBuilder(); sb.AppendLine($"Point Name(Point Id), Timestamp, Current Value"); sb.AppendLine(new string('-', 45)); AFListResults <PIPoint, AFValue> results = pointsList.EndOfStream(); if (results.HasErrors) { foreach (var e in results.Errors) { sb.AppendLine($"{e.Key}: {e.Value}"); } } foreach (var v in results.Results) { if (!results.Errors.ContainsKey(v.PIPoint)) { sb.AppendLine($"{string.Concat($"{v.PIPoint.Name} ({v.PIPoint.ID})"),-15}," + $" {v.Timestamp}, {v.Value}"); } } sb.AppendLine(); Console.Write(sb.ToString()); break; } case "arclist": { AFTimeRange timeRange = new AFTimeRange(st, et); if (!Int32.TryParse(addlparam1, out int maxcount)) { maxcount = 0; } // Holds the results keyed on the associated point var resultsMap = new Dictionary <PIPoint, AFValues>(); var pagingConfig = new PIPagingConfiguration(PIPageType.TagCount, GlobalConfig.PageSize); IEnumerable <AFValues> listResults = pointsList.RecordedValues(timeRange: timeRange, boundaryType: AFBoundaryType.Inside, filterExpression: null, includeFilteredValues: false, pagingConfig: pagingConfig, maxCount: maxcount ); foreach (var pointResults in listResults) { resultsMap[pointResults.PIPoint] = pointResults; } foreach (var pointValues in resultsMap) { var sb = new StringBuilder(); sb.AppendLine($"Point: {pointValues.Key} Archive Values " + $"Count: {pointValues.Value.Count}"); sb.AppendLine(new string('-', 45)); pointValues.Value.ForEach(v => sb.AppendLine($"{v.Timestamp}, {v.Value}")); sb.AppendLine(); Console.Write(sb.ToString()); } break; } case "plot": { AFTimeRange timeRange = new AFTimeRange(st, et); if (!Int32.TryParse(addlparam1, out int intervals)) { intervals = 640; //horizontal pixels in the trend } var resultsMap = new Dictionary <PIPoint, AFValues>(); var pagingConfig = new PIPagingConfiguration(PIPageType.TagCount, GlobalConfig.PageSize); IEnumerable <AFValues> listResults = pointsList.PlotValues(timeRange: timeRange, intervals: intervals, pagingConfig: pagingConfig ); foreach (var pointResults in listResults) { resultsMap[pointResults.PIPoint] = pointResults; } foreach (var pointValues in resultsMap) { var sb = new StringBuilder(); sb.AppendLine($"Point: {pointValues.Key} Plot Values Interval: {intervals}" + $" Count: {pointValues.Value.Count}"); sb.AppendLine(new string('-', 45)); pointValues.Value.ForEach(v => sb.AppendLine($"{v.Timestamp}, {v.Value}")); sb.AppendLine(); Console.Write(sb.ToString()); } break; } case "interp": { AFTimeRange timeRange = new AFTimeRange(st, et); var resultsMap = new Dictionary <PIPoint, AFValues>(); var pagingConfig = new PIPagingConfiguration(PIPageType.TagCount, GlobalConfig.PageSize); if (addlparam1.StartsWith("c=")) { if (!Int32.TryParse(addlparam1.Substring(2), out int count)) { count = 10; //default count } IEnumerable <AFValues> listResults = pointsList.InterpolatedValuesByCount(timeRange: timeRange, numberOfValues: count, filterExpression: null, includeFilteredValues: false, pagingConfig: pagingConfig ); foreach (var pointResults in listResults) { resultsMap[pointResults.PIPoint] = pointResults; } foreach (var pointValues in resultsMap) { var sb = new StringBuilder(); sb.AppendLine($"Point: {pointValues.Key} Interpolated Values " + $"Count: {pointValues.Value.Count}"); sb.AppendLine(new string('-', 45)); pointValues.Value.ForEach(v => sb.AppendLine($"{v.Timestamp}, {v.Value}")); sb.AppendLine(); Console.Write(sb.ToString()); } } else { if (!AFTimeSpan.TryParse(addlparam1, out AFTimeSpan interval) || interval == new AFTimeSpan(0)) { interval = summaryDuration; } IEnumerable <AFValues> listResults = pointsList.InterpolatedValues(timeRange: timeRange, interval: interval, filterExpression: null, includeFilteredValues: false, pagingConfig: pagingConfig ); foreach (var pointResults in listResults) { resultsMap[pointResults.PIPoint] = pointResults; } foreach (var pointValues in resultsMap) { var sb = new StringBuilder(); sb.AppendLine($"Point: {pointValues.Key} Interpolated Values " + $"Interval: {interval.ToString()}"); sb.AppendLine(new string('-', 45)); pointValues.Value.ForEach(v => sb.AppendLine($"{v.Timestamp}, {v.Value}")); sb.AppendLine(); Console.Write(sb.ToString()); } } break; } case "summaries": { var resultsMap = new Dictionary <PIPoint, AFValues>(); var pagingConfig = new PIPagingConfiguration(PIPageType.TagCount, GlobalConfig.PageSize); if (st > et) //summaries cannot handle reversed times { var temp = st; st = et; et = temp; } AFTimeRange timeRange = new AFTimeRange(st, et); var intervalDefinitions = new AFTimeIntervalDefinition(timeRange, 1); AFCalculationBasis calculationBasis = AFCalculationBasis.EventWeighted; if (addlparam1 == "t") { calculationBasis = AFCalculationBasis.TimeWeighted; } foreach (var pt in pointsList) { var summaryType = AFSummaryTypes.All; if (pt.PointType == PIPointType.Digital || pt.PointType == PIPointType.Timestamp || pt.PointType == PIPointType.Blob || pt.PointType == PIPointType.String || pt.PointType == PIPointType.Null) { summaryType = AFSummaryTypes.AllForNonNumeric; } IDictionary <AFSummaryTypes, AFValues> summaries = pt.Summaries(new List <AFTimeIntervalDefinition>() { intervalDefinitions }, reverseTime: false, summaryType: summaryType, calcBasis: calculationBasis, timeType: AFTimestampCalculation.Auto ); var sb = new StringBuilder(); sb.AppendLine($"Point: {pt.Name} {calculationBasis} Summary"); sb.AppendLine(new string('-', 45)); foreach (var s in summaries) { AFValues vals = s.Value; foreach (var v in vals) { if (v.Value.GetType() != typeof(PIException)) { if (string.Compare(s.Key.ToString(), "Minimum", true) == 0 || string.Compare(s.Key.ToString(), "Maximum", true) == 0) { sb.AppendLine($"{s.Key,-16}: {v.Value,-20} {v.Timestamp}"); } else { sb.AppendLine($"{s.Key,-16}: {v.Value}"); } } else { sb.AppendLine($"{s.Key,-16}: {v}"); } } } sb.AppendLine(); Console.Write(sb.ToString()); } /* * Non numeric tags in pointsList requires splitting of queries so the above is preferred. * The below implementation works when there are no non-numeric types or one particular summary needs to be run */ //var listResults = pointsList.Summaries(new List<AFTimeIntervalDefinition>() { // intervalDefinitions }, // reverseTime: false, // summaryTypes: AFSummaryTypes.All, // calculationBasis: calculationBasis, // timeType: AFTimestampCalculation.Auto, // pagingConfig: pagingConfig // ); //foreach (IDictionary<AFSummaryTypes, AFValues> summaries in listResults) //{ // foreach (IDictionary<AFSummaryTypes, AFValues> pointResults in listResults) // { // AFValues pointValues = pointResults[AFSummaryTypes.Average]; // PIPoint point = pointValues.PIPoint; // //Map the results back to the point // resultsMap[point] = pointValues; // } //} break; } case "update": case "annotate": { string addlparam2 = string.Empty; AFUpdateOption updateOption = AFUpdateOption.Replace; AFBufferOption bufOption = AFBufferOption.BufferIfPossible; AFValue val; if (times.Length > 0) { addlparam1 = times[0]; if (times.Length > 1) { addlparam2 = times[1]; } } switch (addlparam1) { case "i": updateOption = AFUpdateOption.Insert; break; case "nr": updateOption = AFUpdateOption.NoReplace; break; case "ro": updateOption = AFUpdateOption.ReplaceOnly; break; case "inc": updateOption = AFUpdateOption.InsertNoCompression; break; case "rm": updateOption = AFUpdateOption.Remove; break; } switch (addlparam2) { case "dnb": bufOption = AFBufferOption.DoNotBuffer; break; case "buf": bufOption = AFBufferOption.Buffer; break; } foreach (var pt in pointsList) { Console.WriteLine($"Point: {pt.Name} {command} ({updateOption} {bufOption})"); Console.WriteLine(new string('-', 45)); Console.Write("Enter timestamp: "); var time = Console.ReadLine(); if (!AFTime.TryParse(time, out AFTime ts)) { ParseArgs.PrintHelp("Invalid Timestamp"); break; } if (command == "update" || !(pt.RecordedValuesAtTimes(new List <AFTime>() { ts }, AFRetrievalMode.Exact)[0].IsGood)) { Console.Write("Enter new value: "); var data = Console.ReadLine(); if (!Double.TryParse(data, out var value)) { ParseArgs.PrintHelp("Invalid data"); break; } val = new AFValue(value, ts); } else { val = pt.RecordedValuesAtTimes(new List <AFTime>() { ts }, AFRetrievalMode.Exact)[0]; } if (command == "annotate") { Console.Write("Enter annotation: "); var ann = Console.ReadLine(); pt.SetAnnotation(val, ann); } pt.UpdateValue(value: val, option: updateOption, bufferOption: bufOption); Console.WriteLine($"Successfully {command}d"); } Console.WriteLine(); break; } case "delete": { AFTimeRange timeRange = new AFTimeRange(st, et); if (myServer.Supports(PIServerFeature.DeleteRange)) { foreach (var pt in pointsList) { int delcount = 0; var sb = new StringBuilder(); var intervalDefinitions = new AFTimeIntervalDefinition(timeRange, 1); //getting the count of events - optional IDictionary <AFSummaryTypes, AFValues> summaries = pt.Summaries(new List <AFTimeIntervalDefinition>() { intervalDefinitions }, reverseTime: false, summaryType: AFSummaryTypes.Count, calcBasis: AFCalculationBasis.EventWeighted, timeType: AFTimestampCalculation.Auto ); foreach (var s in summaries) { AFValues vals = s.Value; vals = s.Value; foreach (var v in vals) { if (v.Value.GetType() != typeof(PIException)) { delcount = v.ValueAsInt32(); //count } } } if (delcount > 0) { var errs = pt.ReplaceValues(timeRange, new List <AFValue>() { }); if (errs != null) { foreach (var e in errs.Errors) { sb.AppendLine($"{e.Key}: {e.Value}"); delcount--; } } } sb.AppendLine($"Point: {pt.Name} Deleted {delcount} events"); sb.AppendLine(new string('-', 45)); sb.AppendLine(); Console.Write(sb.ToString()); } } else { foreach (var pt in pointsList) { int delcount = 0; var sb = new StringBuilder(); AFValues vals = pt.RecordedValues(timeRange: timeRange, boundaryType: AFBoundaryType.Inside, filterExpression: null, includeFilteredValues: false, maxCount: 0 ); delcount = vals.Count; if (delcount > 0) { var errs = pt.UpdateValues(values: vals, updateOption: AFUpdateOption.Remove, bufferOption: AFBufferOption.BufferIfPossible); if (errs != null) { foreach (var e in errs.Errors) { sb.AppendLine($"{e.Key}: {e.Value}"); delcount--; } } } sb.AppendLine($"Point: {pt.Name} Deleted {delcount} events"); sb.AppendLine(new string('-', 45)); sb.AppendLine(); Console.Write(sb.ToString()); } } break; } case "sign,t": { Dictionary <PIPoint, int> errPoints = pointsList.ToDictionary(key => key, value => 0); //if (Int32.TryParse(myServer.ServerVersion.Substring(4, 3), out int srvbuild) && srvbuild >= 395); if (myServer.Supports(PIServerFeature.TimeSeriesDataPipe)) { PIDataPipe timeSeriesDatapipe = new PIDataPipe(AFDataPipeType.TimeSeries); Console.WriteLine("Signing up for TimeSeries events"); var errs = timeSeriesDatapipe.AddSignups(pointsList); if (errs != null) { foreach (var e in errs.Errors) { Console.WriteLine($"Failed timeseries signup: {e.Key}, {e.Value.Message}"); errPoints[e.Key]++; } foreach (var ep in errPoints) { if (ep.Value >= 1) { pointsList.Remove(ep.Key); } } if (pointsList.Count == 0) { ParseArgs.PrintHelp("No valid PI Points"); if (timeSeriesDatapipe != null) { timeSeriesDatapipe.Close(); timeSeriesDatapipe.Dispose(); } return; } } timeSeriesDatapipe.Subscribe(new DataPipeObserver("TimeSeries")); Console.WriteLine("Subscribed Points (current value): "); AFListResults <PIPoint, AFValue> results = pointsList.EndOfStream(); if (results.HasErrors) { foreach (var e in results.Errors) { Console.WriteLine($"{e.Key}: {e.Value}"); } } foreach (var v in results.Results) { if (!results.Errors.ContainsKey(v.PIPoint)) { Console.WriteLine($"{v.PIPoint.Name,-12}, {v.Timestamp}, {v.Value}"); } } Console.WriteLine(new string('-', 45)); //Fetch timeseries events till user termination while (!GlobalConfig.CancelSignups) { timeSeriesDatapipe.GetObserverEvents(GlobalConfig.PipeMaxEvtCount, out bool hasMoreEvents); Thread.Sleep(GlobalConfig.PipeCheckFreq); } Console.WriteLine("Cancelling signups ..."); if (timeSeriesDatapipe != null) { timeSeriesDatapipe.Close(); timeSeriesDatapipe.Dispose(); } } else { ParseArgs.PrintHelp($"Time series not supported in Archive version {myServer.ServerVersion}"); } break; } case "sign,as": case "sign,sa": case "sign,a": case "sign,s": { bool snapSubscribe = false; bool archSubscribe = false; PIDataPipe snapDatapipe = null; PIDataPipe archDatapipe = null; Dictionary <PIPoint, int> errPoints = pointsList.ToDictionary(key => key, value => 0); if (command.Substring(5).Contains("s")) { snapSubscribe = true; snapDatapipe = new PIDataPipe(AFDataPipeType.Snapshot); Console.WriteLine("Signing up for Snapshot events"); var errs = snapDatapipe.AddSignups(pointsList); snapDatapipe.Subscribe(new DataPipeObserver("Snapshot")); if (errs != null) { foreach (var e in errs.Errors) { Console.WriteLine($"Failed snapshot signup: {e.Key}, {e.Value.Message}"); errPoints[e.Key]++; } } } if (command.Substring(5).Contains("a")) { archSubscribe = true; archDatapipe = new PIDataPipe(AFDataPipeType.Archive); Console.WriteLine("Signing up for Archive events"); var errs = archDatapipe.AddSignups(pointsList); if (errs != null) { foreach (var e in errs.Errors) { Console.WriteLine($"Failed archive signup: {e.Key}, {e.Value.Message}"); errPoints[e.Key]++; } } archDatapipe.Subscribe(new DataPipeObserver("Archive ")); } //remove unsubscribable points int errorLimit = snapSubscribe ? 1 : 0; if (archSubscribe) { errorLimit++; } foreach (var ep in errPoints) { if (ep.Value >= errorLimit) { pointsList.Remove(ep.Key); } } if (pointsList.Count == 0) { ParseArgs.PrintHelp("No valid PI Points"); if (snapDatapipe != null) { snapDatapipe.Close(); snapDatapipe.Dispose(); } if (archDatapipe != null) { archDatapipe.Close(); archDatapipe.Dispose(); } return; } Console.WriteLine("Subscribed Points (current value): "); //foreach (var p in pointsList) //{ // Console.WriteLine($"{p.Name,-12}, {p.EndOfStream().Timestamp}, {p.EndOfStream()}"); //} AFListResults <PIPoint, AFValue> results = pointsList.EndOfStream(); if (results.HasErrors) { foreach (var e in results.Errors) { Console.WriteLine($"{e.Key}: {e.Value}"); } } foreach (var v in results.Results) { if (!results.Errors.ContainsKey(v.PIPoint)) { Console.WriteLine($"{v.PIPoint.Name,-12}, {v.Timestamp}, {v.Value}"); } } Console.WriteLine(new string('-', 45)); //Fetch events from the data pipes while (!GlobalConfig.CancelSignups) { if (snapSubscribe) { snapDatapipe.GetObserverEvents(GlobalConfig.PipeMaxEvtCount, out bool hasMoreEvents1); } if (archSubscribe) { archDatapipe.GetObserverEvents(GlobalConfig.PipeMaxEvtCount, out bool hasMoreEvents2); } Thread.Sleep(GlobalConfig.PipeCheckFreq); } Console.WriteLine("Cancelling signups ..."); if (snapDatapipe != null) { snapDatapipe.Close(); snapDatapipe.Dispose(); } if (archDatapipe != null) { archDatapipe.Close(); archDatapipe.Dispose(); } } break; } Console.WriteLine(new string('~', 45)); } catch (Exception ex) { ParseArgs.PrintHelp(ex.Message); if (myServer != null) { myServer.Disconnect(); if (GlobalConfig.Debug) { Console.WriteLine($"Disconnecting from {myServer.Name}"); } } } }
public void PIDataPipeTimeSeriesTest(PIPointType piPointType, object[] eventValues) { Contract.Requires(eventValues != null); const string PointName = "PIDataPipeTests_PIPoint"; AFDatabase db = AFFixture.AFDatabase; PIServer piServer = PIFixture.PIServer; var piDataPipe = new PIDataPipe(AFDataPipeType.TimeSeries); var piPointList = new PIPointList(); var now = AFTime.NowInWholeSeconds; try { Output.WriteLine("Create the Future PI Points with Zero Compression and specified PI Point type."); PIFixture.DeletePIPoints(PointName + "*", Output); var testPIPoints = PIFixture.CreatePIPoints(PointName + "###", eventValues.Length, new Dictionary <string, object> { { PICommonPointAttributes.PointType, piPointType }, { PICommonPointAttributes.ExceptionDeviation, 0 }, { PICommonPointAttributes.ExceptionMaximum, 0 }, { PICommonPointAttributes.Compressing, 0 }, { PICommonPointAttributes.DigitalSetName, "Phases" }, { PICommonPointAttributes.Future, true }, }); Assert.True(testPIPoints.Count() == eventValues.Length, $"Unable to create all the test PI Points."); piPointList.AddRange(testPIPoints); // Add the PI Point as sign up to the PIDataPipe. Output.WriteLine($"Sign up all PI Points with PIDataPipe."); var afErrors = piDataPipe.AddSignups(piPointList); var prefixErrorMessage = "Adding sign ups to the PIDataPipe was unsuccessful."; Assert.True(afErrors == null, userMessage: afErrors?.Errors.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] ")); // Write one data value to each PI Point. var expectedAFValues = new AFValues(); for (int i = 0; i < eventValues.Length; i++) { AFValue afValue = null; var timestamp = now + TimeSpan.FromMinutes(i - eventValues.Length); // Special Handling of Input Data for Digital and Timestamp switch (piPointType) { case PIPointType.Digital: afValue = new AFValue(new AFEnumerationValue("Phases", (int)eventValues[i]), timestamp); break; case PIPointType.Timestamp: afValue = new AFValue(new AFTime(eventValues[i], now), timestamp); break; default: afValue = new AFValue(eventValues[i], timestamp); break; } Output.WriteLine($"Writing Value [{eventValues[i]}] with Timestamp [{timestamp}] to PI Point [{piPointList[i].Name}]."); piPointList[i].UpdateValue(afValue, AFUpdateOption.InsertNoCompression); // If writing digital states, we need to save the corresponding value for verification. // Since we are using Phases, 0 ~ Phase1, 1 ~ Phase2, etc. if (piPointType == PIPointType.Digital) { int input = (int)eventValues[i]; afValue = new AFValue(new AFEnumerationValue($"Phase{input + 1}", input), timestamp); } afValue.PIPoint = piPointList[i]; expectedAFValues.Add(afValue); } // Retry assert to retrieve expected Update Events from the PIDataPipe var actualAFValues = new AFValues(); Output.WriteLine($"Reading Events from the PI DataPipe."); AssertEventually.True(() => { var updateEvents = piDataPipe.GetUpdateEvents(eventValues.Length); prefixErrorMessage = "Retrieving Update Events from the PIDataPipe was unsuccessful."; Assert.False(updateEvents.HasErrors, userMessage: updateEvents.Errors?.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] ")); actualAFValues.AddRange(updateEvents.Results.Select(update => update.Value)); if (actualAFValues.Count >= expectedAFValues.Count) { // Verify that all expected update events are received from the PIDataPipe Assert.True(expectedAFValues.Count == actualAFValues.Count, "PIDataPipe returned more events than expected. " + $"Expected Count: {expectedAFValues.Count}, Actual Count: {actualAFValues.Count}."); return(true); } return(false); }, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(0.5), "Unable to retrieve events within the time frame."); // Verify all received events. Output.WriteLine($"Verifying all {actualAFValues.Count} events from the PI DataPipe."); for (int i = 0; i < actualAFValues.Count; i++) { // Special handling of Output events for Timestamp if (piPointType == PIPointType.Timestamp) { actualAFValues[i].Value = new AFTime(actualAFValues[i].Value, now); } AFFixture.CheckAFValue(actualAFValues[i], expectedAFValues[i]); Assert.True(object.Equals(actualAFValues[i].PIPoint, expectedAFValues[i].PIPoint), $"Unexpected PI Point Association. Expected: [{expectedAFValues[i].PIPoint}], Actual: [{actualAFValues[i].PIPoint}]."); } // Remove all sign ups from the PIDataPipe Output.WriteLine($"Remove all PI Point sign ups from PIDataPipe."); afErrors = piDataPipe.RemoveSignups(piPointList); prefixErrorMessage = "Removing sign ups to the PIDataPipe was unsuccessful."; Assert.True(afErrors == null, userMessage: afErrors?.Errors.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] ")); // Write dummy values to the PI Points and confirm PI DataPipe receives none. Output.WriteLine($"Write dummy values to the PI Points."); for (int i = 0; i < eventValues.Length; i++) { piPointList[i].UpdateValue(new AFValue(eventValues[i], now), AFUpdateOption.InsertNoCompression); } Output.WriteLine($"Verify no events are received by the PIDataPipe."); var noEvents = piDataPipe.GetUpdateEvents(eventValues.Length); prefixErrorMessage = "Retrieving Update Events from the PIDataPipe was unsuccessful."; Assert.False(noEvents.HasErrors, userMessage: noEvents.Errors?.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] ")); Assert.True(noEvents.Count == 0, "PIDataPipe received events even after removing all sign ups."); } finally { piDataPipe.RemoveSignups(piPointList); piDataPipe.Dispose(); PIFixture.DeletePIPoints(PointName + "*", Output); } }