21 Replies Latest reply on Mar 2, 2015 3:16 PM by viveks

    C# SDK - How to find the number of times a tag is under a certain value

    jscotti

      I need some help,

      I am trying to find the amount of times a tag is under a certain value for the past 30 days.

      I've posted my code below,

      It doesn't seem to be working because no matter what I change the expression to it always shows either 1 or 0

                  _pisdk = new PISDK.PISDK();
                  PISDK.Server piServer = _pisdk.Servers["SERVER"];
                  PISDK.Server myServer;
                  PISDK.PIPoints myPoints;
                  PISDK.PIPoint myPoint;
                  PISDK.PIData myPIdata;
                  PISDK.IPIData2 ipidata2;
                  PISDKCommon.NamedValues nvsSum;
                  PISDK.PIValues pvs;
                  myPoints = piServer.PIPoints;
                  myPoint = myPoints["TAG"];
                  myPIdata = myPoint.Data;
                  ipidata2 = myPIdata as PISDK.IPIData2;
                  string expression = "'TAG' < 40";
                  nvsSum = ipidata2.FilteredSummaries("*-30d", "*", "", expression, PISDK.ArchiveSummariesTypeConstants.asTotal, PISDK.CalculationBasisConstants.cbTimeWeighted, PISDK.FilterSampleTypeConstants.fstExpRecordedValues);
                  int p = nvsSum.Count;
      
      
        • Re: C# SDK
          Dan Fishman

          Maybe try nvsSum["total"].value[1].value

           

          That will give you back the value (might want make it a double).  Just nvsSum["total"].value[1] will return a PIValue.

           

          Regards,

          Dan

          • Re: C# SDK
            dng

            You can also use the PIData.RecordedValues method to find the number of time a tag is under a certain value (during a time period).

             

            e.g.

            PIValues sum = myPIdata.RecordedValues("*-30d", "*", BoundaryTypeConstants.btInside, expression, FilteredViewConstants.fvRemoveFiltered);
            int p = sum.Count;
            
            


            I have moved this post to the PI Developers Club > General Programming Languages subspace because community members there can best address your programming questions!

              • Re: C# SDK
                ashaw

                Another way:

                            PISDK.PISDK myPISDK;
                            myPISDK = new PISDK.PISDK();
                            PISDK.Server srv;
                            PISDK.PIPoint pt;
                            PISDK.PIValues values;
                            int count = 0;
                
                
                            srv = myPISDK.Servers.DefaultServer;
                            pt = srv.PIPoints["sinusoid"];
                            values = pt.Data.RecordedValues("1-jan-15", "10-jan-15");
                
                            foreach (PISDK.PIValue value in values)
                             {
                                Console.WriteLine(value.Value + " " + value.TimeStamp.LocalDate);
                                if (value.Value is Single && value.Value > 50)
                                {
                                    count++;
                                }
                             }
                            Console.WriteLine("Sinusoid was above 50 " + count + " times from 1-jan through 10-jan");
                            Console.ReadLine();
                
                  • Re: C# SDK
                    bperry

                    This does work, but whenever possible, it's best to get the PI Archive to filter the values server-side (as Daphne Ng recommended). This way the entire collection of values isn't pushed to the client.

                    1 of 1 people found this helpful
                • Re: C# SDK
                  Dan Fishman

                    Do you want to find the number of times the values is under 40 or the amount of time?

                   

                   

                  Dan

                  1 of 1 people found this helpful
                  • Re: C# SDK
                    Eugene Lee

                    Hi jscotti, if you want the number of times, you shouldn't use the asTotal. Instead, you should use asCount. I have tested the code below on my machine and it works well. I have also removed the declaration of MyServer since you didn't use it anywhere else.

                     

                                PISDK.PISDK _pisdk = new PISDK.PISDK();
                                PISDK.Server piServer = _pisdk.Servers.DefaultServer;
                                PISDK.PIPoints myPoints;
                                PISDK.PIPoint myPoint;
                                PISDK.PIData myPIdata;
                                PISDK.IPIData2 ipidata2;
                                PISDKCommon.NamedValues nvsSum;
                                PISDK.PIValues pvs;
                                myPoints = piServer.PIPoints;
                                myPoint = myPoints["cdt158"];
                                myPIdata = myPoint.Data;
                                ipidata2 = myPIdata as PISDK.IPIData2;
                                string expression = "'cdt158' < 400";
                                nvsSum = ipidata2.FilteredSummaries("*-30m", "*", null, expression, PISDK.ArchiveSummariesTypeConstants.asCount, PISDK.CalculationBasisConstants.cbEventWeighted, PISDK.FilterSampleTypeConstants.fstExpRecordedValues);
                                pvs = nvsSum["Count"].Value;
                                double n = pvs[1].Value;
                    

                     

                    This returns me a result of 1801 because all of my cdt158 events are under 400.

                      • Re: C# SDK - How to find the number of times a tag is under a certain value
                        Rick Davin

                        At risk of stating the obvious (or as least to most but not all readers), this correct answer works not just because of asCount but also because you use cbEventWeighted instead of cbTimeWeighted.  Both options used in tandem provide the proper answer.

                        1 of 1 people found this helpful
                          • Re: C# SDK - How to find the number of times a tag is under a certain value
                            Eugene Lee

                            Yes, and also in addition to that, here are some more calculation basis types from the PI SDK reference manual that you can use.

                             

                            cbTimeWeighted

                            Weight the values in the calculation by the time over which they apply. Interpolation is based on the step attribute of the point. Interpolated events are generated at the boundaries if necessary.

                            cbEventWeighted

                            Evaluate values with equal weighting for each event. No interpolation is done. There must be at least one event within the time range to perform a successful calculation. Two events are required for standard deviation.

                            In handling events at the boundary of the calculation, PISDK uses following OPC standard:

                            1) use events at both boundaries when there is only one calculation interval;

                            2) include events at start time in multiple intervals and the intervals are in ascending time order;

                            3) include events at the end time in multiple intervals and the intervals are in descending time order.

                            cbTimeWeightedContinuous

                            Apply weighting as in cbTimeWeighted, but do all interpolation between values as if they represent continuous data, (standard interpolation) regardless of the step attribute of the point.

                            cbTimeWeightedDiscrete

                            Apply weighting as in cbTimeWeighted but interpolation between values is performed as if they represent discrete, unrelated values (stair step plot) regardless of the step attribute of the point.

                            cbEventWeightedExcludeMostRecentEvent

                            The calculation behaves the same as cbEventWeighted, except in the handling of events at the boundary of summary intervals in a multiple intervals calculation. Use this option to prevent events at the intervals boundary from being double count at both intervals. With this option, events at the end time(most recent time) of an interval is not used in that interval.

                            cbEventWeightedExcludeEarliestEvent

                            Similar to the option cbEventWeightedExcludeMostRecentEvent. With this option, events at the start time(earliest time) of an interval is not used in that interval.

                            cbEventWeightedIncludeBothEnds

                            With this option, events at both ends of the interval boundaries are included in the event weighted calculation.

                        • Re: C# SDK
                          pthivierge

                          Hello Mr. Scotti,

                          Is there a reason why your are not using the AF SDK?  PI AF SDK is our latest technology, can connect to both PI Data Archive and AF.  It is regularly updated, benefits from newest technologies and is the recommended SDK to use for new projects.

                           

                          Having this said, in case you would like to achieve the same thing using the AF SDK, I am providing you an example.  The example gives the number of occurrences (Count) where cdt158 exceeded 170.

                           

                          Add a reference to OSIsoft.AFSDK

                           

                          using OSIsoft.AF;
                          using OSIsoft.AF.PI;
                          using OSIsoft.AF.Data;
                          using OSIsoft.AF.Time;
                          
                          

                           

                           

                          public static void FilteredSummariesExample()
                                  {
                                      var piserver = PIServer.FindPIServer("Optimus");
                                      piserver.Connect();
                          
                                      var point = PIPoint.FindPIPoint(piserver,"cdt158");
                                     
                                      var timeRange = new AFTimeRange("*-2h", "*");
                                      var res = point.FilteredSummaries(timeRange,
                                                              new AFTimeSpan(timeRange.Span),          // calculation window, since we want a single result, we make it equal to our time range
                                                              "'cdt158'>170",                          // true/false expression evaluated for one minute window
                                                              AFSummaryTypes.Count,                    // summary to return
                                                              AFCalculationBasis.EventWeighted,        // base
                                                              AFSampleType.ExpressionRecordedValues,   // sampling, interpolated or recorded values
                                                              AFTimeSpan.Zero,                         // Sampling interval, N/A in this case
                                                              AFTimestampCalculation.Auto              //
                                                              );
                          
                          
                                      Console.WriteLine(string.Format("Number of results:{0}", res[AFSummaryTypes.Count].Count));
                                      Console.WriteLine(string.Format("Number of times 'cdt158'>170 :{0}", res[AFSummaryTypes.Count].First().Value));
                          
                          
                                  }
                          
                          
                          • Re: C# SDK
                            jscotti


                            Thank you all for the quick responses, Eugenes answer is working for me

                            it was the pvs[1].Value that I needed

                             

                            Patrice , I plan to eventually modify all the legacy code into the AFSDK, just haven't had the time yet

                            • Re: C# SDK - How to find the number of times a tag is under a certain value
                              jscotti

                              Hey guys could you help me out one more time,  how would I also get the timestamp from every time this event occured?

                               

                               

                              Thanks

                                • Re: C# SDK - How to find the number of times a tag is under a certain value
                                  Dan Fishman

                                  If using the PI SDK try using the RecordedValues method.  See the PI SDK RecordedValues method for more information.


                                  RecordedValues StartTime, EndTime, BoundaryType, [FilterExp], [ShowFiltered], [AsyncStatus]

                                   

                                  This method returns a PIValues collection.  There are many similar posts on the PISquare and here is one of the first I found.  There are a number of samples using the AF SDK.  Let us know and we can provide a link to AF SDK code or work with you do get what works best.  Note, the filtering occurs on the PI Server. 

                                    • Re: C# SDK - How to find the number of times a tag is under a certain value
                                      dng

                                      Yep! I gave an example with recorded value on the second comment above.

                                       

                                                  PIValues vals = myPIdata.RecordedValues("*-1d", "*", BoundaryTypeConstants.btInside, expression, FilteredViewConstants.fvRemoveFiltered);
                                                  foreach (PIValue val in sum)
                                                  {
                                                      Console.WriteLine(val.TimeStamp.LocalDate);
                                                  }
                                      
                                        • Re: C# SDK
                                          Dan Fishman

                                          Ha!  Nice!  I should have just linked back to this thread.  How about a discussion on how to avoid duplicate data within the PI System .

                                           

                                          Dan


                                          • Re: C# SDK - How to find the number of times a tag is under a certain value
                                            jscotti

                                            thanks but this is not working, I'm passing the same expression from my filtered summaries but im getting an empty pivalues collection.

                                            I know it has happened at least once, the filtered summary asCount returns 6 times

                                            I cant get the timestamps from the FilteredSummaries function?

                                             

                                            _pisdk = new PISDK.PISDK();
                                            PISDK.Server piServer = _pisdk.Servers["server"];
                                             PISDK.PIPoint myPoint;
                                            PISDK.PIData myPIdata;
                                            PISDK.PIValues pvs;
                                              
                                             string results ="";
                                             string tag = "myTag";
                                             string setpoint = "40";
                                             string expression = "('" + tag + "'< " + setpoint + " AND prevval('" + tag + "',curtime) > " + setpoint + ")";
                                            
                                            myPoint = piServer.PIPoints[tag];
                                                    myPIdata = myPoint.Data;                    
                                                    pvs = myPIdata.RecordedValues("*-30d", "*", BoundaryTypeConstants.btInside, expression, FilteredViewConstants.fvRemoveFiltered);
                                                     foreach (PIValue val in pvs)
                                                                {                        
                                                                        results += val.TimeStamp.LocalDate.ToString() + ",";
                                            
                                                                }