26 Replies Latest reply on Jun 29, 2017 10:04 PM by Guilherme Ferreira

    How to get value of attributes from an event frame

    MikeSpath

      I'm trying to find a way via the AF SDK to get the value of the referenced elements associated with a found event frame. I thought the code below was the answer but it does not give the value that triggered the event but it just gives me the current attribute value of the referenced element.

       

                  AFEventFrameSearch search = new AFEventFrameSearch(db, "search", query);
      
                  //use new mehotd to GetTotalCount() without bringing back all EF headers. Fast and lower memory footprint 
                  MessageBox.Show(string.Format("Total EF match critiera: {0} ", search.GetTotalCount()));
      
      
                  //now actually bring back EF and full load- much more expensive call. 
                  IEnumerable<AFEventFrame> eventFameResults = search.FindEventFrames(0, true, int.MaxValue);
                  foreach(AFEventFrame ef in eventFameResults)
                  {
                      //ef.CaptureValues();
      
      
                      if (ef.CanBeAcknowledged && /*!ef.IsAcknowledged && */ ef.Name.Contains("DO"))
                      {
                          MessageBox.Show(ef.Name);
                          ef.Acknowledge();
      
                          // now get more details from the even from the referenced elements
                          foreach (AFElement elem in ef.ReferencedElements)
                          {
                              foreach (AFAttribute attrib in elem.Attributes)
                              {
                                  if (attrib.Name.Contains("DO"))
                                  {
                                      AFValue myValue = attrib.GetValue();
                                      MessageBox.Show(string.Format("DO:{0}",myValue.Value.ToString()));
                                  }
                              }
                          }
      
      
                      }
      
        • Re: How to get value of attributes from an event frame
          Rick Davin

          Hi Mike,

           

          Feel free to apply Syntax Highlight >> to your code.  I've done it for you the past couple of days.

           

          Let me give a HUGE WARNINGDO NOT USE int.MaxValue for the AFSearch pageSize parameter.  And that means DO NOT USE as in NEVER, EVER, EVER.  The AFSearch classes have built-in, transparent paging that will loop over everything being searched.  You are really pounding the client PC by trying to load everything at once, instead of 1000 or so one page at a time.  In fact, I suggest you keep it to 1000 and only then if you remove the MessageBox from the loop.  With a MessageBox holding things up for a human to respond, you may as well use a pageSize of 10.

           

          For a given event frame, you may inspect all of its ReferencedElements collection or just its PrimaryReferencedElement.  Pick that one that means the most to your app and is easiest for others to understand.

           

          One thing an element lacks that an event frame has is a time context.  Inside your innermost loop the attrib.GetValue() is getting the current value.  If you want to know the value when the event frame was started, that is to say what value was used for triggering, you must pass the event frame's StartTime to attrib.GetValue().

           

          AFValue myValue = attrib.GetValue(ef.StartTime); 
          3 of 3 people found this helpful
            • Re: How to get value of attributes from an event frame
              MikeSpath

              Thanks Rick:

              I will format the code as you specified, I was unaware of the rule, I will use from now on, as well as Page size.

              Mike

                • Re: How to get value of attributes from an event frame
                  Rick Davin

                  Hi Mike.

                   

                  Formatting the code on your end is optional.  We will do it for you when we come across it.  You have to admit it makes the post easier to read, so the easier it is to read might lead to a faster, better answer.  Doing it yourself when you create the post leads to possibility that your post is answered even quicker.

                   

                  Didn't mean to be too harsh on the int.MaxValue for pageSize.  Though it is horribly bad practice and can really hammer your network, the client PC, and be a big performance drag.

                   

                  As for the "meat" of the post, I trust you understand that you must pass in the ef.StartTime to see the trigger values.  One thing you want to add to your code is to enable server-side caching.  Immediately after Line 01, add:

                   

                  search.CacheTimeout = TimeSpan.FromMinutes(10);
                  

                   

                  If you feel your question has been answered, please mark your post accordingly.

                    • Re: How to get value of attributes from an event frame
                      MikeSpath

                      Yeah, that code is from our sandbox application used to quickly test stuff but good insight on how to use the AFSearch, I copied that code that had the int.max from another blog or post a while ago.

                        • Re: How to get value of attributes from an event frame
                          Rick Davin

                          Even with the older AFEventFrame.FindEventFrames method, using a maxCount of int.MaxValue is never recommended.  But pageSize with AFSearch is very different than maxCount.  See this post for more explanation:

                           

                          AFEventFrameSearch and paging

                            • Re: How to get value of attributes from an event frame
                              MikeSpath

                              I'm trying to also get child attributes using the start time of the event frame and it looks as if it is giving me the current value. Shouldn't I be able to send the event frame start time into the GetValue() call on a child attribute to get value at start time?

                                • Re: How to get value of attributes from an event frame
                                  Rick Davin

                                  Yes, Mike, you should be able to do so with any of these methods:

                                   

                                   

                                  If that is not working correctly, we need to see all the relevant code in order to diagnose further.

                                    • Re: How to get value of attributes from an event frame
                                      MikeSpath

                                      Hi Rick:

                                      I think that this is not working as I expect. I will try to illustrate here the best I can.

                                      * I have created a test element with a attribute value called CellCount tied to a pipoint.

                                      * This attribute has sub attributes that are used for users to setup the limits (HiHi, Hi, Lo, LoLo)

                                      * We provide a UI to the user to adjust the limits (sub Attributes)

                                      * The use case that I have done was to adjust the Hi limit in PSE to create an event frame

                                      * The application that I use as a sandbox has a button event handler routine that is shown below

                                      * When I run the application and click on the button I display some values in a message box: the value of the Attribute at the time of the event start time, then the value of the LoLo subattibute at event start time, then the value of the HiHi sub attribute at the event start time.

                                      * What I'm finding is that I start the application after the event has started, I see the value of all attributes and sub sttributes at the time of event frame start.

                                      * When I go into PSE and change the values for sub attibutes HiHi or LoLo, I see what I expect, the original values at the time of the event frame start.

                                      * The issue I have is when I stop the application, run it again, press the button to run the routine I see the correct value for the Attribute (value at start time) but I see the current values in the sub Attributes even though I'm passing in the event frame start time.

                                       

                                      Code below : I'm sorry but I do not see the function on the toolbar ro format the text as code.

                                       

                                      private void btnFindEventsT2_Click(object sender, EventArgs e)
                                              {
                                                  //Query string, logical AND applied. 
                                                  string query = "Start:>=*-2h";//InProgress:=False Template:Downtime Category:Temperature*";
                                      
                                                  //use simple search, although searchMode is very useful using other overloads 
                                                  AFEventFrameSearch search = new AFEventFrameSearch(db, "search", query);
                                      
                                                  //use new mehotd to GetTotalCount() without bringing back all EF headers. Fast and lower memory footprint 
                                                  MessageBox.Show(string.Format("Total EF match critiera: {0} ", search.GetTotalCount()));
                                      
                                                  //now actually bring back EF and full load- much more expensive call. 
                                                  IEnumerable<AFEventFrame> eventFameResults = search.FindEventFrames(0, true, 10);
                                                  foreach(AFEventFrame ef in eventFameResults)
                                                  {
                                                      //ef.CaptureValues();
                                                      if (ef.Name.Contains("Cell"))
                                                      {
                                                          //MessageBox.Show(ef.Name);
                                                          //ef.Acknowledge(@"SPECTRA\mspath", AFTime.Now);
                                                          //ef.Acknowledge();
                                                         
                                                          // now get more details from the event
                                                          foreach (AFElement elem in ef.ReferencedElements)
                                                          {
                                                              foreach (AFAttribute attrib in elem.Attributes)
                                                              {
                                                                  if (attrib.Name.Contains("Cell"))
                                                                  {
                                                                      AFValue myValue = attrib.GetValue(ef.StartTime);
                                                                      MessageBox.Show(string.Format("Cell: {0}", myValue.Value.ToString()));
                                                                      foreach (AFAttribute subAtt in attrib.Attributes)
                                                                      {
                                                                          if (subAtt.Name.Contains("HiHi"))
                                                                          {
                                                                              AFValue HiHiValue = subAtt.GetValue(ef.StartTime);
                                                                              MessageBox.Show(string.Format("HiHi Cell: {0}", HiHiValue.Value.ToString()));
                                                                          }
                                                                          if (subAtt.Name.Contains("LoLo"))
                                                                          {
                                                                              AFValue LoLoValue = subAtt.GetValue(ef.StartTime);
                                                                              MessageBox.Show(string.Format("LoLo Cell: {0}", LoLoValue.Value.ToString()));
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                          }
                                                       }
                                                  }
                                              }
                                      
                                        • Re: How to get value of attributes from an event frame
                                          Rick Davin

                                          To format text, click the blue Use advanced editor link in the upper right of a post,

                                           

                                          2017-06-28 08_18_28-How to get value of attributes from an event frame _ PI Square.png

                                           

                                          The select the >> on the far right of the 2nd line of the toolbar:

                                           

                                          2017-06-28 08_19_39-Reply to 'Re_ How to get value of attributes fr... _ PI Square.png

                                           

                                          Then choose Syntax highlighting > C#:

                                           

                                          2017-06-28 08_20_37-Reply to 'Re_ How to get value of attributes fr... _ PI Square.png

                                          • Re: How to get value of attributes from an event frame
                                            Rick Davin

                                            Mike,

                                            Are you limits such as HiHi defined as static attributes or are they historized as PIPoints?

                                                • Re: How to get value of attributes from an event frame
                                                  Rick Davin

                                                  Mike,

                                                   

                                                  There is absolutely nothing peculiar about your earlier image.  You have a static attribute that is not a Configuration Item.  It will only have 1 date associated with it, namely the effective date of the element's version: 1/1/1970.  Your UI that allows users to change the limits will therefore retroactively change the limits back to 1/1/1970.  That is a limitation of your design.  It is futile for you to go back to an event frame's start time to dynamically capture the limit.  That's why your code doesn't work as you are hoping it would work.  Yet the code does work precisely as you've written it.

                                                   

                                                  If you want to know a history of limits, a poor implementation would be to use element versioning.  This performs sluggishly.  Instead you really should be storing the limit history in your Data Archive as PIPoint(s).  Even if that limit changes once a year, historize it as a PIPoint.

                                                    • Re: How to get value of attributes from an event frame
                                                      MikeSpath

                                                      Hi Rick:

                                                      Thanks for your help, the reason we are trying to use the sub attributes was to avoid having the user to pile on the point count and system cost. Is there a way to store the values in the event frame's attribute section? I notice start trigger expression and name can be stored.

                                                      Mike

                                                        • Re: How to get value of attributes from an event frame
                                                          Rick Davin

                                                          The start trigger name and expression may be stored as static string attributes on the generated event frame.  What is not stored is the values provided to the expression that caused the trigger.

                                                           

                                                          You may also define variables before the trigger definitions.  However you can't map those variables to attributes.

                                                           

                                                          You could use StringBuilder to create a reference back to attribute on the the PrimaryReferencedElement.  However, unlike a PIPoint where you could specify the StartTime as the time context, with StringBuilder you use the default time context, which is the EndTime.  You also have the very likely scenario where someone may do something that causes the event frame to re-capture values, in which case it would recapture the most recently entered limit.

                                                            • Re: How to get value of attributes from an event frame
                                                              MikeSpath

                                                              Hi Rick:

                                                              Could I do something with Extended Properties on an event frame, store the limit values in one or more attributes there? I must be able to create and retrieve them through the AF SDK.

                                                              ExtendedPropeties.png

                                                                • Re: How to get value of attributes from an event frame
                                                                  Rick Davin

                                                                  Let's say you have an Asset Analysis to generate an event frame.  You have little to do as the start and end trigger are performed automatically.  You are hoping for a magical code fix but have to understand that your code must run after the fact.  Let's say you have a routine that runs nightly at 4 AM.  Define your event frame to have static attributes for the limits and also have a static Boolean attribute named "Limits Captured".  The default value for "Limits Captured" would be false.  Your routine runs at 4 AM daily and checks any event frames where "Limits Captured" is false.  You then assign the limits to the static attributes.  Finally you set "Limits Captured" to true, and move to next event frame.

                                                                    • Re: How to get value of attributes from an event frame
                                                                      Guilherme Ferreira

                                                                      Hi Mike!

                                                                       

                                                                      As Rick explained, if the attribute is not mapped to a PI Point, you do not have history. So, if you change the subattribute value and run your code again, it will retrieve the new value, as it doesn't store history.

                                                                      What you could do is store the subattribute value as an attribute of the event frame.

                                                                       

                                                                       

                                                                      The substitution parameter Elements[.] will return the primary referenced element of the event frame generated.

                                                                      Consequently, Elements[.] |CellCount|HiHi will be the HiHi subattribute you want.

                                                                       

                                                                      Regards

                                                                      1 of 1 people found this helpful
                                                                        • Re: How to get value of attributes from an event frame
                                                                          Rick Davin

                                                                          Guilherme,

                                                                           

                                                                          That only works for PIPoints, which the poster is not using for the HiHi traits, nor will he convert them to be PIPoints.  Therefore, he cannot use your solution. 

                                                                          • Re: How to get value of attributes from an event frame
                                                                            MikeSpath

                                                                            Thank you for your suggestion but what Rick states in the next post is true, we cannot add any pipoint to the solution. I even had a pi support engineer walk me through creating an expression that populated a string pi tag with the limit info on event but that solution would add one pipoint per element which was still rejected by management due to added tag cost.

                                                                            Miike

                                                                              • Re: How to get value of attributes from an event frame
                                                                                Guilherme Ferreira

                                                                                Unfortunately, Rick is right!

                                                                                 

                                                                                Rick Davin why isn't that possible? It feels so simple and obvious!

                                                                                Of course it shouldn't work for summary data, but a simple value...

                                                                                 

                                                                                Regards

                                                                                  • Re: How to get value of attributes from an event frame
                                                                                    Rick Davin

                                                                                    Because the PIPoint DR accepts various time contexts, such as "Start Time" as part of their configuration string.  Other DR's, such as - but not limited to - StringBuilder, Table, and Formula, do not have this.  In those cases, it uses the default time context, which is the event frame's EndTime, which means you get the value of when the trigger ends, not starts.

                                                                                     

                                                                                    And in the case of a static attribute without any history, it should be obvious why.

                                                                                      • Re: How to get value of attributes from an event frame
                                                                                        Guilherme Ferreira

                                                                                        Ok, I understand that!

                                                                                        But if I ask an static attribute for its value, no matter if using event's start or end time as time context, it should be returned. Shouldn't it?

                                                                                        The same way that I can switch query date in PSE and still see the static value.

                                                                                        That's what I tried to configure.

                                                                                          • Re: How to get value of attributes from an event frame
                                                                                            Rick Davin

                                                                                            You were trying to use the PIPoint DR to configure it.  You could use StringBuilder instead, and yes that would work (done it many times before).  By default, StringBuilder would read it as a string, but you may change the EF attribute type to be Single.

                                                                                             

                                                                                            On another note, it is possible to write a custom DR that uses StartTime instead of EndTime, or like PIPoint DR, allows for a config option.  See this link for an example.

                                                                                              • Re: How to get value of attributes from an event frame
                                                                                                Guilherme Ferreira

                                                                                                So String Builder it is! That's what I was looking for... Thanks!

                                                                                                 

                                                                                                 

                                                                                                If I understood it right, this should attend to Mike's needs.

                                                                                                 

                                                                                                            IEnumerable<AFEventFrame> eventFameResults = search.FindEventFrames(0, true, 10);  
                                                                                                            foreach(AFEventFrame ef in eventFameResults)  
                                                                                                            {  
                                                                                                                //ef.CaptureValues();  
                                                                                                                if (ef.Name.Contains("Cell"))  
                                                                                                                {  
                                                                                                                    //MessageBox.Show(ef.Name);  
                                                                                                                    //ef.Acknowledge(@"SPECTRA\mspath", AFTime.Now);  
                                                                                                                    //ef.Acknowledge();  
                                                                                                                     
                                                                                                                    //no need to go over the referenced element attributes
                                                                                                                    //the values are already stored in event frame's attributes
                                                                                                                    foreach (AFAttribute attrib in ef.Attributes)  
                                                                                                                    {  
                                                                                                                        if (attrib.Name.Contains("Cell"))  
                                                                                                                        {  
                                                                                                                            AFValue myValue = attrib.GetValue();  
                                                                                                                            MessageBox.Show(string.Format("Cell: {0}", myValue.Value.ToString()));  
                                                                                                                        }
                                                                                                                        foreach (AFAttribute subAtt in attrib.Attributes)  
                                                                                                                            {  
                                                                                                                                if (subAtt.Name.Contains("HiHi"))  
                                                                                                                                {  
                                                                                                                                    AFValue HiHiValue = subAtt.GetValue();  
                                                                                                                                    MessageBox.Show(string.Format("HiHi Cell: {0}", HiHiValue.Value.ToString()));  
                                                                                                                                }  
                                                                                                                                if (subAtt.Name.Contains("LoLo"))  
                                                                                                                                {  
                                                                                                                                    AFValue LoLoValue = subAtt.GetValue();  
                                                                                                                                    MessageBox.Show(string.Format("LoLo Cell: {0}", LoLoValue.Value.ToString()));  
                                                                                                                                }  
                                                                                                                            }
                                                                                                                       }
                                                                                                                  }
                                                                                                             }  
                                                                                                                        }  
                                                                                                                    }  
                                                                                                                 }  
                                                                                                            }
                                                                                                

                                                                                                 

                                                                                                         

                                                                                                Regards