6 Replies Latest reply on Apr 27, 2018 3:14 PM by gregor

    SQC chart control limit data in C#

    Dhiman

      Hi,

      I am a .NET C# developer and developing an application to show a chart similar to the SQC chart in from PI data base.

      I am using .NET AFSDK to connect to PI and get the data.

      But I am not able to see any API in the AFSDK to pickup various control limit data for UCL, USL, LCL, CL etc.

       

      Can you please help me in getting these data from the PI data store so that the .NET charts can be plotted?

       

      Please forgive my ignorance as this is the first time I am developing applications for PI data base.

       

      Thanks,

      Dhiman

        • Re: SQC chart control limit data in C#
          wpribula

          Hello Dhinam,

          Question is where are these limits stored? DO you ave them in some tag, or in some configuration parameter, or do you have Attributes for them under Attribute which is using them?

          • Re: SQC chart control limit data in C#
            gregor

            Hello Dhiman,

             

            Welcome to our PI Developers Club community! There is no need to apologize.

             

            I admit that I had to refresh my knowledge about the good old PI Alarm Subsystem and I did this by looking at the corresponding chapters in the PI Data Archive 2017 R2 Applications User Guide.

            Because PI Alarm Subsystem belongs to the PI Data Archive, I also checked the PI Hierarchy in AF SDK Reference but didn't see anything specific on the subject.

             

            PI SQC Alarm points are using point class SQC_Alarm and (by default) the PointSource is 'Q'. Limits (UCL, LCL etc.) are stored with separate PI Points. You find those points defined with the corresponding point attributes (UCLTag, LCLTag etc.) With other words, to get the limits of an SQC Alarm point, you first need to load the point attributes and check its values, load referenced points and e.g. their current values.

             

            Do you need some sample code to get started?

            Can you share more information about what you like to accomplish?

             

            I am uncertain about our current recommendation but would assume that we suggest using Asset Analytics to capture Event Frames whenever certain conditions are met. Have you looked into this option? I have been looking around and found Asset Based PI Example Kit for Condition Monitoring could be a good example for you.

              • Re: SQC chart control limit data in C#
                PritamH

                Hi Gregor,

                I am also from same team (Dhiman's team), in current process book application SQC Chart is populated and get data from one tag only, but when I checked in PI SQL Commander, SQC_Alarm table is showing empty. So I am not able to understand how the tag retrieve and populate data to current application from PI database.

                 

                Can you please guide me in getting these data from the PI data store ?

                 

                Thanks,

                Pritam Hazra

              • Re: SQC chart control limit data in C#
                gregor

                Hello Dhiman,

                Hello Pritam,

                 

                The following sample illustrates how you would read the limits for PI Points with point class SQC_Alarm. Together with the inline comments it should be clear what the code is doing and why. If not, please ask.

                 

                I am planning to share a sample for point class Alarm too.

                 

                using OSIsoft.AF.PI;
                using System;
                using System.Linq;
                
                namespace T36350
                {
                    class Program
                    {
                        static void Main(string[] args)
                        {
                            // The server object
                            var piDAHost = "GB-PIDA1";
                            var piSrv = new PIServers()[piDAHost];
                
                            // The SQC Class object
                            var sqcClassName = "SQC_Alarm";
                            var sqcClass = piSrv.PointClasses[sqcClassName];
                
                            // Complete list of Class Attribute names
                            var sqcClassAttributes = sqcClass.GetAttributes().Keys.ToArray<string>();
                            var queryString = string.Format("ptclassname:{0}", sqcClassName);
                
                            // Find all SQC_Alarm points and include loading the point Attributes
                            var sqcPoints = PIPoint.FindPIPoints(piSrv, queryString, false, sqcClassAttributes, OSIsoft.AF.Search.AFSearchTextOption.ExactMatch);
                
                            // Loop through SQC_Alarm points
                            foreach (var sqcPoint in sqcPoints)
                            {
                                // Print the points name to console
                                Console.WriteLine("SQC Point: {0}", sqcPoint.Name);
                
                                // Loop through the point attributes defined in SQC_Alarm class
                                foreach(var attr in sqcClassAttributes)
                                {
                
                                    // We are only interested in the Attributes referencing a limit Tag
                                    if (attr.EndsWith("LTag"))
                                    {
                
                                        // Retrieve the attributes value. Should be the name of the point containing the limit
                                        var attrVal = sqcPoint.GetAttribute(attr).ToString();
                
                                        // Let's exclude empty (none existant) references
                                        if (attrVal != string.Empty)
                                        {
                
                                            // There's a chance the reference does not resolve a valid PI Point.
                                            // Let's take this situation into account by using a try-catch block
                                            try
                                            {
                
                                                // Find the PI Point
                                                var limitPoint = PIPoint.FindPIPoint(piSrv, attrVal);
                
                                                // Read its current value
                                                var limitValue = limitPoint.CurrentValue();
                
                                                // Focus on the Value property of the AFValue object
                                                var lValue = limitValue.Value;
                                                Console.ForegroundColor = ConsoleColor.White;
                
                                                // Print attribute name, name of the referenced PI Point
                                                // and the current limit value to console
                                                Console.WriteLine("  {0}: {1} has value: {2}", attr, attrVal, lValue);
                                            }
                                            catch (Exception ex)
                                            {
                
                                                // Inform about the issue using red color
                                                Console.ForegroundColor = ConsoleColor.Red;
                                                Console.WriteLine("Failed finding limitPoint '{0}': {1}", attrVal, ex.HResult);
                                            }
                                        }
                                    }
                                }
                            }
                
                            // Let's nicely inform the user that we are done but allow
                            // her / him to review what we found
                            Console.WriteLine();
                            Console.ForegroundColor = ConsoleColor.Gray;
                            Console.Write("Done. Press any key to quit .. ");
                            Console.ReadKey();
                        }
                    }
                }
                
                
                1 of 1 people found this helpful
                  • Re: SQC chart control limit data in C#
                    gregor

                    With PI Points of class Alarm, the limits are stored within test?, where ? represents a number between 1 and 5. But not just the limit values but the equation itself is stored. There are also action1..action5 which allow to pick an alert state from the assigned Digital State Set. This may sound confusing but is pretty simple after reading the belonging documentation.

                     

                    The following sample does not illustrate how to extract the numerical limits from the equation strings as I consider this a doable task for a developer.

                     

                    using OSIsoft.AF.PI;
                    using System;
                    using System.Collections.Generic;
                    using System.Linq;
                    
                    namespace T36350A
                    {
                        class Program
                        {
                            static void Main(string[] args)
                            {
                                // The server object
                                var piDAHost = "GB-PIDA1";
                                var piSrv = new PIServers()[piDAHost];
                    
                                // The Alarm Class object
                                var almClassName = "Alarm";
                                var almClass = piSrv.PointClasses[almClassName];
                    
                                // Complete list of Class Attribute names
                                var almClassAttributes = almClass.GetAttributes().Keys.ToArray<string>();
                                var queryString = string.Format("ptclassname:{0}", almClassName);
                    
                                // Find all SQC_Alarm points and include loading the point Attributes
                                var almPoints = PIPoint.FindPIPoints(piSrv, queryString, false, almClassAttributes, OSIsoft.AF.Search.AFSearchTextOption.ExactMatch);
                    
                                // Loop through SQC_Alarm points
                                foreach (var almPoint in almPoints)
                                {
                                   
                                    // Print the point name to console
                                    Console.WriteLine(almPoint.Name);
                    
                                    // Because I am not sure if attributes will be processed in order but also like
                                    // to avoid looping through them 3 times, let's use some "buffering"
                                    var testL = new List<string>();
                                    var actionL = new List<string>();
                                    var textL = new List<string>();
                    
                                    // Loop through the point attributes of Alarm class
                                    foreach (var attr in almClassAttributes)
                                    {
                                       
                                        // Get the attribute value
                                        var attrVal = almPoint.GetAttribute(attr).ToString();
                    
                                        // We are interested collecting all test? attributes with non-empty value
                                        if ((attr.StartsWith("test")) && (attrVal != string.Empty))
                                        {
                                            testL.Add(string.Format("    {0}: {1}", attr, attrVal));
                                        }
                                       
                                        // Here we take all non-empty action? attributes
                                        if ((attr.StartsWith("action")) && (attrVal != string.Empty))
                                        {
                                            actionL.Add(string.Format("    {0}: {1}", attr, attrVal));
                                        }
                                       
                                        // and this is for the (optional) text? attributes
                                        if ((attr.StartsWith("text")) && (attrVal != string.Empty))
                                        {
                                            textL.Add(string.Format("    {0}: {1}", attr, attrVal));
                                        }
                                    }
                    
                                    // Now process Attributes in categories of tests, actions and texts
                                    Console.WriteLine("  --> Tests ");
                                    foreach (var line in testL)
                                    {
                                        Console.WriteLine(line);
                                    }
                                    Console.WriteLine("  --> Actions");
                                    foreach (var line in actionL)
                                    {
                                        Console.WriteLine(line);
                                    }
                                    Console.WriteLine("  --> Texts");
                                    foreach (var line in textL)
                                    {
                                        Console.WriteLine(line);
                                    }
                                }
                    
                                // Let's nicely inform the user that we are done but allow
                                // her / him to review what we found
                                Console.WriteLine();
                                Console.ForegroundColor = ConsoleColor.Gray;
                                Console.Write("Done. Press any key to quit .. ");
                                Console.ReadKey();
                            }
                        }
                    }
                    
                    1 of 1 people found this helpful