Eugene Lee

Search for PI Point by Point ID with PI Web API

Blog Post created by Eugene Lee Employee on May 15, 2019

Introduction

Normally, when we search for PI Points in PI Web API, we come equipped with its path. In this case, we can simply use the GetByPath action of the Point Controller to achieve this.

Point Controller GetByPath

 

But what if one day, your custom web application has a requirement where a list of Point IDs is given to you and there is a need for you to find the name of the PI Point corresponding to these IDs? If you are developing your application using the .NET Framework, then you have the option to use the PIPoint.FindPIPoint method available in AF SDK.

PIPoint.FindPIPoint

But since you are developing a web application, you do not have that luxury.

 

Today, in this blog post, I will be addressing how to search for a PI Point using its Point ID via PI Web API and WebID 2.0. An example of such a request can be found here.

https://pisquare.osisoft.com/thread/39989-find-pi-point-by-id

 

Concepts

If you don't know already, WebID version 2.0, introduced in PI Web API 2017 R2, provides different types of WebIDs (see: WebID Type). Specifying the WebID type gives you options for reducing WebID sizes (for URL length limitations), for identifying ambiguous paths/names of AF Event Frames and AF Notifications, and for accommodating path and name changes.

 

I will be using the IDOnly type today to achieve my goal of searching via the Point ID. The language of choice will be JavaScript.

 

Let's take a look at the composition of the IDOnly type of a PI Point WebID.

 

I chose a sample that is available from our public PI Web API endpoint found here.

I1DPW6Wlk0_Utku9vWTvxg45oA0egAAA

 

Let's try to break it down.

 

NameValue
IWeb ID type indicator. “IDOnly” in this case
1Web ID version number
DPWeb ID marker for PI Point objects
W6Wlk0_Utku9vWTvxg45oAURL Safe Base64 encoded string of PI Data Archive Id
0egAAAURL Safe Base64 encoded string of PI Point Id

 

With this knowledge, we can see that we are able to use the Point ID directly by encoding it in the WebID and using it in the Point Controller Get action.

Point Controller Get

 

Function to generate IDOnly type of WebID

Disclaimer:

This code could contain bugs and shouldn’t be used in production without extensive testing.

You agree that if you use any of the provided code in your own production code that you accept all ownership, risks, liabilities, and responsibilities associated with the performance, support, and maintenance of the code.

 

Please see this post here if you would like to see this same block of code with nicer indents.

function NewIDOnlyWebID(dataType, guid, oid, ownerType, ownerguid) {

//get the marker for the datatype
var marker = getOwnerMarker(dataType, ownerType)

//encode the server id to a base64 string
var serverwebid = encodeguid(guid)

//encode the owner id if datatype has a owner
var typeswithowner = ["AFAnalysisRule", "AFAttribute", 'AFAttributeTemplate', "AFEnumerationValue", "AFTimeRule"];
if (typeswithowner.includes(dataType)) {
if (ownerguid) {
serverwebid += encodeguid(ownerguid)
}
else {
throw 'please provide a valid owner guid'
}
}

//return webid if datatype is a server
if (dataType == "PIServer" || dataType == "PISystem") {
return 'I1' + marker + (serverwebid).replace(/=/g, '').replace(/\//g, '_').replace(/\+/g, '-')
}

//return webid if datatype is a pi point
if (dataType == "PIPoint") {
if (!oid) throw 'provide a valid PI Point ID'
var arr = new Uint8Array(new Uint32Array([oid]).buffer);
var pointwebid = btoa(String.fromCharCode.apply(null, arr))
return 'I1' + marker + (serverwebid + pointwebid).replace(/=/g, '').replace(/\//g, '_').replace(/\+/g, '-')
}

//return webid for af objects
var afwebid = encodeguid(oid)
return 'I1' + marker + (serverwebid + afwebid).replace(/=/g, '').replace(/\//g, '_').replace(/\+/g, '-')
}

function encodeguid(guid) {
var s = guid.replace(/[^0-9a-f]/ig, '').toLowerCase();

//check for invalid guid
if (s.length != 32) throw 'invalid guid';

//arrange bytes as PI Web API uses Microsoft style GUID
s = s.slice(6, 8) + s.slice(4, 6) + s.slice(2, 4) + s.slice(0, 2) +
s.slice(10, 12) + s.slice(8, 10) +
s.slice(14, 16) + s.slice(12, 14) +
s.slice(16);

//base64 encode the byte array
var t = '';
for (var n = 0; n < s.length; n += 2) {
t += String.fromCharCode(parseInt(s.substr(n, 2), 16));
}
return btoa(t)
}

function getOwnerMarker(dataType, ownerType) {
var marker
switch (dataType) {
case 'AFAnalysis':
marker = 'XS'
break;
case 'AFAnalysisCategory':
marker = 'XC'
break;
case 'AFAnalysisTemplate':
marker = 'XT'
break;
case 'AFAnalysisRule':
marker = 'XR'
switch (ownerType) {
case 'AFAnalysis':
marker += "X"
break
case 'AFAnalysisTemplate':
marker += "T"
break
default:
throw "please provide owner type"
}
break;
case 'AFAnalysisRulePlugin':
marker = 'XP'
break;
case 'AFAttribute':
marker = 'Ab'
switch (ownerType) {
case 'AFElement':
marker += "E"
break
case 'AFEventFrame':
marker += "F"
break
case 'AFNotification':
marker += "N"
break
default:
throw "please provide owner type"
}
break;
case 'AFAttributeCategory':
marker = 'AC'
break;
case 'AFAttributeTemplate':
marker = 'ATE'
break;
case 'AFDatabase':
marker = 'RD'
break;
case 'AFElement':
marker = 'Em'
break;
case 'AFElementCategory':
marker = 'EC'
break;
case 'AFElementTemplate':
marker = 'ET'
break;
case 'AFEnumerationSet':
marker = 'MS'
switch (ownerType) {
case 'PISystem':
marker += "R"
break
case 'PIServer':
marker += "D"
break
default:
throw "please provide owner type"
}
break;
case 'AFEnumerationValue':
marker = 'MV'
switch (ownerType) {
case 'PISystem':
marker += "R"
break
case 'PIServer':
marker += "D"
break
default:
throw "please provide owner type"
}
break;
case 'AFEventFrame':
marker = 'Fm'
break;
case 'AFNotification':
marker = 'Nf'
break;
case 'AFNotificationTemplate':
marker = 'NT'
break;
case 'AFNotificationContactTemplate':
marker = 'NC'
break;
case 'AFTimeRule':
marker = 'TR'
switch (ownerType) {
case 'AFAnalysis':
marker += "X"
break
case 'AFAnalysisTemplate':
marker += "T"
break
default:
throw "please provide owner type"
}
break;
case 'AFTimeRulePlugin':
marker = 'TP'
break;
case 'AFSecurityIdentity':
marker = 'SI'
break;
case 'AFSecurityMapping':
marker = 'SM'
break;
case 'AFTable':
marker = 'Bl'
break;
case 'AFTableCategory':
marker = 'BC'
break;
case 'PIPoint':
marker = 'DP'
break;
case 'PIServer':
marker = 'DS'
break;
case 'PISystem':
marker = 'RS'
break;
case 'UOM':
marker = 'Ut'
break;
case 'UOMClass':
marker = 'UC'
break;
default:
throw "please provide a suitable datatype"

}
return marker
}

The code above provides a generalized function that can help you to generate a PI Point WebID. The function takes 5 parameters.

 

namevalue
dataTypethe type of object
guidthe guid of the server that the object belongs to
oidthe id of the object itself
ownerTypethe type of the owner object (only required for objects with owner types)
ownerguidthe guid of the owner object (only required for objects with owner types)

 

 

Example usage for PI Point objects, 

console.log(NewIDOnlyWebID('PIPoint', '93a5a55b-d44f-4bb6-bdbd-64efc60e39a0', 59601))

Result will be the PI Point WebID

I1DPW6Wlk0_Utku9vWTvxg45oA0egAAA

 

Example usage for AF Attribute objects belong to an AF Element,

console.log(NewIDOnlyWebID('AFAttribute', '0b101021-e3bc-433d-9f06-a6a2db5f0803', '4f46d670-487e-5aa1-38b9-cd626ea43bc6', 'AFElement', 'cd24b9af-68d5-11e8-80db-000d3a10c7ce'))

Result will be the AF Attribute WebID

I1AbEIRAQC7zjPUOfBqai218IAwr7kkzdVo6BGA2wANOhDHzgcNZGT35IoVo4uc1ibqQ7xg

 

 

How to get the object guids?

For PI Data Archive, we can make a call to the DataServer Controller and utilize its GetByPath action and only select the Id field. An example is shown below.

 

 

Similarly for AF Server, we can make a call to the AssetServer Controller and utilize its GetByPath action and only select the Id field. I will leave this as an exercise for you to try out.

 

For AF objects, we can find the guid at the lower right corner of PI System Explorer.

 

Solve the initial problem

At the start of this blog, our challenge was to find the name of the PI Point corresponding to a Point ID that was given. Now with the PI Point WebID that was generated, we can easily do so with the Get action of the Point Controller.

 

 

 

Conclusion

We can see that WebID 2.0 has enhanced the flexibility of PI Web API and it allows us to do things that were previously thought impossible. The possibilities are endless and only limited by your imagination. I hoped you have enjoyed reading this blog and learnt something useful from it.

 

Please drop any comments below!

 

 

 

See also

pi-web-api-web-id-20-specification-tables

using-web-id-20-to-optimize-your-applications

Outcomes