4 Replies Latest reply on Mar 17, 2011 3:11 PM by charlie@osisoft.com

    PI Eventing - How to get last changed value

    jagadeesh.macherla

      Hi Team

       

      As I raised a concern in my earlier thread that I have implemented OnNewValueChanges event for eventpipe to notify for value changes, how can i get the delta change for value, in other words, i need to get the difference between last value and new value. I have seen the property LastValueSent in PIData object but its implemented in SDK.

       

      Han Yong(OSIsoft Vcampus Member) suggested two ways of acheving the same:

      1. PIData.RecordedValuesByCount
      2. PIData.ArcValue

       

       

      Following parameters are recieved
      TagName : sinusoid
      Connected to default PI Server
      Created EventPipe from ListData.... Waiting for new events
       Previous Value :85.66788,96.36205 Date is :3/15/2011 4:28:59 PM. Event: sinusoid, New Value : 85.82043
       Previous Value :85.66788,96.36205 Date is :3/15/2011 4:28:59 PM. Event: sinusoid, New Value : 85.66788
       Previous Value :84.58118,96.36205 Date is :3/15/2011 4:32:30 PM. Event: sinusoid, New Value : 84.73842
       Previous Value :84.58118,96.36205 Date is :3/15/2011 4:32:30 PM. Event: sinusoid, New Value : 84.58118
       Previous Value :83.46222,96.36205 Date is :3/15/2011 4:36:01 PM. Event: sinusoid, New Value : 83.624
       Previous Value :83.46222,96.36205 Date is :3/15/2011 4:36:01 PM. Event: sinusoid, New Value 83.46222

       

      There are two things to note:

      1. For same timestamp, it is returning two events.
      2. If I am not wrong, as per Han's post, the new value generated in previous timestamp should be the Previous value in next timestamp, which is not happening in this case.

      The code snippet for the event generation is as follows:

       

       

       

       

       

       

       

       I also tried PIData.ArcValue method but again the new value does not matches with previous value for next timestamp.

       

      private void myEvents_OnNewValue()
      {
           try
           {
                Array EVP = myPipe.TakeAll();
                foreach (Object _obj in EVP)
                {
                     EO = _obj as PIEventObject;
                     _ptValue = (PointValue)EO.EventData;
                     
                     //PIValue pivalue = _ptValue.PIPoint.Data.ArcValue(DateTime.Now, RetrievalTypeConstants.rtBefore, null);
                     PIValues piValues = _ptValue.PIPoint.Data.RecordedValuesByCount(System.DateTime.Now, 2, DirectionConstants.dReverse, BoundaryTypeConstants.btInside, "", FilteredViewConstants.fvRemoveFiltered, null);
      
                     _value = _ptValue.PIValue;
      
                      if (_value.Value is DigitalState)
                     {
                        Console.WriteLine("\n Previous Value :" + piValues[1].Value + "," + piValues[2].Value + " Date is :" + EO.ReceivedTime.LocalDate + ". Event: " + _ptValue.PIPoint.Name + ", New Value : " + ((DigitalState)_value.Value).Name);
                     }
                     else
                     {
                          Console.WriteLine("\n Previous Value :" + piValues[1].Value + "," + piValues[2].Value + " Date is :" + EO.ReceivedTime.LocalDate + ". Event: " + _ptValue.PIPoint.Name + ", New Value :  " + _value.Value.ToString());
                     }
                }
           }
           catch (Exception ex)
           {
                Console.WriteLine(ex.Message.ToString());
           }
      }
      

       

       

      Please assist me on this.

       

      Jagadeesh

        • Re: PI Eventing - How to get last changed value
          Ahmad Fattahi

           

           

          Jagadeesh,

           

          You have set the Count argument to 2 in your call of the method; that should explain why you are getting 2 values per call. There is a detailed example on using the RecordedValuesByCount method in the PI SDK help which I am copying for you here.

           

           

           

          This example, during the Form_Load, connects to the default server, clears and initializes the display with reasonable defaults. When Command1 is hit it validates the user's input and retrieves the requested recorded values and displays them. 

           

          5518.valsbycount.gif

           
          Option Explicit
          Dim srv As Server
          Dim piconst As PIConstant
          Private Sub Command1_Click()
          On Error GoTo handler
             ' validate the input
             If Len(Text1.Text) = 0 Then
                MsgBox "Please enter a tag name"
                Exit Sub
             End If
             Dim dt As Date
             dt = CDate(Text2.Text)
             If dt < 25568.5 Then
                MsgBox "Invalid start time."
                Exit Sub
             End If
             Dim btType As BoundaryTypeConstants
             btType = piconst.Item(List1.Text).Value
             Dim pt As PIPoint
             Set pt = srv.PIPoints(Text1.Text)
             ' clear the results
             List2.Clear
             ' Get the recorded values
             Dim pvs As PIValues
             Dim count As Long
             count = CLng(Text3.Text)
             Dim direction As DirectionConstants
             If Option1.Value = True Then
                direction = dForward
             Else
                direction = dReverse
             End If
             
             Set pvs = pt.Data.RecordedValuesByCount(dt, count, direction, btType)
             Label8.Caption = CStr(pvs.count)
             Dim pv As PIValue
             For Each pv In pvs
                List2.AddItem CStr(pv.TimeStamp.LocalDate) + vbTab + CStr(pv.Value)
             Next
          Exit Sub
          handler:
             MsgBox Err.Description
          End Sub
          
          Private Sub Form_Load()
          On Error GoTo handler
             Set srv = Servers.DefaultServer
             ClearForm
          Exit Sub
          handler:
             MsgBox Err.Description
          End Sub
          Private Sub ClearForm()
             Text1.Text = "cdm158"
             Dim dt As Date, dt2 As Date
             dt = Now() - 8# / 24#
             Text2.Text = CStr(dt)
             Text3.Text = CStr(10)
             List1.Clear
             Label8.Caption = ""
             List2.Clear
             On Error GoTo handler
             Set piconst = PIConstants.Item("BoundaryTypeConstants")
             Dim nv As NamedValue
             For Each nv In piconst
                List1.AddItem nv.Name
             Next
             List1.ListIndex = 0
             Option1.Value = True
             Exit Sub
          handler:
             MsgBox Err.Description
          End Sub
          

           

            • Re: PI Eventing - How to get last changed value
              hanyong

              Hi Jagadeesh,

               

              As Ahmad have explained. RecordedValuesByCount gets a certain number from values (count) before or after a passed timestamp. Since we are passing the parameter 2, and the timestamp of current time (System.DateTime.Now), it gets the latest 2 values from the PI Server for the tag. 

               

               

               

              Looking at the result you have posted, we can see a few things:

               

              Previous Value :85.66788,96.36205 Date is :3/15/2011 4:28:59 PM. Event: sinusoi

               

              d, New Value : 85.82043

               

               Previous Value :85.66788,96.36205 Date is :3/15/2011 4:28:59 PM. Event: sinusoi

               

              d, New Value : 85.66788

               

               

              1. We have 2 events (85.82043 and 85.66788) received from the EventPipe at the same time. It could be that the tag is updated with 2 values within a short period of time, it really depends on the PollInterval of the EventPipe which Andreas mentioned in his previous post. But this means that when you received the notification when the value 85.82043 comes in, the latest value is already updated to 85.66788. Hence reading from PI Server using RecordedValuesByCount gives 85.66788 (latest or snapshot value) and 96.36205 (previous value). 
              2. You might have expected 85.82043 to be the previous value when 85.66788 is received instead of 96.35205. And the reason behind this is probably due to compression on the PI Server as values are being archived. In a nutshell, PI Server apply compression on values to minimize the amount to data while preserving the trend of the tag. If you want more information about how compression works, you can refer to this webinar.

                The effect that you see here is that not all values would be archived after compression. Hence in your case 96.35205 remains as the previous value even when new values like 85.82043 is received. My apologies as this is something that  I should have mentioned as a point to take note in my previous post.

              It is possible to change the compression setting to save all changes in value, but I wouldn't recommend it unless you are sure that you want every value for the tag to be archived, especially when you have a lot of tags to work with (mentioned previously). The other alternative to save the latest value received locally for comparison (mentioned in the previous post), which we do not have to make any assumptions about the compression of the tags.

               

               

               

               

                • Re: PI Eventing - How to get last changed value

                  I would like to make a suggestion that may help your program responsiveness and reliability.

                   

                  Inside your event handler, you make calls to the PI Server in a loop for all events.  If you have a large number of events, this could add up to significant time in the callback.  While you are processing in the callback, the PISDK is waiting for you to finish before any more events are fired.  I suggest you copy all the events from the EventPipe, then process the results afterward.

                    • Re: PI Eventing - How to get last changed value

                      Perhaps I do not understand all your requirements, but there is another architecture you could use that would reduce the number of calls to the PI Server significantly.  At startup, use ListData.Snapshot to get the latest PIValues for all your PIPoints.  (note: If the list is greater than 100,000, you might split the list into chunks for better performance)  If you sign up for a snapshot EventPipe before getting the snapshot, new events will automatically be retrieved for which you can calculate a delta value.  If you only want compressed values, then sign up for an archive EventPipe.

                       

                      Such an architecture will eliminate the RecordedValues calls you are making.