6 Replies Latest reply on Oct 23, 2017 12:45 PM by Rick Davin

    Dose updatevalue accepts double as a parameters for the new value and datatime as timestamp parameter

    Aysha

      Hi

      for the function Updatevalue does it accept double as parameter for the new value? and for the timestamp parameter does it accept time ?

      ex

      double NewVal=33.39;

      Datetime Timestamp=Convert.toDateTime("15/10/2017 6:20:10 PM");

      x.Data.Updatevalue(Newval, NewTime);

        • Re: Dose updatevalue accepts double as a parameters for the new value and datatime as timestamp parameter
          Rick Davin

          Hello Aysha,

           

          The PI SDK UpdateValue accepts 4 arguments.  The first arg is an object, which can be a double, or a Single, or a string.  If the target PIPoint is a Float32 instead of a Float64, the double will be converted to a Single.

           

          Definitely sounds like you are just starting out programming with our SDK's.  In which case we can't strongly recommended enough that you use AF SDK instead of PI SDK since PI SDK is targeted for deprecation.  The AF SDK UpdateValue method takes an AFValue, and the AFValue constructor is quite flexible with many overloads.  But it still revolves around the notion of the Value property is an object.

            • Re: Dose updatevalue accepts double as a parameters for the new value and datatime as timestamp parameter
              Aysha

              Then why it is not adding new values to the archive

              here is my code:

               

              PISDK.PIValues yvalues = new PIValues();
              PISDK.PIDATA yData =yPoint.Data;
              PIValue tValue = tData.ArcValue("*",RetrievalTypeConstant.rtAtOrBefore);
              
              for(int j=0;j<(peaks.count+1)/3;j++)
              {
              yvalues.readonly=false;
              ypoint.data.update/value(convert.ToDouble(peaks[(j*3)+1]),Convert.ToDateTime(peaks[(j*3)+2]));
              yvalues.ReadOnly =true;
              }
              yvalues.ReadOnly =false;
              yPoint.Data.updatevalue(tValue, curtime);
              yvalues.Readonly = true;
              

               

              It will not add value for the (update) one inside the loop

              but it will add value for the one outside the loop

               

              WHY?

                • Re: Dose updatevalue accepts double as a parameters for the new value and datatime as timestamp parameter
                  Rick Davin

                  I'm surprised any of the code works at all because there are many typos to cause compiler errors.  What data type is peaks?  Guessing string or object, because Convert.ToDateTime always throws an invalid cast exception for numeric inputs.  You are also trying to do way too much unneeded steps (such as toggling PIValues.ReadOnly repeatedly), though for debugging purposes you could add a few extra steps to check in the Locals window.

                   

                  Here is a cleaner version of what I interpret your code to be doing.  The variables yPoint, peaks, and curtime are known prior to this snippet.  You only need to set yvalues.ReadOnly once.

                   

                  PIData yData = yPoint.Data;
                  PIValue tValue = yData.ArcValue("*", RetrievalTypeConstants.rtAtOrBefore);
                  
                  PIValues yvalues = new PIValues();
                  yvalues.ReadOnly = false;
                  
                  for (int j = 0; j < (peaks.Count + 1) / 3; j++)
                  {
                      yPoint.Data.UpdateValue(Convert.ToDouble(peaks[(j * 3) + 1]), Convert.ToDateTime(peaks[(j * 3) + 2]));
                  }
                  
                  yPoint.Data.UpdateValue(tValue, curtime);
                  

                   

                   

                  The looping mechanism seems convoluted.  Below is a reworking.  For efficiency we recommend bulk.  Since your tag is Float32, I use Single instead of double.  I also break down the date time conversion into 2 variables, since 2 conversions will occur.

                   

                  PIValues yvalues = new PIValues();
                  yvalues.ReadOnly = false;
                  
                  for (int j = 0; j < peaks.Count; j += 3)
                  {
                      Single val = Convert.ToSingle(peaks[j + 1]);
                      DateTime dotnetTime = Convert.ToDateTime(peaks[j + 2]);
                      PITime ptime = dotnetTime.ConvertToPITime();
                      // Place Debug Breakpoint below and inspect above in Locals Windows
                      yvalues.Add(ptime, val, null);
                  }
                  
                  PIValue lastRecordedValue = yPoint.Data.ArcValue("*", RetrievalTypeConstants.rtAtOrBefore);
                  yvalues.Add(curtime, lastRecordedValue.Value, null);
                  
                  // Make one bulk call
                  yPoint.Data.UpdateValues(yvalues, DataMergeConstants.dmReplaceDuplicates, null);
                  

                   

                   

                  To convert from a .NET DateTime to a PITime, add this PITimeExtensions class to your project:

                   

                  using System;
                  using PITimeServer;
                  
                  public static class PITimeExtensions
                  {
                      private static readonly DateTime beginningOfUtcTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                      public static DateTime ConvertToLocalTime(this PITime pitime)
                      {
                          var utcTicks = Convert.ToInt64(pitime.UTCSeconds * TimeSpan.TicksPerSecond);
                          var utcTime = beginningOfUtcTime.AddTicks(utcTicks);
                          return utcTime.ToLocalTime();
                      }
                  
                      public static PITime ConvertToPITime(this DateTime dotnetTime)
                      {
                          // WARNING: You may get undesired results if dotnetTime.Kind is Unspecified.
                          var utcTicks = dotnetTime.ToUniversalTime().Ticks - beginningOfUtcTime.Ticks;
                          var utcSeconds = utcTicks / (double)TimeSpan.TicksPerSecond;
                          PITime pitime = new PITime();
                          pitime.UTCSeconds = utcSeconds;
                          return pitime;
                      }
                  }
                  

                   

                  However, the burden is up to you AS THE DEVELOPER to understand time conversion rules.  If you convert a string to a .NET DateTime, it's Kind is Unspecified, even if you wanted it to be Local.  As the developer, you should have explicit calls to convert any Unspecified .NET DateTimes to be Utc or Local before you call ConvertToPITime.  You could use either of the following as your needs dictate:

                   

                  Coerce to Local

                  dotnetTime = DateTime.SpecifyKind(dotnetTime, DateTimeKind.Local);
                  

                   

                  Coerce to Utc

                  dotnetTime = DateTime.SpecifyKind(dotnetTime, DateTimeKind.Utc);
                  

                   

                   

                  Despite all this code, you may still not be able to save values to the archives.  It all depends upon what each PIValue's TimeStamp would be and whether or not your archives are setup to support that time.  For example, if the earliest time for your archives is January 1, 2016 and you attempt to update values before that date, then those values will not be saved.  Better debugging of your app can help highlight that.  Again, create variables to hold important values, set a Debug Breakpoint, and check the Locals window to see what value is in those important variables.