最近良哥在开发某电厂数据分析平台时需要操作PI数据库(OSIsoft公司的实时数据库产品),从PI 官网(https://techsupport.osisoft.com/)介绍可知,常用的访问PI数据库的方案有:①使用PI JDBC Driver或 ODBC Driver;②使用PI WEB API;③使用PI SDK;
一、使用 PI JDBC Driver
PI的JDBC驱动程序是一个java数据库连接驱动,通过SQL查询提供了强大的数据访问PI系统 。PI JDBC Driver 提供了一个类似于java 访问Mysql或者Oracle 同样的方式。但是,JDBC Driver 是 通过中间层 PI SQL DATA Access Server 来实现 PI JDBC driver 和 PI OLEDB Enterprise/PI OLEDB providers 之间的交互的。因此需要同时安装jdbc驱动和PI SQL DAS。
二、使用 PI WEB API
PI Web API是一个RESTful API,允许你通过HTTP请求与PI System进行交互。Java应用程序可以使用HTTP客户端库(如Apache HttpClient或OkHttp)来调用PI Web API。此方案是最便捷的,但是据厂家技术人员反馈,该方式只支持3.x版本以上的PI数据库。由于良哥此次面临的PI数据库是2.x版本,因此该方案无效。
三、使用 PI SDK
前言
此方案由于需要调用OSIsoft提供的piapi32.dll动态库,因此只能在windows系统上实现,同时对于c语言实现的库函数,java在调用时也需要完成变量类型的适配工作。以下主要详述此方案的具体实现方法。
1)环境:
操作系统:windows(linux不适用)
jdk版本:jdk1.8-32位(一定要32位版本,否则无法调用动态库)
PI接口库函数:piapi32.dll
下载地址1:https://download.youkuaiyun.com/download/hualinger/90414712
下载地址2:https://download.youkuaiyun.com/download/hualinger/90414696
2)POM引用(SpringBoot环境):
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.5.0</version>
</dependency>
3)代码示例
import com.sun.jna.ptr.FloatByReference;
import com.sun.jna.ptr.IntByReference;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class PIAPITestUtils {
@Test
public void testPIDB() {
PIAPILibrary api = PIAPILibrary.INSTANCE;//Dll实例
// 连接服务
System.out.println(api.piut_setservernode("192.168.0.109"));
System.out.println(api.pitm_systime());
// 获取位号“CDM158”的实时数据
// 1.定义变量
IntByReference pt = new IntByReference();
IntByReference timedate = new IntByReference();
FloatByReference rval = new FloatByReference();
IntByReference istat = new IntByReference(0);
// 2.调用接口获取数据
System.out.println(api.pipt_findpoint("CDM158", pt));
System.out.println(api.pisn_getsnapshot(pt.getValue(), rval, istat, timedate));
// 3.输出结果
System.out.println(pt.getValue());
System.out.println(rval.getValue());
System.out.println(istat.getValue());
System.out.println(timedate.getValue());
}
}
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.FloatByReference;
import com.sun.jna.ptr.IntByReference;
public interface PIAPILibrary extends Library {
PIAPILibrary INSTANCE = (PIAPILibrary) Native.loadLibrary("piapi32", PIAPILibrary.class);
// piapi32中的接口 见piapi.h
int piut_setservernode(String servername);
int pitm_systime();
// 查找tagname指定的位号并存入pt中
// PIINT32 pipt_findpoint( char PIPTR *tagname, int32 PIPTR *pt );
int pipt_findpoint(String tagname, IntByReference pt);
// 获取PI时间
// 这个函数解析传入的时间字符串并返回pi本地时间。如果传递的字符串是相对时间,则使用reltime作为计算绝对时间的起点。
// 如果时间字符串有效则返回0,如果无效则返回-1。有效的时间字符串是一种绝对格式,包含dd-mm -yy hh:mm:ss、+|- n和|h|m|s格式的相对时间、
// 用单词指定的绝对时间(今天、昨天、星期天、星期一、…)、用星号表示当前时间,或者使用单词绝对时间和相对时间之一的组合时间。
// PIINT32 pitm_parsetime( char PIPTR *str, int32 reltime, int32 PIPTR *timedate);
int pitm_parsetime(String timestr, int reltime, IntByReference timedate);
// 获取timedate时间位号pt的值并存入rval、istat中
// 这个函数检索发送到pi系统的特定点的最新值。返回快照的工程单位值、状态码、时间和日期。
// 如果点类型不是实数,则以istat形式返回值,而rval参数返回为0。
// PIINT32 pisn_getsnapshot( int32 pt, float PIPTR *rval, int32 PIPTR *istat, int32 *timedate );
int pisn_getsnapshot(int pt, FloatByReference rval, IntByReference istat, IntByReference timedate);
// 写入位号pt在时间timedate的值
// PIINT32 pisn_putsnapshot( int32 pt, float rval, int32 istat, int32 timedate );
int pisn_putsnapshot(int pt, float rval, int istat, int timedate);
// 写入位号pt的值rval、istat、timedate、wait
// PIINT32 piar_putvalue( int32 pt, float rval, int32 istat, int32 timedate, int32 wait );
int piar_putvalue(int pt, float rval, int istat, int timedate, int wait);
//这个函数检索服务器上定义的所有单位。第一次调用该函数时,应该将Index设置为0,随后的调用应该将Index增加到number-1,以检索剩余的单元名称。
// int32 piba_getunit( char PIPTR * unit, int32 len, int32 index, int32 PIPTR * number );
int piba_getunit(String unit, int len, int index, IntByReference number);
}
4)运行结果:
5)其他
1):基本类型 直接找java中与之对应的类型转换即可
2):指针类型 转换如下
c语言函数:PIINT32 pisn_getsnapshot( int32 pt, float PIPTR *rval, int32 PIPTR *istat, int32 *timedate );
java映射:int pisn_getsnapshot(int pt, FloatByReference rval, IntByReference istat, IntByReference timedate);
3)jna对结构体、指针、引用、拷贝参数传递的使用参考:https://blog.youkuaiyun.com/xie_heng/article/details/49814207
详见帮助文档:
下载地址1:https://download.youkuaiyun.com/download/hualinger/90414712
下载地址2:https://download.youkuaiyun.com/download/hualinger/90414696