andreas

C++ and PI - calling PI Web Services

Blog Post created by andreas Employee on Dec 1, 2011

As promised in this post I am continuing my travel to the land of C++.

 

In this post I will try to get a snapshot calling PI Web Services from C++. Similar as with the PI SDK this does requires some more ground work then consuming the PI Web Services in .NET.

 

The following example makes use of the gSoap toolkit, an open source, cross-platform toolkit for calling web services from C and C++ - so you may start by downloading it from here. I encourage you to take a look at the Getting Started. This example requires basic binding with no security - make sure that you use the web_config_basic_no_security web.config file for your PI Webservice*.

 

If you have downloaded the gSoap toolkit you start with creating the include files for your C++ application. This is a two step process starting with using wsdl2h to create the gSOAP header file from the WSDL. Adjust the path to the webservice as necessary. Note that you can choose your own name for the web service namespace with the -n argument.

 

The second step is using the soapcpp2 compiler to create the necessary code snippets to include into your application. The -I indicates the path to the import folder of the gSoap toolkit - you need to adjust that depending of the version and where you have extracted your gSoap toolkit.

 

soapcpp2.exe -1 -i -IE:\gsoap_2.7.17\gsoap-2.7\gsoap\import -C PITimeSeriesService.h

That is the point now for opening Visual Studio and starting our project:

 

 0027.20111118_5F00_01.png

 

Soapcpp2 has created some files that we need in our project:

 

BasicEndpoint.nsmap
soapBasicEndpointProxy.cpp
soapBasicEndpointProxy.h
soapC.cpp
soapH.h
soapStub.h

 

We copy them to our source directory and add the cpp files to the project. Furthermore we need to add stdsoap2.cpp from the gSoap toolkit. Finally it should look like this:

 

1460.20111118_5F00_02.png

 

We need to add the gsoap source directory as additional include directory for the C++ compiler:

 

5822.20111118_5F00_04.png

 

If we have not done so at the beginning we disable precompiled headers now:

 

0451.20111118_5F00_05.png

 

and add the necessary includes:

 
#pragma once
#include
<stdio.h>
#include
<tchar.h>
#include <iostream>
#include "BasicEndpoint.nsmap"
#include "soapBasicEndpointProxy.h"

Now it is time to open our source file and start to write the code. As first step we will get the PI Web Services version and the endpoint:

 

int

_tmain(int argc, _TCHAR* argv[])
{
   
// gSOAP proxy object for PI Web Services
   
BasicEndpointProxy wsService;

    // Product version request

    _PIWS1__GetProductVersion wsVreq;
    _PIWS1__GetProductVersionResponse wsVresp;
   
   
// Get Version and Endpoint string
   
int error = wsService.GetProductVersion(&wsVreq, &wsVresp);

   
if (SOAP_OK == error)
    {
        std::cout <<
"Endpoint: "
                  << wsService.soap_endpoint
                  << std::endl;
        std::cout <<
"PI Web Services Version: "
                  << wsVresp.GetProductVersionResult->c_str()
                  << std::endl;
    }
   
else
    {
        std::cout <<
"GetProductVersion fault\n";
        soap_print_fault(&wsService, stderr);
    }

   
    // free dynamic memory allocated by gSOAP

    wsService.destroy();
   
return 0;
}

Time for testing - if you have done everything above you should get something similar to:

 

2022.20111118_5F00_06.png

 

 Now let us prepare for the snapshot:

 

// Snapshot request
_PIWS1__GetPISnapshotData wsRequest;
_PIWS1__GetPISnapshotDataResponse wsResponse;
PIWS1__ArrayOfString wsPaths;
// Path to a PI Tag
std::string strPath =
"PI:\\\\SCHREMMERAVMPI\\Sinusoid";
// Add to the Array of Paths
wsPaths.string.push_back(strPath);
// Path to a PI Tag
strPath =
"PI:\\\\SCHREMMERAVMPI\\CDT158";
// Add to the Array of Paths
wsPaths.string.push_back(strPath);
// Path to a PI Tag
strPath =
"PI:\\\\SCHREMMERAVMPI\\CDM158";
// Add to the Array of Paths
wsPaths.string.push_back(strPath);
wsRequest.paths = &wsPaths;

And the final step is getting the snapshot and printing it out:

 

error = wsService.GetPISnapshotData(&wsRequest, &wsResponse);


if (SOAP_OK == error)
{
    std::cout <<
"GetPISnapshotData: "
              << wsResponse.GetPISnapshotDataResult->TimeSeries.size()
              << std::endl;
    PIWS1__ArrayOfTimedValue *wsTimedValues;
   
for (unsigned int a=0;
         a < wsResponse.GetPISnapshotDataResult->TimeSeries.size();
         a++)
    {
        wsTimedValues = wsResponse.GetPISnapshotDataResult->TimeSeries[ a ]->TimedValues;
        std::cout << wsResponse.GetPISnapshotDataResult->TimeSeries[ a ]->Path->c_str()
                  <<
" "
                  << ctime(&wsTimedValues->TimedValue[ 0 ]->Time)
                  <<
" "
                  << wsTimedValues->TimedValue[ 0 ]->__item
                  << std::endl;
    }
}
else
{
    std::cout <<
"GetPISnapshotData fault\n";
    soap_print_fault(&wsService, stderr);
}
wsService.destroy();

Again time for a test:

 

5557.20111118_5F00_07.png

 

Done! But not with C++ - we will revisit the PI SDK soon...

 

Notes:

 

*ways to secure basicHttpBinding are described in the PI Web Services documentation.

 

You might recognize STL (Standard Template Library) keywords in the code. gSoap uses this for strings and arrays by default. Good documentation on STL can be found here.

Outcomes