I've figured out how to create elements and attributes in pi.
Now I want to populate the attributes with data values.
How would I specify the time and value I want to for a specific attribute and upload it into pi?
Your first sentence suggests that by "pi" you mean you created elements and assets on an AF Asset Server, which in code would be a PISystem object.
To populate data, there are a couple of things to consider. A OSIsoft.AF.PI.PIPoint and an OSIsoft.AF.Asset.AFAttribute may both update values. For an AFAttribute, its really up to it's assigned data reference to perform the update. So if your AFAttribute uses the PIPoint data reference, you have 2 ways to update it's value. Sample code may be found on GitHub:
PI-AF-SDK-Basic-Samples/ExamplesLibrary/WriteValuesExample at master · osisoft/PI-AF-SDK-Basic-Samples · GitHub
The smaller questions behind your main question may possibly be:
Q) How do I create an AFValue?
A) See AFValue Constructors.
Q) How do I create an AFTime instance?
A) See AFTime Constructors.
You mention in the title that you wish to use the AFSDK, so I just want to verify that you want to add values programmatically?
What format is the data in? Is the data stored in text files that you'll feed through, or is it something dynamically generated via this program?
The reason I ask is just to ensure we're using the right method of getting data into PI. If the data is stored in text files, etc. we could use one of our connectors such as the PI UFL Connector.
If we're using the AF SDK, we can use the PIPoint.UpdateValues() method: PIPoint.UpdateValues Method
This PI Square post might be helpful as well: Write Value to Multiple Tags or Attributes
I do want to add values programmatically.
It's dynamically generated.
I want to be able to specify the time of the value.
There are many AFValue Constructor , most allow for an AFTime object to be passed to the constructor. This is what specifies the timestamp of the value.
For example, you can construct a new value the following way:
new AFValue(10, new AFTime('T'))
AFTime also allow for a diversity of time formats. For more details on those, you can look here: AFTime Structure
I'm trying to add values for the attribute IAC:
Below is the code i used to update the value:
But this somehow write the last value for all values going back to 1/1/1970
Can you confirm the usage of AFTime?
Looking at the valuestowrite, the timestamp is correct:
But when inputted into PI, it seems to only take the last AFValue and set all times equal to the last AFValue in the list.
There are several things wrong with what you are trying to do.
First of all, attribute IAC does not have a data reference, which means its a static value, which means it cannot contain history. You can set its value, but the time would be the effective element version date, which probably is 1/1/1970.
To set it's value in code, you could use something like:
// Put this after you define & set AFElement inverter
AFAttribute iac = inverter.Attributes["IAC"];
// No need to use AFTime for static values.
Here's link to AFAttribute.SetValue .
how can I set IAC to have a data reference so that it can contain history?
Whether or not one is allowed to write history to a given attribute depends upon the capabilities of the attribute's data reference. For example, Table Lookup is good for reading some small history, but not very good at writing it. Here's what does a great job at writing history: the PI Point Data Reference. Yep. The Data Archive is great for this.
So map your attribute to PIPoint, and then you may write history to it.
For more learning opportunities, please visit our Online Learning.
So in this case, i have a generated attribute, but before I try to write to the attribute:
1) I should generate a PI Point
2) Set the attribute to the PI Point
3) Write data with timestamp to the PI Point
Yes. You may then write history. You may only use AFAttribute.SetValue if you've declared the PIPoint with ReadOnly=False. That's the old school way. Personally, I prefer the newer way of using AFAttribute.Data.UpdateValues method, which ignores ReadOnly.
Modifying your code, and assuming you added the AFAttribute iac right after AFElement inverter, your loop looks like:
for (int i = 0; i < 10; i++)
AFTime time = new AFTime(new DateTime(2016, 1, i, 0, 0, 0, DateTimeKind.Local));
AFValue afValueFloat = new AFValue(iac, i, time);
Where I am using this AFValue Constructor . Then to update, change your AFListData.UpdateValues to be:
iac.Data.UpdateValues(valuesToWrite, AFUpdateOption.InsertNoCompression, AFBufferOption.BufferIfPossible);
Let's go with the newer way..
So for the newer way.. do I still need to create a PI point to write to history?
I tried the following and got:
This is because its not set to be a PiPoint...
So how would I create a PI point based on the element and attribute name?
First you would need to create a PIPoint in your data archive. Here's some YouTube links:
OSIsoft: The different ways to create PI tags
OSIsoft: Creating PI tags with the PI SMT Point Builder plug-in
You could name the PIPoint whatever you like. Once the PIPoint is created, you would then map it to your Inverter template, or if not a template, then the element itself.
A template's default naming pattern for PIPoints is \\%Server%\%Element%.%Attribute% but are in no way limited to this pattern. This again is just a default and you may change it to your needs. Sure you might want to name your tag Inverter.IAC but then again you would have multiple sites, so it might be something like Site1.Inverter.IAC. Come up with a naming pattern that fits your application, and change the template pattern accordingly.
Retrieving data ...