# AVEVA PI

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

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，读的是它的快照（当前）值。

## 连接字段 {#connection-fields}

| 字段 | 它是什么 | 格式 | 默认值 |
|---|---|---|---|
| 主机 | 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 信任它，或你在本驱动页面的[现场设备访问](#equipment-access)里批准了这份证书本身时被接受。轮询间隔可以配置：设备的默认值（1000 毫秒）适用于每一个没有自己另作规定的点位。

## 准备 PI Web API {#prepare-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 却拒绝设备发送的账户时，页面会说明用户名或密码被拒绝，并指向“连接”卡片。服务一旦应答，这两种提示都会自行消失。日志和代理读到的是同样的步骤。服务拒绝承载令牌时，用驱动自己的话说明。

## 点位寻址 {#tag-addressing}

点位的 **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 时很好用。

## 写入 {#writes}

读写方式可写的点位通过 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](connector) 页面。

## 支持的数据类型 {#supported-data-types}

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

## 命令 {#commands}

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

## 设备发现 {#discovery}

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

PI 设备的页面上没有**发现点位**：遍历从一个 AF 元素开始，而设备并不保存这个元素，所以设备的点来自这次扫描，或者手工添加（见[发现一台设备的点位](connector-discovery#discovering-a-devices-tags)）。

## 现场设备访问 {#equipment-access}

端口上没有分配证书的 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 份等待批准的证书；列表满了以后，新的证书仍会被拒绝但不会列出，卡片会说明这一点。
