Skip navigation
All Places > PI Developers Club > Blog > 2014 > September
2014

Hi vCampus Members,

 

We are excited to announce the availability of our next milestone: PI Server 2015 Beta, which includes both PI Data Archive 2015 Beta (3.4.395.11) and PI AF Client 2015 Beta (2.7.0.6298).  Please note that since CTP1 back in May, the name of the release has changed from “PI Server 2014 R2” to “PI Server 2015” to more accurately reflect the release date of our final milestone.

 

For those of you that missed our CTP1 announcement, Beta showcases two of the major features of PI Server 2015:  (1) the ability to store time series data with future time stamps and (2) the ability to migrate PI Batch data to PI Event Frames.  As with any pre-release software, please review the accompanying documentation for features and limitations before proceeding too far.  Please conduct your evaluation in a test environment, not a production environment.

 

Here’s a highlight of what’s new in Beta since CTP1:

 

Installation

  • Upgrades are supported from 64-bit versions of PI Data Archive PR1 SP1x (3.4.375.80) and later, including CTP1.
  • PI AF Client 2015 Beta (2.7.0.6298) is included.
  • PI System Management Tools (SMT) 2015 Beta (3.5.0.12) is included.
  • PI Collective Manager 2015 Beta (1.3.0.1) is included.
  • PI SDK 2014 (1.4.4.484) is included.
  • PI Buffer Subsystem 4.3.0.28 is included.
  • .NET Framework 4.5.2 is required and included.
  • The path for future archives can now be specified.
  • The limitation with 1-CPU machines has been removed, but 2+CPUs are recommended

Future Data

  • PI AF Client 2015 provides enhanced data access capabilities for future tags via AFDataPipe, AFDataCache, and new methods for specifically differentiating current value from end-of-stream value.
  • Automatically created future archives always start with an initial size of 1 MB and grow dynamically.
  • Automatically created future archives always have a duration of one calendar month: either 28, 29, 30, or 31 days.
  • The location of automatically created future archives is completely independent from the location of automatically created historical archives; this location is initially specified during installation and can be changed afterwards with the PI SMT 2015 Archives plug-in.
  • PI SMT 2015 Archives plug-in has been re-worked: there is a tab per server, there are separate tabs for historical and future archives, the automatic creation settings can be configured without using the PI SMT Tuning Parameters plug-in, disk free space and usage is displayed for the drives configured for automatic archive creation, etc.
  • PI SMT 2015 Point Builder plug-in can create future tags from the “General” tab by setting “Future Data” to “Allow.”
  • PI SMT 2015 CurrentValues plug-in returns the value at server’s current time for future tags instead of the SYSTEM digital state “Future Data Unsupported.”
  • Attempts to write annotations to future tags are rejected with error “[-11170] Annotation not supported for future tags.”  Support will be added before final release.

Migration of PI Batch data to PI Event Frames

  • PI SMT MDB to AF Synchronization plug-in has been renamed to “PI SMT AF Link” to reflect the fact that it orchestrates both migration of the PI Module Database (MDB) to AF as well as the migration of PI Batch data to PI Event Frames.
  • PI SMT AF Link has been enhanced to configure the appropriate security in PI AF to handle the migration.
  • PI SMT AF Link has been enhanced to initiate analysis of the PI Batch Database before migration to PI Event Frames.  It displays the results of the analysis, including any errors (organized by category), archive gaps, and missing PI Identity Mappings.
  • PI SMT AF Link has been enhanced to initiate migration after analysis.  During migration, it provides status updates; after migration, it displays a final report, including whether any names were changed or errors were encountered.
  • PI Campaigns are migrated to PI Event Frames.
  • Empty procedure names and batch IDs are accounted for during migration.
  • The PI Unit index is forcefully synchronized with the MDB before analysis and migration.
  • Migration uses a set of derived PI Event Frame templates: PICampaignMigrated, PIBatchMigrated, PIUnitBatchMigrated, PISubBatchMigrated_L1, PISubBatchMigrated_L2, PISubBatchMigrated_L3, and PISubBatchMIgrated_L4.
  • The PI Batch Database is disabled for write access once migration has been initiated, causing write attempts to fail with error “[-19600] PI Batch Database is read-only because migration to PI Event Frames is in progress.”
  • The PI Batch Database remains disabled for write access after migration completes, causing write attempts to fail with error “[-19601] PI Batch Database is read-only because migration to PI Event Frames has completed.”

PI Server 2015 Beta is available for you to download under the Pre-Release category in the vCampus download page.  Just like before, if you have any questions or wish to provide feedback, please contact us at BetaPIServer@osisoft.com.

 

Thank you for your continued engagement.

 

Regards,

 

PI Server Team

 

 

After reading some interesting articles about the next version of Visual Studio, I have decided to try it and install the CTP 3 version of Visual Studio 14. If you also want to try, you can download Visual Studio 14 CTP 3 for free under this site

 

There are a lot of enhancements of the product but I want to talk specifically about one of them which I believe adds a lot of values to this community. It is called PerfTips.

 

Many of the threads in this community are related to performance. The custom applications should not only work properly but it is desirable to work as efficiently as possible. Under the vCampus Library, there are some white papers only focused on code optimization.

 

PerfTips is a new editor feature whose purpose is to eliminate the barriers between writing code and performance monitor. It displays the time execution for a method directly in the editor while stepping in through your code.

 

Let’s give a practical demonstration! If you want to know the execution time of the method PIServer.Connect() which obviously connects to the PI Data Archive, it will be displayed as soon as you pass through that line on the editor. Please refer to Figure1 which shows the screenshot of this example.

 

 

 

4503.fig1.png

 

 

 

Figure 1 - Time execution of the PIServer.Connect() method using Visual Studio 14 CTP3.

 

 

 

What about the execution time to get all values from the sinusoid PI Point form the last ten days? If we continue the program execution we will find the answer.

 

 

 

 

 

7065.fig2.png

 

Figure 2 - Time execution of the PIPoint.RecordedValues method using Visual Studio 14 CTP3.

 

 

 

You should be aware of that sometimes the first operation may take longer than subsequent calls, so the initial number returned should be taken with a grain of salt.  

 

 If you are interested in showing only the time execution which are higher than a limit, Visual Studio lets you configure it on its Options window.

 

 

 

4214.fig3.png

 

Figure 3 - PerfTips options in Visual Studio 14 CTP3.

 

 

 

Remember that you cannot install this product if you have another version of Visual Studio already installed on your machine. Microsoft recommends you to install it on new virtual machine.

 

If you want to take advantage of all of the product new features make sure to install it on Windows 8.1 and not one of its previous versions.

 

Hope you have enjoyed this tip!

 

 

Introduction

 

On my previous blog post, I have shown you how to install PHP and how to develop a simple PHP application in Eclipse. On another blog post, we have developed a web application with jQuery/JavaScript which have access to the PI System through PI Web API. This time, I will show you how to develop a similar application not using jQuery/JavaScript but PHP only.

 

What is the different between a web application developed in jQuery and PHP?

 

The main difference is that PHP is a server-side language while jQuery/JavaScript is a client-side language.

 

On the web application with jQuery, when the browser access the web page, the web server sends the HTML pages and the required JavaScript scripts to the browser. The browser is the one who calls the PI Web API which sends the PI System data back to it. The browser then displays the received data to the user in a HTML page.

 

The main disadvantage of this option is security. As the browser is the one who makes the calls to PI Web API, the end user has access to the JavaScript files which contains information concerning which resources are being used by the application including the address of PI Web API and all the GET and POST requests. It does not mean that is not secure but sometimes people want to hide this type of information.

 

We are going to realize that this same web application developed on PHP works a little different. When the browser access the similar page the web server calls the PI Web API which sends the PI System data back to it. Then the web server generates the HTML pages containing the data received and sends to the browser. This way the end user would not have any idea about how and where this data is coming from.

 

It is important to note that PHP is one option for server-side programming. ASP.NET is another alternative to take the benefits of this approach. If you choose ASP.NET, you might consider taking advantage of PI AF SDK which is a .NET library. You cannot use PI AF SDK in PHP applications.

 

PHP Web Application

 

The source code package from this application is available on this GitHub repository. It is very similar to the one developed in jQuery/JavaScript. It actually uses the same Cascate Style Sheet called default.css. There are more two php files in this PHP proejct:

  • Piwebapi_wrapper.php which is the PHP class responsible for connecting and getting data from PI Web API. It does not embed any HTML5 code snippet. There are only static methods used to connect to PI Web API. There is a private method called GetJSONObject() responsable for getting the HTTP response and converting it to a JSON object. Below is the code snippet:

 

<?php
class PIWebAPI
{     
     public static function CheckIfPIServerExists($piServerName)
     {
          $base_service_url = "https://marc-web-sql/piwebapi/";
          $url = $base_service_url . "dataservers";
          $obj = PIWebAPI::GetJSONObject($url);
          foreach($obj->Items as $myServer)
          {
               if(strtolower($myServer->Name)==strtolower($piServerName))
               {
                    return(true);
               }     
          }
          return (false);
     }

     public static function CheckIfPIPointExists($piServerName, $piPointName)
     {
          $base_service_url = "https://marc-web-sql/piwebapi/";
          $url = $base_service_url . "points?path=\\\\" . $piServerName . "\\" . $piPointName;
          $obj1 = PIWebAPI::GetJSONObject($url);
          try {
          if(($obj1->Name)!=null)
          {
               return (true);
          }
          return (false);          
          }
          catch (Exception $e)
          {

          }
     }

     public static function GetSnapshot($piServerName, $piPointName)
     {
          $base_service_url = "https://marc-web-sql/piwebapi/";
          $service_url = $base_service_url . "points?path=\\\\" . $piServerName . "\\" . $piPointName;
          $obj_pipoint = PIWebAPI::GetJSONObject($service_url);
          $url = $obj_pipoint->Links->Value;
          $obj_snapshot = PIWebAPI::GetJSONObject($url);
          return ($obj_snapshot);

     }

     public static function GetRecordedValues($piServerName, $piPointName,$startTime,$endTime)
     {
          $base_service_url = "https://marc-web-sql/piwebapi/";
          $service_url = $base_service_url . "points?path=\\\\" . $piServerName . "\\" . $piPointName;
          $obj_pipoint = PIWebAPI::GetJSONObject($service_url);
          $url = $obj_pipoint->Links->{'RecordedData'} ."?starttime=" . $startTime . "&endtime=" . $endTime;
          $obj_rec = PIWebAPI::GetJSONObject($url);
          return ($obj_rec);

     }

     public static function  GeInterpolatedValues($piServerName, $piPointName,$startTime,$endTime,$interval)
     {
          $base_service_url = "https://marc-web-sql/piwebapi/";
          $service_url = $base_service_url . "points?path=\\\\" . $piServerName . "\\" . $piPointName;
          $obj_pipoint = PIWebAPI::GetJSONObject($service_url);
          $url = $obj_pipoint->Links->{'InterpolatedData'} ."?starttime=" . $startTime . "&endtime=" . $endTime . "&interval=" . $interval;
          $obj_int = PIWebAPI::GetJSONObject($url);
          return ($obj_int);

     }

     private static function GetJSONObject($url)
     {

          $ch = curl_init($url);
          curl_setopt($ch, CURLOPT_HEADER, false);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
          curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
          //header('Content-type: application/json');
          $result = curl_exec($ch);
          $json_o=json_decode($result);
          return ($json_o);
     }     
}

 

 

 

  • Piwebapi_data_retrieval.php is responsible for displaying the HTML pages for the end user. On the web application developed using jQuery there were two HTML pages: pi_data_request.html and pi_data_result.html. The first was used to display the data request form and the second shows the page with PI data if the inputs from the request form were correct. In this case, both pages has been merged to this php file. Below is the code snippet of this file with my comments:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="common.css" rel="stylesheet" />
<title>PI Web API and PHP Intergration test</title>
</head>
<body>

<?php
//include_once is used to reference the PHP class responsable for connecting to PI Web API.
include_once ("piwebapi.class.php");


//The browser will make a GET request when called this page for the first time. Therefore isset ( $_POST ["step"] ) will be false.
//When the request is submitted, isset ( $_POST ["step"] ) will be true;

if (isset ( $_POST ["step"] ) and $_POST ["step"] > 0) {

     //We need to get the POST data and store in PHP variables for later use.
     $piServerName = $_POST["piServerName"];
     $piPointName = $_POST["piPointName"];
     $startTime =  $_POST["startTime"];
     $endTime =  $_POST["endTime"];
     $interval =  $_POST["interval"];
     $gsnap =  $_POST["getsnap"];
     $grec =  $_POST["getrec"];
     $gint =  $_POST["getint"];


     //Checking on the PI Web API PHP class if the PI Server name provided is valid.
     $PIServerExists = PIWebAPI::CheckIfPIServerExists ( $piServerName );
     $PIPointExists=false;
     if ($PIServerExists==true)
     {
          //Checking on the PI Web API PHP class if the PI Point name provided is valid.
          $PIPointExists = PIWebAPI::CheckIfPIPointExists ( $piServerName, $piPointName );
     }

     //Calls a PHP method to embed HTML code in response. The same is true for other methods starting with "display"
     //The HTML code is generate according to the input variables of the method (PI Web API response). Therefore, it is a dynamic page.

     displayTitle ( $piPointName );
     displayInfo ( $piServerName, $piPointName, $startTime, $endTime, $interval, $PIServerExists, $PIPointExists );

     if (($PIServerExists==true) && ($PIPointExists==true))
     {
          $SinusoidSnap = PIWebAPI::GetSnapshot ( $piServerName, $piPointName );
          $SinusoidRec = PIWebAPI::GetRecordedValues ( $piServerName, $piPointName, $startTime, $endTime );
          $SinusoidInt = PIWebAPI::GeInterpolatedValues ( $piServerName, $piPointName, $startTime, $endTime, $interval );
         if ($gsnap=="option1")
         {
               displaySnapValues($SinusoidSnap);
         }
         if ($grec=="option1")
         {
              displayRecValues($SinusoidRec);
         }
         if ($gint=="option1")
         {
              displayIntValues($SinusoidInt);
         }
     }

} 
//Display the request form
else {
     displayRequestDataForm ();
}


//When this function is called, PHP will display only the request form.
function displayRequestDataForm() {
     ?>

<h1>Request PI Data</h1>
     <p>Please fill in your details below and click  on "Get PI
          Data". Fields marked with an asterisk (*) are required.</p>
     <form action="piwebapi_data_retrieval.php" method="post">
          <div style='width: 30em;'>

                    <label     for='piServerName'>PI Server Name *</label> 
                    <input type='hidden' name='step' value='1' /> 
                    <input type='text' name='piServerName' id='piServerName' value='' /> <label
                    for='piPointName'>PI Point name *</label> <input type='text'
                    name='piPointName' id='piPointName' value='' /> <label for='startTime'>Start
                    time *</label> <input type='text' name='startTime' id='startTime'
                    value='' /> <label for='endTime'>End time *</label> <input
                    type='text' name='endTime' id='endTime' value='' /> <label
                    for='interval'>Interval *</label> <input type='text' name='interval'
                    id='interval' value='' /> <label for='getsnap'>Get Snapshot?</label>
               <select name='getsnap' id='getsnap' size='1'>
                    <option value='option1'>Yes</option>
                    <option value='option2'>No</option>
               </select> <label for='getrec'>Get Recorded Data?</label> <select
                    name='getrec' id='getrec' size='1'>
                    <option value='option1'>Yes</option>
                    <option value='option2'>No</option>
               </select> <label for='getint'>Get Interpolated Data?</label> <select
                    name='getint' id='getint' size='1'>
                    <option value='option1'>Yes</option>
                    <option value='option2'>No</option>
               </select>

               <div style='clear: both;'>
                    <input type='submit' name='submitButton' id='submitButton' value='Get PI Data!' /> 
                    <input type='button' name='Button' id='DefaultButton' onclick='defaultValues()' value='Default Values' style='margin-right: 20px;' />
               </div>
          </div>
     </form>
        <script>
        function defaultValues() {
            var piServerName = document.getElementById('piServerName');
            var piPointName = document.getElementById('piPointName');
            var StartTime = document.getElementById('startTime');
            var EndTime = document.getElementById('endTime');
            var Interval = document.getElementById('interval');
            piServerName.value = 'MARC-PI2014';
            piPointName.value = 'SINUSOID';
            StartTime.value = '*-1d';
            EndTime.value = '*';
            Interval.value = '1h';
        }
    </script>

               <?php
}
function displayTitle($piPointName) {
     ?>
     <h1>Displaying <?php echo $piPointName?> data</h1>     
               <?php
}
function displayInfo($piServerName, $piPointName, $startTime, $endTime, $interval, $PIServerExists, $PIPointExists) {
     ?>
     <h2>Connection information</h2>
     <br />
     <table style='width: 20em; border: 1px solid #666;'>
          <tr>
               <th>Property</th>
               <th>Value</th>
          </tr>

          <tr>
               <td>PI Server</td>
               <td><?php echo $piServerName ?></td>
          </tr>
          <tr>
               <td>PI Point</td>
               <td><?php echo $piPointName ?></td>
          </tr>
          <tr>
               <td>Start time</td>
               <td><?php echo $startTime ?></td>
          </tr>
          <tr>
               <td>End time</td>
               <td><?php echo $endTime ?></td>
          </tr>
          <tr>
               <td>Interval</td>
               <td><?php echo $interval ?></td>
          </tr>

          <tr>
               <td>Does the PI Server exist?</td>
               <td><?php
     if ($PIServerExists == true) {
          echo 'Yes';
     } else {
          echo 'No';
     }
     ?></td>
          </tr>
          <tr>
               <td>Does the PI Point exist?</td>
               <td><?php

     if ($PIPointExists == true) {
          echo 'Yes';
     } else {
          echo 'No';
     }
     ?></td>
          </tr>
     </table>     
          <?php
}
function displaySnapValues($SinusoidSnap) {
     ?>
     <h2>Snapshot Value of Sinusoid</h2>
     <br />
     <table style='width: 20em; border: 1px solid #666;'>
          <tr>
               <th>Value</th>
               <th>Timestamp</th>
          </tr>
          <tr>
               <td><?php echo $SinusoidSnap->Value; ?></td>
               <td><?php echo $SinusoidSnap->Timestamp; ?></td>
          </tr>
     </table>
     <br />
     <br />
          <?php
}
function displayRecValues($SinusoidRec) {
     ?>

     <h2>Recorded Values of Sinusoid</h2>
     <br />
     <table style='width: 20em; border: 1px solid #666;'>
          <tr>
               <th>Value</th>
               <th>Timestamp</th>
          </tr><?php
     foreach ( $SinusoidRec->Items as $Value ) {
          echo '\n<tr>';
          echo '\n\t<td>' . $Value->Value . '</td>';
          echo '\n\t<td>' . $Value->Timestamp . '</td>';
          echo '\n</tr>';
     }
     ?>

     </table>

     <br />
     <br />
     <?php
}
function displayIntValues($SinusoidInt) {
     ?>
     <h2>Interpolated Values of Sinusoid</h2>
     <br />
     <table style='width: 20em; border: 1px solid #666;'>
          <tr>
               <th>Value</th>
               <th>Timestamp</th>
          </tr>
          <?php
     foreach ( $SinusoidInt->Items as $Value ) {
          echo '\n<tr>';
          echo '\n\t<td>' . $Value->Value . '</td>';
          echo '\n\t<td>' . $Value->Timestamp . '</td>';
          echo '\n</tr>';
     }
     ?>
     </table>
     <?php
}

?>
</body>
</html>

Testing the PHP application

 

As you have realized, piwebapi_data_retrieval.php will display the data request form unless isset( $_POST ["step"]) is equal to true and $_POST ["step"] is higher than 0. When the browser access this file for the first time through the GET request, it will display the request form due to the fact that isset( $_POST ["step"]) would be false. Figure 1 shows the screenshot of data request form.

 

 

 

6708.fig1.png

 

Figure 1 – Data Request Form

 

After filling the values properly, open the developer tools of your browser. In my case I am using Google Chrome. When I click on the button “Get PI Data!”, it appears on the developer tools that a POST request was made to the web server (and not to the PI Web API). Please refer to Figure 2 for more information.

 

 

 

8130.fig2.png

 

Figure 2 – Using Google Chrome Developer Tools to find the POST request of the application.

 

 

 

If you request for more information of this POST request, you will see all the variables sent which will be stored under the php $_POST variable. Please refer to Figure 3 which shows those variables on the Google Chrome Developer Tools.

 

 

 

5543.fig3.png

 

Figure 3 – Using Google Chrome Developer Tools to find the details of the POST request of the application.

 

I hope that with this example you have understood how this PHP program works in general.

 

Conclusion

 

This purpose of this blog post is to provide you an example of a PHP web application on top of the PI Web API.  On the next blog post, we are going to develop a custom data reference which will show the first paragraph of a wikipedia article after searching for a given a name. Stay tuned!

I'm pleased to announce that the next generation Buffer Subsystem is now available via the following setup kits:

  • AF Client 2014 R2, version 2..6.1.6238
  • PI SDK 2014, version 1.4.4.484

Highlights:

  • PIbufss now supports buffering to multiple servers and collectives. This is an important feature for clients that rely on PIBufSS to distribute data across a collective. Previously you had to choose one PI collective to buffer to, now you don't have to choose.
  • PIbufss now sends data 2-3 times faster than previous versions (assuming the necessary additional bandwidth is available.) This not only means higher sustained data rates, but it also means that after a network outage any data queued up will be unloaded faster, resulting in users getting live updates that much sooner.
    • New auto-tuning feature attempts to maximize throughput by finding the optimal number of events to send per message
  • PIbufss is now more robust when recovering from an uncontrolled shutdown. When running prior versions it was not uncommon after a power outage for pibufss to stop sending data to the server due to a queue file getting corrupt. This would require manual intervention to dismount and rename/repair the queue. PIbufss 4.3 is built on newer queue technology that can recover from these situations.
  • Improvements for monitoring the health of PIBufSS
    • A single health status that provides indication of the health of PIBufSS
    • A queue capacity counter indicates in the event of a network outage how long pibufss can buffer before you start losing data.
    • A new three tired health diagnostics capability with drilled down capabilities using performance counters
    • New command line options and enhancements

     

  • New Buffering Manager, which includes:
  • An Upgrade wizard to help migrate from BufServ to PIBufSS 
  • An Add Server wizard to help users through the process of configuring buffering to a new server.
  • A Dashboard for configuring and monitoring buffering.Integrated 
  • Buffering Manager integration with the PISDKUtility, PI System Explorer and the PI Interface Configuration Utility (version 1.4.15.46 - recently released) 

 

PHP is a server-side scripting language designed for web development but also used as a general-purpose programming language. In general, PHP web applications run on a web server, and serves web pages to visitors on request. One key features of PHP is that you can embed PHP code within HTML web pages, making it very easy for you to create dynamic content quickly.

Why you should you consider using PHP?

First of all, PHP is completely free and it is very easy to learn when compared to other scripting languages.

 

One of the great features of PHP is that it is cross-platform which means that you can run PHP programs on Windows, Linux, Mac OS and Solaris among others. This is also true for web servers as PHP engine can be integrated with all common web servers, including IIS, Apache and Zeus.

 

According to the web site w3techs.com, PHP is used by 82.1% of all the websites whose server-side programming language we know by the time of this writing reflecting its importance on the market.

 

If you search on the web about the advantages and disadvantages of PHP when compared to ASP.NET MVC, for instance, you will note the majority of the answers are that it depends. That is why in my humble opinion I believe that it is important considering this technology when choosing the programming language for your web application.

Integrated Development Environment options

For developers who loves Visual Studio, there is a good and a bad news for you. The good news is that there are some Visual Studio extensions that let you develop PHP web application using Visual Studio, taking advantage of its main features. Nevertheless, the bad news is that I couldn’t find any free extension. One of them is called “PHP Tools for Visual Studio”. After installing this extension, you will realize that you can only use it for free during a small period of time to test it. For more information please visit this page.

 

For this reason, I will show you how to develop PHP using Eclipse. I am going to write some blog posts about Java so this is a good opportunity for you to get started with Eclipse, one of the main IDE for Java.

Installing PDT on Eclipse

Eclipse is an integrated development environment (IDE). It contains a base workspace and an extensible plug-in system for customizing the environment. It is mostly used for Java development but it can be used to PHP development as well. If do not have Eclipse, you can download it from Eclipse web site.

 

In order to develop PHP in Eclipse, one of the options is to install the PDT (PHP Development Tools) package.  Please follow the procedure in order to install this package:

  1. Open Eclipse (my version is Kepler Service Release 2).
  2. Go to Help --> Install New Software...
  3. Expand the "Work with" drop down and select: "Kepler - http://download.eclipse.org/releases/kepler".
  4. Expand "Programming Languages" from the list.
  5. Check PHP Development Tools (PDT) SDK Feature.
  6. Click "Next >" at the bottom and follow the further instruction of Eclipse.
  7. After successful installation of PDT: Go to Window --> Preferences and make sure you will find PHP listed on the left panel.

Installing XAMPP

On the previous section, it was shown how to install the package for Eclipse in order to develop in PHP. Nevertheless, there are many products that still need to be installed like Apache HTTP Server and PHP binaries. In this blog post, we are going to install it using a solution package called XAMPPP, which is a free and open source cross-platform web server solution stack package, consisting mainly of the Apache HTTP Server, MySQL database, and interpreters for scripts written in the PHP and Perl programming languages.

 

In my case, I have downloaded version 1.8.1 from this website but more recent versions should work as well. After the download is complete just execute the setup and follow the steps.

Setting up XDebug

If you want to have the possibility to debug PHP code within Eclipse you should configure XDebug or Zend. In this blog post, we are going to set up the XDebug.

 

XDebug is an opensource Debugger and Profiler for PHP. PDT has built in support for XDebug, which allows you to step-debug through your PHP projects. It is already included on the XAMPP solution.

 

In order to enable XDebug, the file php.ini located on C:\xampp\php\php.ini needs to be edited as shown below:

 

 

 

[XDebug]
zend_extension = "C:\xampp\php\ext\php_xdebug.dll"
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "C:\xampp\tmp"
xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "127.0.0.1"
xdebug.trace_output_dir = "C:\xampp\tmp"

 

 

 

After saving php.ini, restart Apache through XAMPP Control Panel as shown on Figure 1.

 

8446.fig1.jpg

 

Figure 1 – XAMPP Control Panel used to start and stop Apache.

 

 

 

 Open Eclipse and make sure that the workspace you are working is: \xampp\htdocs.  This folder is the root folder of your web server.

 

When Eclipse is loaded, click on WindowàPreference. On the left pane, select PHP à Debug. Under Default Settings, choose XDebug for the PHP Debugger as shown on Figure 2 and then click “Apply” and then “OK”.

 

 

 

 8015.fig2.jpg

 

Figure 2 – PHP Debug settings on Eclipse.

 

 

 

At this point, you shall be ready to create your first PHP web application.

 

I have written this procedure by watching this video on youtube. Watching this video might help you understand better even though we are using more recent product versions in case you have questions.

Your first PHP program

On package explorer located on the left pane of Eclipse, right-click and select Newà Project…

 

On the New Project window, select PHP Project under PHP folder. Type on the project name “HelloWorld” and then click on finished making sure that the project will be created under the folder C:\xampp\htdocs.

 

Now, there is a folder HelloWorld on Package Explorer. Right click on it and select New à Other. A window called New will open where you should select “PHP File” and name this new file helloworld.php.

 

 

 

Copy and paste the following content of helloworld.php:

 

 

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Greetings</title>
<link rel="stylesheet" type="text/css" href="common.css" />
</head>
<body>
<?php
echo "<h1>Hello World!!</h1>";
$hour = date ("G");
if ($hour >= 5 && $hour < 12) {
      echo "<h1>Good morning!</h1>";
} elseif ($hour >= 12 && $hour < 18) {
      echo "<h1>Good afternoon!</h1>";
} elseif ($hour >= 18 && $hour < 22) {
      echo "<h1>Good evening!</h1>";
} else {
      echo "<h1>Good night!</h1>";
}
?>
</body>
</html>

 

 

At this point, your project in Eclipse should be similar to the screenshot shown on Figure 3.

 

 

 

2548.fig3.jpg

 

Figure 3 – HelloWorld project in Eclipse

 

 

 

This is a good example for showing that PHP code is embedded within the HTML markup. If you read the code snippet carefully, you will note that the application will show “Good morning!”, “Good afternoon!”, “Good evening!” or “Good night!” according to the value of the variable $hour, which corresponds to the current hour. The function date("G") is responsible for getting the current hour of the day.

 

If you insert a breakpoint on line 13 and debug your project, you will be able to check the values stored by the variables on the variables window as shown on Figure 4.

 

3755.fig4.jpg

 

Figure 4 – Debugging HelloWorld PHP project in Eclipse

Conclusion

This purpose of this blog post is to help you set up your environment to develop PHP web applications. On the next blog post, we are going to develop the same web application that receives data from the PI System through PI Web API but not using jQuery \JavaScript but PHP. The advantages and disadvantages of this this options are going to be discussed as well. Stay tuned!!

目的:

 

本文目的为介绍创建数据引用的方法,请不要将本文例子作为产品使用,这里有一个性能的问题,该问题将在本文最后予以说明。

 

背景:

 

本文创建的这个例子,是读取使用PI Point Array Data Reference创建的PI AF attribute中的单一值。PI Point Array Data Reference可以使一个PI AF attribute获得多个PI点的值,并以一个值列表的方式进行展示。然而,如果工作中对于这个列表中的某一个值感兴趣,目前没有方法可以直接将这个感兴趣的值使用另一个PI AF attribute在PI AF客端展示出来。因此,本文创建的这个例子,可以使用已存在的基于PI Point Array Data Reference的PI AF attribute的名字和单一值在值列表中的编号作为参数,使用另一个PI AF attribute展示出该值。

 

结果:

 

让我们先看一下使用本文例子的展示结果。

 

我们先创建一个基于PI Point Array Data Reference的PI AF attribute,并查看显示出的值列表。

 

8168.1.png

 

之后,我们使用本文创建新的PI AF Data Reference (Array_show)显示一个单一值。

 

例如,Attribute2是一个基于PI Point Array Data Reference的PI AF attribute,下面是使用基于Array_show的Attribute3显示Attribute2中的第一个值:

 

8420.2.png

 

过程:

 

下面是Array_show的制作过程。

 

打开MS VS 2012,并创建一个项目。需要选择”Class Library“, 这是创建.dll文件的要求。本文例子将使用C#代码。

 

4810.3.png

 

项目创建好之后,请加入 “OSIsoft.AFSDK”函数库引用

 

7802.4.png

 

准备:

 

创建.dll项目的GUID。一般在VS的“工具”菜单中均会有这个工具。

 

3107.5.png

 

在项目中加入GUID,以及一些需要的头文件名。同时,该例子需要一个字符串类型的变量传递PI AF attribute的名字,以及一个整形变量传递值编号。

 

2234.6.png

 

主要功能:

 

1. public override string ConfigString

 

熟悉PI AF Data Reference的朋友会注意到在“Setting"按钮下面,会有一串字符。这串字符就是用于将这个attribute的基本配置信息传递给 PI AF Server。如下面的PI Point Data Reference,其可以传递链接的PI Server的信息和点名传递给PI AF Server。

 

2705.7.png

 

因此,对于Array_show来说,有两个参数需要传递给PI AF Server --- 基于PI Point Array Data Reference的PI AF attribute的名字和值编号。

 

 

 
public override string ConfigString
{
    get
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("{0} = {1};", "Target Attribute",target_attribute_name);
        sb.AppendFormat("{0} = {1};", "Index", index);
        return sb.ToString();
    }
    set
    {
        var tokens = value.Split(';');
        foreach (var token in tokens)
        {
            var key = token.Split('=');
            switch (key[0])
            {
                case "Target Attribute":
                    target_attribute_name = key[1];
                    break;
                case "Index":
                    index = Convert.ToInt32(key[1]);
                    break;
            }
        }
        SaveConfigChanges();  // save the change to PI AF Server
 
    }
}

 

 

2. public override AFValue GetValue

 

此方法是给PI AF attribute传递值。本例中,基于Array_show的attribute需要获取另一个attribute中的一个值。因此我们需要使用一个额外的方法获取原始attribute,并传递一个AFAttributeList的类给GetValue方法。原始的attribute的名字是由上述的ConfigString提供的。

 

 

 
public override AFAttributeList GetInputs(object context)
{
    AFAttributeList attribute_list = new AFAttributeList();
    attribute_list.Add(this.GetAttribute(target_attribute_name));  // get the attribute name from the configstring
    return attribute_list;
}
 
public override AFValue GetValue(object context, object timeContext, AFAttributeList inputAttributes, AFValues inputValues)
{
    AFValue result = new AFValue();
    AFValue input = inputValues[0];
    if (input.IsGood)
    {
        result.Timestamp = input.Timestamp;
        Array values = input.Value as Array;
        result.Value = values.GetValue(index - 1); 
    }
    else
    {
        result.Status = AFValueStatus.Bad;
        result.Value = new Exception("Bad Value");
    }
    return result;
}

 

 

3. Support function:

 

PI AF Server需要知道AFDataReference class中的哪些方法被使用到这个项目中。因此,以下3个support function是非常重要的。

 

 

 
public override AFDataReferenceMethod SupportedMethods
{
    get
    {
        return AFDataReferenceMethod.GetValue | AFDataReferenceMethod.GetValues;  // 实际使用GetValue即可。这里列出了GetValues是用于显示如何支持多个function
    }
}
 
public override AFDataMethods SupportedDataMethods
{
    get
    {
        return this.DefaultSupportedDataMethods;
    }
}
 
public override AFDataReferenceContext SupportedContexts
{
    get
    {
        return AFDataReferenceContext.All;
    }
}

 4. 配置编辑器:

 

像PI Point Data Reference,当点击”Settings”按钮后,会有一个配置界面弹出:

 

8171.8.png

 

因此,给一个新的Data Reference创建一个这样的界面,将使得以后使用更加友好和方便。

 

请右击该项目,加入windows form:

 

1680.9.png

 

方便起见,这里仅创建以下的这个简单的编辑器作为例子,这个编辑器可以使用MS VS中的windows form工具制作完成:

 

2604.10.png

 

完成设计后,下面的工作就是给这个编辑器定义功能。这里,我们将传递"Attribute”文本框中的原始attribute的名字,以及“index"数字选择框中的数字作为值编号。

 

 

 
public partial class Array_showEditor : Form
 {
       Array_show _dr;
 
       public Array_showEditor(Array_show dr, bool IsreadOnly)
       {
           InitializeComponent();
           _dr = dr;
           textBox_Attribute.Text = dr.Get_Attribute_Name;
           numericUpDown_Index.Value= dr.Get_Index;
       }
 
       private void button_Cancel_Click(object sender, EventArgs e)
       {
           this.Close();
           this.Dispose();
       }
 
       private void button_OK_Click(object sender, EventArgs e)
       {
           _dr.Get_Attribute_Name = textBox_Attribute.Text;
           _dr.Get_Index = (int)numericUpDown_Index.Value;
           this.Close();
           this.Dispose();
       }
   }

 编辑器创建好之后,请返回项目代码,将这个编辑器加入。

 

 

 
public override Type EditorType
{
    get
    {
        return typeof(Array_showEditor);
    }
}

 这个方法是AFDataReference class中让PI AF Server知道不同的Data Reference将跳出不同的编辑器界面。

 

同时,我们需要另外两个方法来在两个.cs文件中传递”Attribute"和“index"中的值。

 

 

 
public string Get_Attribute_Name
{
    get
    {
        return target_attribute_name;
    }
    set
    {
        if (target_attribute_name != value)
        {
            target_attribute_name = value;
            SaveConfigChanges();
        }
    }
}
 
public int Get_Index
{
    get
    {
        return index;
    }
    set
    {
        if (value != index)
        {
            index = value;
            SaveConfigChanges();
        }
    }
}

 注册:

 

最后的一步是将我们创建好的项目注册到PI AF Server上:

 

1. 创建.dll文件:

 

2318.11.jpg

 

2. 注册这个.dll到PI AF Server上:

 

复制这个.dll文件的全路径,并使用"RegPlugIn.exe"进行注册:

 

7411.12.jpg

 

现在,您可以使用这个新的Data Reference像本文中在“结果”部分一样。

 

注:

 

性能问题是由于所有的输出值将从PI Point Array Data Reference中来。因此,这将比直接从PI Point中来慢很多(Ling Fung Mok --- PI AF SDK Developer)

xwang

Create your own Data Reference

Posted by xwang Employee Sep 1, 2014

Purpose:

 

The aim of this post is to introduce the method on Data Reference creation, please do not use it as a product, as there is the performance issue, which will be explained at the end of this post.

 

 

 

Background:

 

The example I used is to create a Data Reference to read the single value from one existed PI AF Attribute which with PI Point Array Data Reference.  As we know, PI Point Array Data Reference could let the PI AF attribute to get all values from many PI points with one timestamp into one value list.  However, if I am interested in one single value in this value list, it seems no way to get that value out from this attribute to show on PI System Explore via another PI AF attribute directly.  Therefore, I create this Data Reference, passing the existed attribute’s name and the index of the value in the value list as the parameter to fetch this single value, and show it on another attribute.

 

 

 

Rusult:

 

Let us see what the result is for this Data Reference at first.

 

We could set an attribute to use PI Point Array Data Reference (PI PA DR) to show a value list for different PI Point.

 

0844.1.png

 

After that, it will be very easy to use Array_show Data Reference (AS DR) to show a single value from that list by index.

 

For example, I wish to show the first value of “Attribute2”.  It will be clear that the value is shown as Attribute3’s value.

 

4667.2.png

 

 

 

Procedures:

 

Now, let me introduct how to do this Data Reference.

 

Open MS VS 2012, and create a new project.  It will be “Class Library”, as the .dll file is needed.  I use C# code to do this example.

 

7824.3.png

 

After the project created, please add “OSIsoft.AFSDK” as the new reference for this project.

 

6366.4.png

 

 

 

Preparations:

 

The GUID is necessary for the .dll project.  Therefore, please go to create a GUID.  It will be under “TOOLS” menu of VS.

 

3276.5.png

 

Add the GUID and some namespace in this project.  Moreover, please remember to inherit the AFDataReference class, as the main functions to do this project is from this class.

 

We also need to initialize a string type parameter to store the name of the PI AF attribute with PI PA DR, and the integer type parameter to store the index number.

 

4265.6.png

 

 

 

Key functions:

 

The following is the functions for this project.

 

1. public override string ConfigString

 

If familiar with any PI AF Data Reference (PI Point Data Reference for example), there will be a string under “Setting” button.  This string is configuration string, used to transfer some basic information to PI AF Server.  For PI Point Data Reference following, it will provide PI Server name and PI point name to PI AF attribute.

 

4812.7.png

 

Therefore, for AS DR, I decide to transfer 2 information to PI AF Server --- the "attribute name" which PI AF attribute will be with PI PA DR and the "index number" which is to index one single value in the value list.

 

 

 
        public override string ConfigString
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("{0} = {1};", "Target Attribute",target_attribute_name);
                sb.AppendFormat("{0} = {1};", "Index", index);
                return sb.ToString();
            }
            set
            {
                var tokens = value.Split(';');
                foreach (var token in tokens)
                {
                    var key = token.Split('=');
                    switch (key[0])
                    {
                        case "Target Attribute":
                            target_attribute_name = key[1];
                            break;
                        case "Index":
                            index = Convert.ToInt32(key[1]);
                            break;
                    }
                }
                SaveConfigChanges();  // save the change to PI AF Server

            }
        }

 2. public override AFValue GetValue

 

This is the main function to pass the value to one PI AF attribute.  In this project, my original value is from another PI AF attribute with PI PA DR.  Therefore, it is necessary to include another function to pass the original PI AF attribute name to GetValue function.  The name of the original PI AF attribute will be from the ConfigString function (the previous function).

 

 

 
        public override AFAttributeList GetInputs(object context)
        {
            AFAttributeList attribute_list = new AFAttributeList();
            attribute_list.Add(this.GetAttribute(target_attribute_name));  // get the attribute name from the configstring
            return attribute_list;
        }

        public override AFValue GetValue(object context, object timeContext, AFAttributeList inputAttributes, AFValues inputValues)
        {
            AFValue result = new AFValue();
            AFValue input = inputValues[0];
            if (input.IsGood)
            {
                result.Timestamp = input.Timestamp;
                Array values = input.Value as Array;
                result.Value = values.GetValue(index - 1);  
            }
            else
            {
                result.Status = AFValueStatus.Bad;
                result.Value = new Exception("Bad Value");
            }
            return result;
        }

 3. Support function:

 

PI AF Server needs to know which functions in AFDataReference class will be support for this project.  Therefore, the following 3 support function is very important for this project:

 

 

 
        public override AFDataReferenceMethod SupportedMethods
        {
            get
            {
                return AFDataReferenceMethod.GetValue | AFDataReferenceMethod.GetValues;  // Actually, only GetValue is enough for this project.  This is just to show how to support many functions inherit from AFDataReference class
            }
        }
   
        public override AFDataMethods SupportedDataMethods
        {
            get
            {
                return this.DefaultSupportedDataMethods;
            }
        }

        public override AFDataReferenceContext SupportedContexts
        {
            get
            {
                return AFDataReferenceContext.All;
            }
        }

 4. Editor:

 

Like PI Point Data Reference, after click “Settings” button, there will be a friendly editor to help us make the configuration string.  For example, the following is PI Point Data Reference's Editor:

 

5228.8.png

 

Therefore, to create an editor should be better for this project.

 

Please right click the project, and add a windows form to this project:

 

7674.9.png

 

To easy show, I just create a very simple editor like following, it should be easy to create by VS windows form tools:

 

5684.10.png

 

Then, I used the following code to define the function of this editor.  The function is very easy that “Attribute” field will pass the original PI PA DR attribute’s name, and the index will pass the index number.

 

 

 
 public partial class Array_showEditor : Form
  {
        Array_show _dr;

        public Array_showEditor(Array_show dr, bool IsreadOnly)
        {
            InitializeComponent();
            _dr = dr;
            textBox_Attribute.Text = dr.Get_Attribute_Name;
            numericUpDown_Index.Value= dr.Get_Index;
        }

        private void button_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
        }

        private void button_OK_Click(object sender, EventArgs e)
        {
            _dr.Get_Attribute_Name = textBox_Attribute.Text;
            _dr.Get_Index = (int)numericUpDown_Index.Value;
            this.Close();
            this.Dispose();
        }
    }

 After finish the editor, we will back the project code to make some functions and let the editor work.  The most important function should be:

 

 

 
        public override Type EditorType
        {
            get
            {
                return typeof(Array_showEditor);
            }
        }

This function is inherited from AFDataReference class to let PI AF Server know the “Setting” button will invoke our new editor for our new Data Reference.

 

We also need 2 functions to transfer the value in “Attribute” field and “index” field between our 2 .cs files.

 

 

 
        public string Get_Attribute_Name
        {
            get
            {
                return target_attribute_name;
            }
            set
            {
                if (target_attribute_name != value)
                {
                    target_attribute_name = value;
                    SaveConfigChanges();
                }
            }
        }

        public int Get_Index
        {
            get
            {
                return index;
            }
            set
            {
                if (value != index)
                {
                    index = value;
                    SaveConfigChanges();
                }
            }
        }

 

 

Registration:

 

The last step is to create this .dll file and register it in to PI AF Server.

 

1. Create .dll file:

 

"Build" this project, and you could see the .dll location in "Output" window:

 

0317.11.jpg

 

2. Register this .dll file to PI AF Server:

 

Copy the full path of this .dll file, and use "RegPlugIn.exe" to register this .dll file to PI AF Server:

 

1323.12.jpg

 

Now, you could use this new Data Reference for your PI AF attribute as the "Result" part of this post.

 

 

 

Notes:

 

The performance issue is that all the out value will be from the value list made by PI Point Array Data Reference.  Therefore, it will be slower than read it from the PI point directly (From Ling Fung Mok --- PI AF SDK Developer).

Filter Blog

By date: By tag: