Learn the Basics of PI Programming - Simple PI Web API Calls

Document created by aduhig on Apr 21, 2015
Version 1Show Document
  • View in full screen mode

Activity Objectives

  • Make simple calls to the PI Web API
  • Determine the structure of the data returned



For the next few exercises, we’re going to use a PI AF Database that contains weather data for a few cities in the USA. In preparation, let’s take a look at this database:

  • Open up PI System Explorer using the shortcut on your desktop.
  • Click on the “Database” button in the top left of the window.
  • Select the USAWeather database and click OK. If the USAWeather database is not available, you can import it using the setup files attached to this post.

You should now see the following structure:


As you can see, the USAWeather database element hierarchy has a “Cities” element with five child elements named “Chicago”, “Los Angeles”, “New York”, “San Francisco” and “Washington”. Each city element is derived from the “City” element template which has five attribute templates: “Cloud cover”, “Humidity”, ”Pressure”, ”Temperature”, ”Visibility” and “Wind Speed”.


We could take a look at this database using PI Web API using a simple browser, but we are going to both read and write to it. Reading and writing requires us to make both GET and POST HTTP requests. So, we’ll need to use an HTTP client that supports both of these. Postman is an extension of Google Chrome that makes it easy to test RESTful services by manually crafting HTTP requests, and does the task we’re looking for. While you are learning to use the PI Web API you will most likely make many, many queries using a tool like this.


You can download and install Google Chrome from google.com/chrome/browser and, once it is installed, get the Postman client from getpostman.com. Complete the following tasks below to become more familiar with the query structure when making calls to the PI Web API:

1.    Open Postman by double clicking on the shortcut on your desktop.


2.    Inside Postman, type the following into the address field, making sure that the GET method is selected. You'll need to replace <ServerName> with the name of your PI Web API Server.



After typing, hit enter or press the “Send” button.  This returns some top level properties of the PI Web API.  Note that none of these properties are actual production or configuration data, they are links to other queries and the help file. We really don’t get much from this query.


3.    Let’s go one level deeper. Write the following in the address field and press enter or click “Send”:



Note that this returns a JSON that contains the names, IDs and details of any PI AF Servers that the PI Web API can access.



"Links": {},

"Items": [


"WebId": "S04gWl9O2GK0uSl8fK3qtqagTUFTVEVSUEk",

"Id": "f4a505e2-86ed-4b2b-9297-c7cadeab6a6a",

"Name": "MASTERPI",

"Description": "",

"Path": "\\\\PISRV1",

"ServerVersion": "",

"Links": {

"Self": "https://localhost/piwebapi/assetservers/S04gWl9O2GK0uSl8fK3qtqagTUFTVEVSUEk",

"Databases": "https://localhost/piwebapi/assetservers/S04gWl9O2GK0uSl8fK3qtqagTUFTVEVSUEk/assetdatabases"






Displayed above is the output of the query we just ran. We are already familiar with most of the properties that are returned. However, there appear to be two different IDs for the AF Server object.  We see one “Id” and the “WebId”. The “Id” is the same unique AF Server ID that we see when connecting with PI System Explorer.  The WebId, however, is something new altogether.  When retrieving information, PI Web API encodes both the ID and path to the requested object to form this “WebId”.  This forms a new unique identifier for use in further queries.  Most PI Web API queries require one or more WebIds be included in the call. When you make a query with an input WebId, the PI Web API decodes this WebId and finds the object’s unique ID along with the object’s path.  It then attempts to perform the query using the object’s unique ID.  If this fails, it will perform the query using the path instead.  This gives the PI Web API a redundant, efficient way to reference objects in the PI System.


4,    In the previous call, the PI Web API gave us “Links”, pointing us to queries that can be performed on the returned object.  Examine the syntax of the URL next to the “Databases” link.  It is in the form:




This query references the unique ID of the PI AF Server, and asks for the databases that belong to that server. Click on the link and click on the “Send” button.


5.    Now we have our database names, IDs and associated information. Try to find the “USAWeather” database, then display its “Elements”. You will see a “Cities” element. Drill down one level more by viewing its “Elements” and you’ll see a list of cities. Get the attributes of “Chicago”, then get Interpolated data for the “Wind Speed” attribute.


6.    Up until now, we have been dealing exclusively with GET requests. The PI Web API can also write to the PI Server with the use of POST requests.  We’re going to use a POST to add a new attribute to an existing element in our database.  A PI Web API POST request consists of two parts.  A URL, indicating the object you wish to POST to, and an associated JSON packet, containing the information you wish to send.  We are going to create a new attribute under a parent element, so will have to prepare a URL referring to the attributes under a given element, and a JSON packet to send through with the attribute’s parameters.


First off, we need the URL indicating the object we’d like to post to. Take a look at the help file for this kind of request.  It’s at:




We need to make a query in the form POST elements/{webId}/attributes. We need a webId of the element that we’re going to post to.  Revisit the previous steps, navigate through your AF server using the PI Web API links, and grab the webId of the “Cities” element. Then, type the following into the URL section of Postman, replacing element-webId with the WebId of your “Cities” element:



  • Beside the URL, Select “POST” as the type of request.
  • Further to the right of POST, select “Headers” and enter a header of “Content-type” and a value of “application/json”
  • Below the URL select “raw” as the text type
  • Beside the “raw” selector, ensure that you are making the request in the form of “JSON”.


Write the following into the text entry pane:



     "Name": "ExampleAttribute",

     "Description": "ExampleString",

     "DataReferencePlugIn": "PI Point",

     "ConfigString": "\\\\PISRV1\\CDT158;UOM=m;ReadOnly=False",

     "IsConfigurationItem": true,



Your configuration should look similar to the following screenshot:


Finally, click on the “Send” button. Ensure you receive the “201 Created” Status code.


7.    Change the request back to GET and click the “Send” button. You should see the properties of your created attribute.  Ensure your attribute has a DataReferencePlugIn value of “PI Point” and note that it has a WebId value when queried.


8.    Write a new query to get equally spaced interpolated data every 30 minutes for the last 24 hours for your new attribute. Try to build the URL yourself.

Hint: The resources in the “GET streams/…” resource type return raw data, interpolated data or calculated data based on a single data stream. A “data stream” can be a PI AF Attribute or a PI Point. You need to use the “GET streams/{webId}/interpolated” resource to get evenly spaced interpolated data for a point or attribute. See the help page for more information. You’ll also need to specify parameters at the end of the URL to suit the requirements in the question, try using Postman’s URL params feature, which will automatically append your parameters to your request. Check the form of your URL after making the request and see the syntax that is used.

9.    Write a single value of “35” to the attribute you created in step 6, “ExampleAttribute”. You will need to find an appropriate method to use.



8.      https://<ServerName>/piwebapi/streams/<webid>/interpolated?startTime=*-24h&endTime=*&interval=30m

9.    URL: POST https://<ServerName>/piwebapi/streams/{webId}/value

        Packet: {“Value”: 35,}


As timestamp defaults to the current time, it does not need to be included.