AVEVA PI

AVEVA PI 驱动参考:走 HTTPS 的 PI Web API、承载令牌或 Basic 认证、AF 与 PI point 寻址、读取和写入。

以 Markdown 查看

AVEVA PI 驱动通过 PI Web API 读写一套 AVEVA PI System,也就是这个系统的 REST 接口(HTTP 上的 JSON)。它是一个客户端模式的驱动,由 Ganter Lab 连到 PI Web API 服务上,而传输默认是 HTTPS:驱动会把设备的凭据放在它发出的每一个请求上,所以不加密的连接等于把它们公之于众。普通 HTTP 只作为一个按设备明确做出的选择存在。

一个点位寻址的是一个 AF 属性、一个 PI point,或者一条原始的 PI Web API stream,读的是它的快照(当前)值。

连接字段

字段 它是什么 格式 默认值
主机 PI Web API 服务器的主机名或 IP 地址。可以粘贴完整地址(https://pi-host/piwebapi):前面的 https:// 或 http:// 会把下方的传输方式设成对应的一种,然后被去掉,端口进入端口字段,路径进入资源路径。 主机名或 IP 空
端口 服务的 TCP 端口。新设备让它留空,空框表示所选传输应答的那个端口:走 HTTPS 是 443,明文是 80。框里以灰色显示这个端口,并随传输的选择而变;以 0 保存的设备也是这样显示的。 1 到 65535,或留空 留空
资源路径 接在授权部分后面的那个服务根路径。留空,或者只写一个 /,表示 PI Web API 的标准根 piwebapi。其他任何路径都是驱动实际打开的那条路径,和你打的一模一样:一个发布在反向代理 /pi 后面的服务就在 /pi 上够到,后面什么都不再拼。请把浏览器需要的那条完整路径写出来,服务仍在那里应答时,piwebapi 也写上。 路径文本 留空(= piwebapi)
用普通 HTTP 发送 只把这一台设备从 HTTPS 降到明文 HTTP。不勾表示 HTTPS,也就是 PI Web API 正常的传输方式。面板会把后果说清楚:走明文 HTTP 时,承载令牌或密码在每一次请求里都以明文发送。只有在一个 PI Web API 不用别的传输应答时才用它。 开 / 关 关
用户名 用于 HTTP Basic 认证的账户,只在没有设承载令牌时才用。留空(并且没有令牌)会让请求以匿名身份发出。 自由文本 空
密码 和用户名配对的密码。在静态存储时按 Windows 用户保护;在别的 Windows 账户下输入的秘密会显示为读不出来,必须重新输入一次。 自由文本 空
承载令牌 在每一个请求上以 Authorization: Bearer … 发出的一个令牌。设了它就压过用户名/密码那一对。在静态存储时以同样方式保护。 令牌文本 空

连上时,驱动核实服务根(先 HEAD,退回 GET)。走 HTTPS 时,服务的 TLS 证书在 Windows 信任它,或你在本驱动页面的现场设备访问里批准了这份证书本身时被接受。轮询间隔可以配置:设备的默认值(1000 毫秒)适用于每一个没有自己另作规定的点位。

准备 PI Web API

驱动通过 HTTP Basic 用用户名和密码登录,或者用承载令牌登录。PI Web API 出厂时只启用 Kerberos 这一种身份验证方法,而驱动不使用 Kerberos,所以刚安装好的服务通常会拒绝工作站,直到在 PI Web API 服务器上完成下面其中一项:

方式 设置位置 然后
Basic 身份验证 PI Web API Admin Utility 的 Authentication Options 页面:勾选 Basic 并应用。或者在 PI System Explorer 的 Configuration 数据库中,选中 OSIsoft > PI Web API > 实例名称 下的 System Configuration 元素:把 Basic 加入 AuthenticationMethods 属性并签入更改。重启 PI Web API 服务。 设备“连接”卡片上的用户名和密码填 PI System 接受的 Windows 账户;域账户写成 DOMAIN\user
承载令牌 配合 AVEVA Identity Manager 设置的 PI Web API(Bearer 身份验证) 令牌填入设备的 Bearer 令牌框

服务返回 401 且不提供 Basic 时,设备页面会用这些步骤说明这一点,代替驱动的英文错误;服务提供 Basic 却拒绝设备发送的账户时,页面会说明用户名或密码被拒绝,并指向“连接”卡片。服务一旦应答,这两种提示都会自行消失。日志和代理读到的是同样的步骤。服务拒绝承载令牌时,用驱动自己的话说明。

点位寻址

点位的 PI 路径字段接受四种形式:

形式 长什么样 怎么解析
AF 属性路径 \\AFServer\Database\Element\SubElement\|Attribute 通过 attributes?path=… 查一次,拿到这个属性的 WebId
PI point 路径 \\PIServer\TagName 通过 points?path=… 查一次,拿到这个 point 的 WebId
WebId 那串不透明的 WebId 本身 直接使用(认出来的方式是一段不含 \、\| 或 / 的长记号)
相对 URL streams/{webId}/value、streamsets/…、attributes?…、points?… 原样发到服务根下面

路径查询会缓存 12 小时,所以稳定运行时的轮询不会一遍遍重查。对前三种形式,读取 GET 的是这条 stream 的快照值(streams/{webId}/value),并取出 JSON 里的 Value 字段;相对 URL 则按字面读,所以请把它指向一个用一份值文档来应答的 endpoint。结果会被转换成点位声明的数据类型。

归档自己对这次采样的判断会随它一起读回来。归档标为不良、标为可疑、或者标为被替换过(一个手工输入而不是测出来的数)的值,都不是对仪器的一次读数,所以也不会被当作读数发布出去:点位转为质量不可用,原因会说是三者中的哪一种。响应里没有值,或者答的是一个数字状态而不是一个单一值时,也是同样处理,这时那个状态的名字会成为原因的一部分。它们的位置上不会被编出什么东西来,也不会有哪份文档冒充成那次测量。

PI Web API 拒绝的读取(一个在成功范围之外的状态,比如账户对这个 point 没有读权限)同样转为质量不可用,原因会点名那个状态,以及服务随它说的话(HTTP 403 Forbidden: …)。服务不认识的路径会这样说出来,并点名那条路径。空地址、不属于四种形式中任何一种的地址,以及读不成声明类型的响应,同样会给出原因。一个完全不答的服务是设备的连接失败:设备会报告它并重新连接,它的点位会指向这台设备。

例子:

  • \\PI-SRV01\FURNACE.TEMP:一个经典的 PI point。
  • \\AF-SRV\Plant\Line 3\Furnace|Temperature:一个 AF 属性。
  • streams/F1DPmNQx2kqBk0qbIVMoxAVBJw/value:一条原始的 stream URL,在你已经从别的工具那里拿到 WebId 时很好用。

写入

读写方式可写的点位通过 PI Web API 的 stream endpoint 来写:向 streams/{webId}/value POST 一个 {"Timestamp":"*","Value":…}(时间戳 * 表示现在)。写入需要一个解析得出来的 WebId,所以它对按 AF 路径、按 PI point 路径、按 WebId 寻址的点位都行得通,对按相对 streams/… URL 寻址的也行:WebId 会从那条 URL 里读出来,写入落在那条 stream 的 value endpoint 上,不管地址后面还带着哪个读取侧的子资源(比如 recorded)。有三种相对形式被拒绝,因为它们各自答的是一份文档而不是某一条 stream 的值,写入会寻错资源:streamsets/…、attributes?… 和 points?…。这次拒绝会点名可接受的那几种形式。写入能不能落地,还取决于 PI Web API 有没有配置成允许写入,以及那个账户对这个 point 有没有写权限。PI Web API 拒绝的写入会得到一个答复,里面有状态,以及服务随它说的话(例如 HTTP 403 Forbidden: …),写入这个值的一方读得到原因。

你在点位写入框里打的是工程值;原始值上总线之前会先把这个点位的转换环节反过来走一遍,见 Connector 页面。

支持的数据类型

Boolean、Int32、Int64、Float、Double 和 String。数值型的 PI point 通常是 Float 或 Double。数字状态不是一个单一值,所以一个用它来应答的 point,不管点位声明的是什么类型,都读作质量不可用并点名那个状态。

命令

除了读写点之外,一个 PI Web API endpoint 还可以被要求去做一件事,而它接受哪些请求是这个服务自己的事。每一条命令都在设备上声明,位置是它页面上的命令卡片:一个名称、POST 到服务根下面的那条相对 URL,以及可选的、它所接收的那一个值的名字,那个值作为请求体发出去。行上的“运行”把它发出去并报告服务答了什么;这条命令同时也成为这台设备在本工作站自己的 OPC UA 地址空间里的一个方法。服务拒绝的请求会得到一个答复,里面有状态,以及服务随它说的话,用的是和被拒绝的写入一样的说法。

设备发现

发现设备按钮读的是一个服务。把它的地址和这次遍历的起点 AF 元素填进驱动页面的“扫描范围”卡片,中间用一个 # 隔开:https://pi-host/piwebapi#\\AF-SRV\Plant\Line 3。扫描会解析那个元素,走一遍它下面每一个元素,并把设备提供出来,每个属性给一个点,各自按自己的 stream 寻址。扫描是不带凭据去读服务的,因为它跑的时候那台该拿着凭据的设备还不存在,所以一个对每次请求都要求认证的 PI Web API 什么都不会回答,那就改为手工添加设备:按主机添加这个服务,再按 AF 或 PI 路径添加点位,具体流程见 Connector 页面上添加设备的那一节。

PI 设备的页面上没有发现点位:遍历从一个 AF 元素开始,而设备并不保存这个元素,所以设备的点来自这次扫描,或者手工添加(见发现一台设备的点位)。

现场设备访问

端口上没有分配证书的 PI Web API 会自己生成并使用一份自签名证书,Windows 中已安装的任何根证书都不为它担保。无需在这台计算机上安装那个根证书。第一次连接会被拒绝,设备在树里和它的页面上显示正在等待证书批准,页面上的查看证书按钮会在那份证书上打开这张卡片;证书则在 AVEVA PI 驱动页面末尾的现场设备访问里等你决定。这张卡片和 OPC UA 驱动页面上的是同一张。

分组 列出什么 你能做什么
等待批准 每一份被拒绝的证书,按它自称的名字列出:它的 SHA-256 指纹、遇到它的地址、最后一次尝试的时间和次数,以及详情(主体、颁发者、域名、有效期)。设备的查看证书打开的那一份会标为“已选中待审核”。 批准从下一次连接尝试起接受这份证书。阻止继续拒绝它,且不再在这里列出。丢弃所有待处理的证书清空列表,什么也不批准、不阻止。
已批准的现场设备 你批准或导入的证书,连同谁在何时做的决定,以及每份证书最后一次被遇到的地址。 撤回批准关闭连接,并把证书放回列表。导入证书在第一次连接之前批准一份你手头已有的公开证书文件(.der、.cer、.crt 或 .pem)。
被阻止的现场设备 你阻止的证书。被阻止的证书即使受 Windows 信任也会被拒绝。 解除阻止把证书放回列表,但不批准它。

批准之前,请与管理该 PI 服务器的人核对指纹。批准只接受这一份证书,而且只在它的有效期内;它代替 Windows 缺少的根证书和证书上写的名字,所以按 IP 地址连接的 PI Web API,即使证书上写的是别的名字也能连上,而证书的其他方面一概不放宽。如果现场设备在你批准过证书的地址上换出另一份证书(证书续期、给端口绑定另一份证书等),读取就会停止,新证书在这里等待,工作站会带着审核按钮提示“证书已更换:<名称>”。Windows 已经信任的证书照旧被接受,永远不会出现在这里;没有任何东西会被自动批准。

驱动自己的失败会说明原因,而不是一个没有名字的 TLS 错误:“这台现场设备的证书(指纹的前 16 个字符)正在 AVEVA PI 驱动页面的‘现场设备访问’里等待你的批准。批准之后就开始读取。”被阻止的则显示“……在本工作站已被阻止。请在 AVEVA PI 驱动页面的‘现场设备访问’里审核它。”超出有效期、已吊销或签名损坏的证书会以这个原因被拒绝,且永远不会被列出,因为批准也不能让它变得可靠。从“扫描范围”卡片扫描这个服务时也遵循同样的决定:陌生的证书会以这句话结束扫描,并在这里等待。

这些决定保存在工作站数据文件夹的 ua\pki\aveva-pi 下,重启后依然有效。操作按钮只对能配置 Connector 的角色显示,而且只在工作站自己的窗口里生效:其他设备上的浏览器只能查看卡片、不能修改,也没有任何代理工具能批准证书(connector_browse 用 awaitingCertificate 标出正在等待的设备)。列表最多保留 100 份等待批准的证书;列表满了以后,新的证书仍会被拒绝但不会列出,卡片会说明这一点。