9 Replies Latest reply on Jul 13, 2018 11:15 AM by jfigueras

    It's possible to get AFAttribute from a tag?

    jfigueras

      Hello,

       

      I need to execute this AF SDK code:

       

          AFAttribute attribute = ...
          IDictionary<AFSummaryTypes, AFValue> summary = attribute.Data.Summary(timeRange, AFSummaryTypes.Average, AFCalculationBasis.EventWeighted, AFTimestampCalculation.Auto);

       

      but I don't have any AFAtribute, I only have one tag.

       

      It's possible to get one AFAttribute for one tag (to fill "..." above, in my code example)?

       

      Thanks,

      Jose Figueras

        • Re: It's possible to get AFAttribute from a tag?
          Rick Davin

          Hi Jose,

           

          If you already have PIPoint object at your fingertips, you would use the PIPoint.Summary method.  It is possible to create tag-centric applications that never touch an AF Server, AFDatabase or assets in anyway.

          1 of 1 people found this helpful
            • Re: It's possible to get AFAttribute from a tag?
              jfigueras

              Hi Rick,

               

              Thanks for your answer, but seems PIPoint.Summary doesn't works for my use case (see my previous related question https://pisquare.osisoft.com/message/113048-re-theres-something-in-pi-sdk-equivalent-to-pi-datalinks-piadvcalcdatparam1param2param3param4average-event-weightedevent-weightedparam7param8param9param10-function).

               

              I need to use AF SDK, but I don't know how to get AFAttribute for one PIPoint tag.

                • Re: It's possible to get AFAttribute from a tag?
                  Rick Davin

                  The link I gave you before was for an AF SDK PIPoint object using an AF SDK Summary method.

                   

                  Can you explain what you have in code right now?  Do you already have a tag - specifically an AF SDK PIPoint object?  Or do all you have is a tag name?

                    • Re: It's possible to get AFAttribute from a tag?
                      jfigueras

                      Hi Rick,

                       

                      I only have a tag name.

                       

                      In other words, I need to "translate to AF SDK" this PI SDK code:

                       

                        Dim piserver As String = "<my-pi-server>"
                              Dim pdata As PISDK.PIData
                              Dim ipdata2 As PISDK.IPIData2
                              Dim nvalues As PISDKCommon.NamedValues
                      
                              Dim ptimeFrom As New PITimeServer.PITimeFormat()
                              ptimeFrom.FormatString = "dd/MM/yyyy hh:mm:ss"
                              ptimeFrom.InputString = "25/04/2017 23:00:00"
                      
                              Dim ptimeTo As New PITimeServer.PITimeFormat()
                              ptimeTo.FormatString = "dd/MM/yyyy hh:mm:ss"
                              ptimeTo.InputString = "26/04/2017 23:00:00"
                      
                              Dim ipisdk As New PISDK.PISDK
                              ipisdk.Servers(piserver).Open("")
                      
                              Dim plist As PISDK.PointList
                              plist = ipisdk.Servers(piserver).GetPoints("tag='<my-tag-name>'")
                      
                              Dim i As Integer
                              Dim j As Integer
                              Dim w As PISDK.PIValue
                              Dim x As PISDK.PIValues
                              For i = 1 To plist.Count
                                  pdata = plist(i).Data
                                  ipdata2 = pdata ' get pointer to IPIData2 Interface
                      
                                  w = ipdata2.Summary(ptimeFrom, ptimeTo, PISDK.ArchiveSummaryTypeConstants.astMean, PISDK.CalculationBasisConstants.cbEventWeighted)
                                  w = ipdata2.Summary(ptimeFrom, ptimeTo, PISDK.ArchiveSummaryTypeConstants.astAverage, PISDK.CalculationBasisConstants.cbEventWeighted)
                      
                                  nvalues = ipdata2.Summaries2(ptimeFrom, ptimeTo, "1h", PISDK.ArchiveSummariesTypeConstants.asAverage, PISDK.CalculationBasisConstants.cbEventWeighted)
                                  x = nvalues("Average").Value
                                  For j = 1 To x.Count
                                      Console.WriteLine(String.Format("27200112;{0};ININ;{1};S", ptimeFrom.LocalDate.AddHours(j).ToString("yyyyMMddHH"), x(j).Value))
                                  Next
                              Next
                      
                              ipisdk.Servers(piserver).Close()
                      

                       

                      This code retrieve slightly different values than PI-Datalink's PIAdvCalcDat(param1;param2;param3;param4;"average (event-weighted)";"event-weighted";param7;param8;param9;param10) function. And I hope retrieve correct values with AF SDK 2016.

                       

                      My current AF SDK code seems like this:

                       

                        string afServerName = "<my-af-server>";
                                  string piServerName = "<my-pi-server>";
                      
                                  PISystems piSystems = new PISystems();
                                  PISystem assetServer = piSystems[afServerName]; // pi asset server (AF)
                                  PIServers piServers = new PIServers();
                                  PIServer piServer = piServers[piServerName]; // pi data archive (PI)
                      
                                  NetworkCredential credential = new NetworkCredential("<my-login>", "<my-password>", "<my-domain>");
                                  piServer.Connect(credential, AFConnectionPreference.PreferPrimary, PIAuthenticationMode.WindowsAuthentication);
                                  assetServer.Connect(credential, AFConnectionPreference.PreferPrimary);
                      
                                  AFDatabase database = assetServer.Databases["<my-database->"];
                      
                                  AFTime st = new AFTime("2017-04-25 23:00:00");
                                  AFTime et = new AFTime(new AFTimeSpan(hours: 1).Add(st));
                                  AFTimeRange timeRange = new AFTimeRange(st, et);
                      
                                  AFAttribute attribute = (AFAttribute)AFAttribute.FindObject("?????????????????????????????????????????????");
                      
                                  IDictionary<AFSummaryTypes, AFValue> summary = attribute.Data.Summary(timeRange, AFSummaryTypes.Average, AFCalculationBasis.EventWeighted, AFTimestampCalculation.Auto);
                      

                       

                      Now, I don't know neither how to get a PIPoint from a tag name nor how to get an AFAttribute from a tag name...

                       

                      Regards,

                      Jose Figueras

                        • Re: It's possible to get AFAttribute from a tag?
                          Rick Davin

                          Hi Jose,

                           

                          A PI SDK app can be made as an AF SDK app, and never needs to touch an AF Server or AFDatabase.  If all your app does is interact with a PI Data Archive, I call it a tag-based application.  If you did have to interact with an AF Server, it would then be an asset-based application.  For the problem at hand, you want a tag-based application.  Therefore, you absolutely, positively need to abandon this notion that you must get an AFAttribute from a tag name.  This is a classical case of what developers call the XY Problem.  You are traveling down the wrong road.  The X is that you want to get an average for a PIPoint.  The Y is that you think you need an AFAttribute to do that, and you are fixated that you cannot do X without Y.  But for your needs, trying to do Y would be a horrible mistake.

                           

                          I don't know if you really must login with different credentials.  If you were using DataLink, it would default to the current Windows credentials.  My example will just worry about that.

                           

                          For these lines, we need to get rid of anything AF Server related because IT IS NOT NEEDED FOR YOUR APPLICATION.  So these lines:

                           

                          string afServerName = "<my-af-server>"; 
                          string piServerName = "<my-pi-server>"; 
                          PISystems piSystems = new PISystems(); 
                          PISystem assetServer = piSystems[afServerName]; // pi asset server (AF) 
                          PIServers piServers = new PIServers(); 
                          PIServer piServer = piServers[piServerName]; // pi data archive (PI) 
                          

                           

                           

                          Should be reduced to:

                           

                          string piServerName = "<my-pi-server>";  
                          PIServers piServers = new PIServers();  
                          PIServer piServer = piServers[piServerName]; // pi data archive (PI)  
                          

                           

                           

                          These lines can be completely eliminated as well, including the explicit login to the PIServer:

                           

                          NetworkCredential credential = new NetworkCredential("<my-login>", "<my-password>", "<my-domain>");  
                          piServer.Connect(credential, AFConnectionPreference.PreferPrimary, PIAuthenticationMode.WindowsAuthentication);  
                          assetServer.Connect(credential, AFConnectionPreference.PreferPrimary);  
                          AFDatabase database = assetServer.Databases["<my-database->"];  
                          

                           

                           

                          Now you need to add some new things to your app:

                           

                          string tagName = "<my-tag-name>";
                          PIPoint tag = PIPoint.FindPIPoint(piServer, tagName);  // An implicit connection to the PIServer will occur
                          

                           

                           

                          This gives us a OSIsoft.AF.PI.PIPoint object in code.  And we did it without touching an AF Server nor an AFDatabase, and most emphatically, without an AFAttribute.  Continuing with your app, I would alter the time stuff to be:

                           

                          AFTime st = new AFTime("2017-04-25 23:00:00");  
                          AFTime et = st + TimeSpan.FromHours(1);  
                          AFTimeRange timeRange = new AFTimeRange(st, et); 
                          

                           

                           

                          At this stage we have a PIPoint object and an AFTimeRange.  Now we need a data call.

                           

                          IDictionary<AFSummaryTypes, AFValue> summary = tag.Summary(timeRange, AFSummaryTypes.Average, AFCalculationBasis.EventWeighted, AFTimestampCalculation.Auto);  
                          

                           

                           

                          Now all that's left to do is to "unwrap" it from the dictionary to get AFValue:

                           

                          AFValue average = summary[AFSummaryTypes.Average];
                          

                           

                           

                          Which is now ready for display or whatever you want to do with that average.  The AFValue has properties such as Value (object), Timestamp (AFTime), and IsGood (bool) that should be helpful in those endeavors.  Putting all the code together (with some name changes on my end):

                           

                          string piDataArchiveName = "<my-pi-server>";
                          PIServers knownServersTable = new PIServers();
                          PIServer dataServer = knownServersTable[piDataArchiveName]; // pi data archive (PI)    
                          
                          string tagName = "<my-tag-name>";
                          PIPoint tag = PIPoint.FindPIPoint(dataServer, tagName);
                          
                          AFTime st = new AFTime("2017-04-25 23:00:00");
                          AFTime et = st + TimeSpan.FromHours(1);
                          AFTimeRange timeRange = new AFTimeRange(st, et);
                          
                          IDictionary<AFSummaryTypes, AFValue> summary = tag.Summary(timeRange, AFSummaryTypes.Average, AFCalculationBasis.EventWeighted, AFTimestampCalculation.Auto);
                          AFValue average = summary[AFSummaryTypes.Average];
                          
                          Console.WriteLine("Tag: {0}", tag.Name);
                          Console.WriteLine("TimeRange: From {0} to {1} LocalTime", timeRange.StartTime.LocalTime, timeRange.EndTime.LocalTime);
                          Console.WriteLine("Event Weighted Average: {0}", average.Value);
                          

                           

                           

                          Important to Remember: a tag-based application has no reason to read an AFAttribute.

                          5 of 5 people found this helpful
                            • Re: It's possible to get AFAttribute from a tag?
                              jfigueras

                              Hi Rick,

                               

                              Thanks a lot for your detailed explanation.

                               

                              But doesn't works for me... because this code returns values that doesn't match PI Datalink's function values (when I use Mode="average (event-weighted)" and CalcBasis="event-weighted").

                               

                              With this code, p.e., I get this average value:

                               

                                 58,7623152481882

                               

                              but, in PI Datalink 2016, for the same tag name and time range, I get this value:

                               

                                 59,671

                               

                              Perhaps I need to use another method, class or API?

                               

                              Regards,

                              Jose Figueras

                                • Re: It's possible to get AFAttribute from a tag?
                                  Rick Davin

                                  Hello Jose,

                                   

                                  Great to see you've finally abandoned the notion you require an attribute.  This is good progress.  What you need to understand is the difference between how AF SDK versus DataLink produce event-weighted results.

                                   

                                  AF SDK returns all recorded values within the time range.  This would be the equivalent of a PIPoint.RecordedValues call using an AFBoundaryType.Inside.  That is to say it, AF SDK Summary/Summaries call only use the values actually stored in the PI Data Archive. This creates a true event-weighted summary since it averages events actually found.

                                   

                                  DataLink can create interpolated values at the time range Start and End times.  If your archived values fall exactly on the Start or End, then those values are used and DataLink would match AF SDK.  But chances are events don't line up evenly at Start and End, in which case DataLink's calculation has added 2 events that are not in the PI Data Archive.  This creates a slightly skewed event-weighted summary.  Which means DataLink's value is wrong, and AF SDK's is correct.

                                   

                                  UPDATE:

                                  Now that you understand the difference between AF SDK's true event-weighted summary versus DataLink's skewed summary, there is a simple way to get AF SDK to interpolate on the time range boundary just like DataLink.  Use an AFCalculationBasis.EventWeightedIncludeBothEnds.  This gives you the additional 2 fabricated events that DataLink uses.

                                   

                                  In the long run, I think it would be better understand why DataLink's interpolated boundary answer is wrong and accept that AF SDK's actual archived events answer is better.

                                  2 of 2 people found this helpful