OSI PI AF SDK query
The PI AF SDK seems to be a OSIsoft.AFSDK.dll library implemented in .Net
You can use it through C# directly, or use it through a Python wrapper pythonnet.
The way it queries asset framework is through navigating from top element to the target element and then get the attribute
It seems to need the connection to asset framework set up in advance, e.g. having the PI system explorer installed and have the AF servers setup? The dll library file needs to be available in the Program Files folder.
It's not like RTQP that can just connect to the URL through ODBC.
Prerequisites: (1) install pythonnet (2) install PI System Explorer
#conda install pythonnet, the pip install may not work with clr
import sys
import clr
sys.path.append(r'C:\Program Files (x86)\PIPC\AF\PublicAssemblies\4.0')
clr.AddReference('OSIsoft.AFSDK')
from OSIsoft.AF import PISystems
from OSIsoft.AF.Time import AFTimeRange
import pandas as pd
#Connect to AF
af_servers = PISystems()
pi_system = af_servers['Your AF Server']
print(pi_system.ConnectionInfo.Host)
#navigate to the attribute
pi_db = pi_system.Databases.get_Item('You AF Database')
element1= pi_db.Elements.get_Item('the top element in the AF')
element2= element1.Elements.get_Item('the second element in the AF')
element3= element2.Elements.get_Item('the third element in the AF')
attr= element3.Attributes.get_Item('target attribute')
print(attr.GetValue())
#query a time range
query_range = AFTimeRange('*-24h', '*')
values = attr.GetValues(query_range, 0, None)
for v in values:
print("Annotated = {0}".format(v.Annotated))
print("IsGood = {0}".format(v.IsGood))
print("Questionable = {0}".format(v.Questionable))
print("Substituted = {0}".format(v.Substituted))
print("TimeStamp = {0}".format(v.Timestamp.LocalTime))
print("UOM = {0}".format(v.UOM))
print("Value = {0}".format(v.Value))
#convert to pandas dataframe
values_list = [[v.Timestamp.LocalTime, v.Value] for v in values if (v.IsGood==1 and v.Questionable==0)]
df = pd.DataFrame(values_list, columns = ['TimeStamp', 'Value'])
Query the current value for a specific timestamp
Note there may be no recorded value at the time. If after the interpolated value, use the GetValue() method below, otherwise the RecordedValue() method can return the immediately prior value.
The PI AF SDK references:
https://docs.osisoft.com/bundle/af-sdk/page/html/M_OSIsoft_AF_Asset_AFAttribute_GetValue_3.htm
https://docs.osisoft.com/bundle/af-sdk/page/html/M_OSIsoft_AF_Data_AFData_RecordedValue.htm
#conda install pythonnet
import sys
import clr
import pandas as pd
sys.path.append(r'C:\Program Files (x86)\PIPC\AF\PublicAssemblies\4.0')
clr.AddReference('OSIsoft.AFSDK')
from OSIsoft.AF import PISystems
from OSIsoft.AF.Time import AFTime, AFTimeRange
from OSIsoft.AF.Data import AFRetrievalMode, AFBoundaryType
#Connect to AF
af_servers = PISystems()
pi_system = af_servers['AF SERVER NAME']
print(pi_system.ConnectionInfo.Host)
#navigate to the attribute
pi_db = pi_system.Databases.get_Item('AF DATABASE NAME')
element1 = pi_db.Elements.get_Item('1st element name')
element2 = element1.Elements.get_Item('2nd element name')
attribute = element2.Attributes.get_Item('ATTRIBUTE NAME')
query_time = AFTime('2022-09-27 21:42:06')
value1 = attribute.GetValue(query_time)
value2 = attribute.Data.RecordedValue(query_time, AFRetrievalMode.AtOrBefore, attribute.DefaultUOM)
print(value1)
print(value2)
Query the values for given a time range
By setting the AFBoundaryType to 'outside' it also returns the immediate values before and after the range. Therefore even there is no recorded value within the range, it still returns the current value for the range.
The PI AF SDK reference:
https://docs.osisoft.com/bundle/af-sdk/page/html/M_OSIsoft_AF_Data_AFData_RecordedValues.htm
#conda install pythonnet
import sys
import clr
import pandas as pd
sys.path.append(r'C:\Program Files (x86)\PIPC\AF\PublicAssemblies\4.0')
clr.AddReference('OSIsoft.AFSDK')
from OSIsoft.AF import PISystems
from OSIsoft.AF.Time import AFTimeRange
from OSIsoft.AF.Data import AFBoundaryType
#Connect to AF
af_servers = PISystems()
pi_system = af_servers['AF SERVER NAME']
#navigate to the attribute
pi_db = pi_system.Databases.get_Item('AF DATABASE NAME')
element1 = pi_db.Elements.get_Item('1st element name')
element2 = element1.Elements.get_Item('2nd element name')
attribute = element2.Attributes.get_Item('ATTRIBUTE NAME')
#query data by time range, also return the immediate values before and after the range
time_range = AFTimeRange('2022-09-27 21:42:06', '2022-09-27 21:42:07')
values = attribute.Data.RecordedValues(time_range, AFBoundaryType.Outside, attribute.DefaultUOM, None, True, 0)
values_list = [[v.Timestamp.LocalTime, v.Value] for v in values if (v.IsGood==1 and v.Questionable==0)]
df = pd.DataFrame(values_list, columns = ['TimeStamp', 'Value'])