stang

PI SDK 开发基础篇

Blog Post created by stang on Aug 19, 2016

: 为了更好的利用站内资源营造一个更好的中文开发资源空间,本文是转发修正帖,原作者为OSIsoft技术工程师王曦(Xi Wang),原帖地址:PI SDK 基础篇

 

本帖旨在介绍使用PI SDK进行开发之初的基本功能。如服务器连接,搜索PI点,读取快照值,读取归档值等。基本程序提供C++C#两种语言的编写方法。这两种语言都需调用PI SDK函数包中一些基本函数库:PISDKPISDKCommonPITimeServer。

说明:本帖中的程序段仅适用于功能性的介绍,不宜直接复制使用,因为程序段之中没有加入任何错误警告功能或抛出例外

说明:PI SDK 是过时的技术

 

 

1. 连PI接服务器

 

C++ 程序

 

#include "stdafx.h"
#include <iostream>
#include <string>
#include "ATLComTime.h"   //for COleDateTime

#import "C:\Program Files\PIPC\PISDK\PISDKCommon.dll" no_namespace
#import "C:\Program Files\PIPC\PISDK\PITimeServer.dll" no_namespace
#import "C:\Program Files\PIPC\PISDK\PISDK.dll" rename("Connected", "PISDKConnected") no_namespace

IPISDKPtr       spPISDK = NULL; //定义新的PISDK指针类
ServerPtr       spServer = NULL; //定义新的PI服务器指针类

// 定义PI服务器连接函数 --- PIServerConnet()

static ServerPtr PIServerConnect(_bstr_t servername)
{
    ::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); //初始化COM
    spPISDK.CreateInstance(__uuidof(PISDK)); //在COM中初始化新的PISDK指针类
    spServer = spPISDK->GetServers()->GetItem(servername);  //通过传递进来的服务器名来连接该服务器。   注:需要使用_bstr_t字符串类型参数
    return spServer; //返回PI服务器指针
}

int _tmain(int argc, _TCHAR* argv[])
{
    _bstr_t servername = "XWANG-KQ8HT8KU8"; //定义服务器名。
    spServer = PIServerConnect(servername); //接收返回的的PI服务器指针类型
    return 0;
}

 

C#程序

 

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using PISDK;
 using PISDKCommon;
 using PITimeServer;

namespace DemPISDK
 {
    class Program
    {
        static void Main(string[] args)
        {
            Server server = ConnectToServer("servername");  //获取返回的PI服务器类型
        }

         private static Server ConnectToServer(string servername)
         {
             PISDK.PISDK pisdk = new PISDK.PISDK();            //定义新的PISDK类
             Server server = null; //定义新的PI服务器类
             server = pisdk.Servers[servername]; //获取服务器名
            server.Open(); //连接PI数据库
             return server;      
         }
    }
}

 

以下所有的功能都将在连接上PI 服务器之后才能实现,因此,将省略PI服务器连接这一部分

 

2. 创建PI点

 

创建单点

 

C++ 程序

 

static PIPointPtr CreatePIPoint (ServerPtr spServer)
 {
    _NamedValuesPtr nvAttribues = NULL; // 定义PI点的属性
    return spServer->PIPoints->Add("test1","classic",PointTypeConstants::pttypFloat32,nvAttribues); // 创建PI点
 }

 

C# 程序

 

private static PIPoint CreatePIPoint ( Server server)
{
    NamedValues nvAttributes nvAttributes = new NamedValues(); // 定义PI点的属性
    return server.PIPoints.Add("test1", "classic", PointTypeConstants.pttypeFloat32, nvAttributes); // 创建PI点
}

创建多点

 

C++程序

 

static void PointsCreation (ServerPtr spServer)
{
    IPIPoints2Ptr spipipoints2 = (IPIPoints2Ptr)spServer->PIPoints; // 创建 IPIPoints2指针,并让其指向传入ServerPtr指针的那片区域

     _variant_t description = "test"; // 创建“描述”属性的variant类型
     _variant_t engunits = "m"; // 创建“工程单位”属性的variant类型
     _variant_t classtype = "classic"; // 创建“点的种类”属性的variant类型
     _variant_t pt = PointTypeConstants::pttypFloat32; // 创建“点的数据类型”属性的variant类型
 
     _NamedValuesPtr nvAttributes; // 创建一个指向点属性的指针
    nvAttributes.CreateInstance(__uuidof(NamedValues)); // 为这个指针创建一片空间,用于存储点的属性
    nvAttributes->Add("descriptor", &description); // 增加“描述”属性
    nvAttributes->Add("engunits", &engunits);
    nvAttributes->Add("ptclassName", &classtype);
    nvAttributes->Add("pointType", &pt);
 
     _variant_t var_nvAttributes; // 创建一个variant类型的指针
    VariantInit(&var_nvAttributes); // 初始化对于上面指针的二级指针为VT_EMPTY
     V_VT (&var_nvAttributes) = VT_DISPATCH; // 将这个二级指针转变为VT_DISPATCH类型
     V_DISPATCH(&var_nvAttributes) = nvAttributes; // 将这个二级指针指向点属相的指针
 
     _NamedValuesPtr nvPoints; // 创建一个定义PI点表的指针
    nvPoints.CreateInstance(__uuidof(NamedValues)); // 为该指针定义一片空间
     nvPoints->Add("test2", &var_nvAttributes); // 加入点名,及其属性
     nvPoints->Add("test3", &var_nvAttributes);
 
     _PIErrorsPtr Errors; // 创建一个PIError的指针
     Errors.CreateInstance(__uuidof(PIErrors)); // 为该指针定义一片空间
     _PIErrors **ErrorsPtr = &Errors; // 为该指针定义一个二级指针
 
     _PointListPtr PointList; // 创建一个PointList的指针
    PointList.CreateInstance(__uuidof(PointList)); // 为该指针定义一片空间
     _PointList **PointListPtr = &PointList; // 为该指针定义一个二级指针 
    spipipoints2->AddTags(nvPoints,ErrorsPtr,PointListPtr,NULL); // 使用之前定义的IPIPoints2类型的指针加入点表
}

这个程序相对较复杂,主要使用了C++中的标准DISPATCH接口类型

 

C#程序

 

private static PointList CreatePIPoints(Server server)
 {
    NamedValues nvTags = new NamedValues();
 
     NamedValues nvAttributes = new NamedValues();
 
    nvAttributes.Add("descriptor", "Test Description");
    nvAttributes.Add("ptclassname", "classic");
    nvAttributes.Add("pointsource", "L");
    nvAttributes.Add("pointtype", PointTypeConstants.pttypFloat32);
 
    nvTags.Add("testAddTag", nvAttributes);
    nvTags.Add("testAddTags001", nvAttributes);
    nvTags.Add("testAddTags002", nvAttributes);
    nvTags.Add("testAddTags003", nvAttributes);
 
     PIErrors errs = new PIErrors();
     PointList ptlist = new PointList();
     IPIPoints2 ipipoints2 = (IPIPoints2)server.PIPoints;
    ipipoints2.AddTags(nvTags, out errs, out ptlist);
 
     return ptlist;
 }

相比起C++程序,C#程序更为通俗

 

这两段程序值得注意的是,在点的创建过程中,点属性中的pointclass和pointtype是必须创建并设定的,如果没有,所有的点是不能被创建的

 

3. 搜点

 

C++程序

 

static PIPointPtr GetPIPointsByName(ServerPtr server, _bstr_t tagname)
 {
    return server->PIPoints->GetItem(tagname); // 返回一个PIPoint类型的指针
}

 

C#程序:

 

private static PIPoint GetPIPointByName(Server server, String tagname)
 {
    return server.PIPoints[tagname]; // 返回一个PIPoint类型的指针
 }

 

按条件搜点表


C++程序

 

static _PointListPtr SearchPIPoints(ServerPtr server, _bstr_t condition)
 {
    return server->GetPoints(condition, NULL);            //返回PointList指针类
 }

 

C#程序

 

private static PointList SearchPIPoints(Server server, String condition)
 {
    return server.GetPoints(condition);                   
 }

4. 编辑点

 

按编辑单点的特定属性

 

C++程序

 

static void TagEdit (ServerPtr spServer)
{
    _bstr_t tagname = "test2"; // 给出点名
     PIPointPtr spPoint; // 创建PIPointPtr类指针接收点的一切信息
     spPoint = spServer->PIPoints->GetItem(tagname); // 将点名传给spPoint指针
 
     _bstr_t tag_description = "descriptor"; // 定义需要调整的属性
     PointAttributePtr pa_attribute = spPoint->PointAttributes->GetItem(tag_description);   // 将属性指针指向之前定义的需要调整的属性
     spPoint->PointAttributes->ReadOnly = VARIANT_FALSE; // 将只读属性关闭
     pa_attribute->Value = "test for tag edit"; // 更改需要调整属性的值
     spPoint->PointAttributes->ReadOnly = VARIANT_TRUE; // 将只读属性打开
}

C# 程序

 

private static void EditPIPoint(PIPoint pt)
 {
     Server server = new Server;

     server.PIPoints[test2];

     PointAttribute attr = pt.PointAttributes["descriptor"];
    pt.PointAttributes.ReadOnly = false;
     attr.Value = "new description";
    pt.PointAttributes.ReadOnly = true;
 }

编辑一组点

 

C++程序

 

static void EditPoints (ServerPtr, spServer)
{
    _bstr_t condition = "tag='test*'"; // 给定编辑点的搜索条件
     _PointListPtr ptlist; // 创建一个点表指针
     ptlist = spServer->GetPoints(condition,NULL); // 将按条件搜索出的点存储到点表里
     _NamedValuesPtr nvTags; // 创建一个接收点表信息的指针
    nvTags.CreateInstance(__uuidof(NamedValues)); // 分配内存区域
     _NamedValuesPtr nvAttributes; // 创建一个接收点属性的指针
     nvAttributes.CreateInstance(__uuidof(NamedValues)); // 分配内存区域
     _variant_t descriptions = "test for points edit"; // 将需要更改的信息创建成 _variant_t类型
 
     nvAttributes->Add("descriptor", &descriptions); // 将修改的信息存储至之前创建的接收点属性的指针指向的区域
     _variant_t var_attributes; // 创建一个新的_variant_t类型参数
    VariantInit(&var_attributes); // 初始化_variant_t类型参数 
     V_VT(&var_attributes) = VT_DISPATCH; // 将_variant_t类型参数转变成VT_DISPATCH接口类型参数
     V_DISPATCH(&var_attributes) = nvAttributes; // 将VT_DISPATCH接口类型参数等同于之前存储属性的那片区域
 
     for (int i = 1; i <= ptlist->Count; i++) // 这个FOR循环是为将符合条件的所有的点的点名和属性加入到指向点表信息指针指向的内存区域
     {
         _variant_t vi = i;
         PIPointPtr spTag = ptlist->Item[&vi];
         nvTags->Add(spTag->Name, &var_attributes);
     }
 
     _PIErrorsPtr Errors; // 需要实例化一个PIErrors
     Errors.CreateInstance(__uuidof(PIErrors));
     _PIErrors **ErrorsPtr = &Errors; // 用一个二级指针指向这个实例
 
     IPIPoints2Ptr ipi_points2 = (IPIPoints2Ptr)spServer->PIPoints;  // 使用 IPIPoints2Ptr类型指针指向点表
     ipi_points2->EditTags(nvTags, &Errors, NULL); // 使用上述指针类里的编辑点的函数,将点表中所有的点的信息做更改
}

 

C#程序

 

private static void EditPIPoints(Server server, PointList ptlist)
 {
     NamedValues nvTags = new NamedValues();
     NamedValues nvAttributes = new NamedValues();
 
    nvAttributes.Add("descriptor", "edited description");

    foreach(PIPoint pt in ptlist)
     {
        nvTags.Add(pt.Name, nvAttributes);
     }
 
     PIErrors errs = new PIErrors();
 
     IPIPoints2 ipipoints2 = (IPIPoints2)server.PIPoints;
     ipipoints2.EditTags(nvTags, out errs);
 
     foreach (PIError err in errs)
     {
        Console.WriteLine(err.Description);
     }
 }

在C#程序中,没有写点表如何获得的,只是直接调用之前按条件搜索点表的程序,原理是一样的

 

以下内容为如何从PI服务器中取出点/点表的一些值。这些程序是基于点的操作,因此,将不再重复如何搜索点/点表。如果使用下述函数,请首先参看本帖第三部分---搜索点/点表

 

5. 取快照值

 

取单快照值

 

C++程序

 

static _PIValuePtr GetSnapshot(PIPointPtr pt)         // 传入点信息
 {
    return (_PIValuePtr)pt->Data->GetSnapshot();
 }

 

C#程序

 

private static PIValue GetSnapshot(PIPoint pt)
 {
    return pt.Data.Snapshot;
 }

取点表快照

 

C++程序

 

static PointValuesPtr GetSnapshot(_PointListPtr sppointlist) // 传入点表信息
 {
    PointValuesPtr ptValues = sppointlist->Data->GetSnapshot(NULL);
    return ptValues;
 }

 

C#程序

 

 

private static PointValues GetSnapshot(PointList ptlist)
 {
    NamedValues nvErrs = new NamedValues();
    PointValues ptvalues = ptlist.Data.get_Snapshot(out nvErrs);
 }

 

6. 取某时刻历史数据

单点某时数据

 

C++程序

 

static _PIValuePtr GetArchive(PIPointPtr pt)
 {
    _bstr_t time = "*-2h"; // 以下内容为将字符串时间转化为_variant_t 类型的时间
    _PITimeFormatPtr sptime;
    sptime.CreateInstance (__uuidof(PITimeFormat));
    sptime->InputString = time;
    _variant_t vtStart;
    VariantInit (&vtStart);
    V_VT (&vtStart) = VT_DISPATCH;
    V_DISPATCH(&vtStart) = sptime; 
    return (_PIValuePtr)pt->Data->ArcValue(vtStart, RetrievalTypeConstants::rtAuto, NULL);      // 将PI点指针类型的指针转换成PI Value类型的指针,并执行函数。
 }

C#程序

 

private static PIValue GetArchive(PIPoint pt)
 { 
    PITimeFormat time = new PITimeFormat();
    time.InputString = "*-2h";
    return pt.Data.ArcValue(time, RetrievalTypeConstants.rtAuto);
 }

Outcomes