# AVEVA PI

> Reference for the AVEVA PI driver: PI Web API over HTTPS, bearer or Basic authentication, AF and PI point addressing, reads and writes.

The AVEVA PI driver reads and writes an **AVEVA PI System** through **PI Web API**,
the system's REST interface (JSON over HTTP). It is a client-mode driver (**Ganter
Lab connects to the PI Web API service**), and the transport is **HTTPS by
default**: the driver puts the device's credentials on every request it makes, so
an unencrypted connection would publish them. Plain HTTP exists only as an explicit
per-device choice.

A tag addresses one **AF attribute**, one **PI point**, or a raw PI Web API stream,
and reads its snapshot (current) value.

## Connection fields {#connection-fields}

| Field | What it is | Format | Default |
|---|---|---|---|
| Host | The PI Web API server's host name or IP address. An address can be pasted whole (`https://pi-host/piwebapi`): `https://` or `http://` in front sets the transport below to match and is dropped, a port goes to the port field and the path to the resource path. | Host name or IP | empty |
| Port | The TCP port of the service. A new device leaves it empty, and an empty box means the port the chosen transport answers on, 443 over HTTPS and 80 in the clear: the box shows that port in grey and follows the transport tick, which is also how a device saved with 0 reads. | 1 to 65535, or empty | empty |
| Resource path | The service root path appended to the authority. Blank, or a bare `/`, means PI Web API's standard root, `piwebapi`. Any other path is the path the driver opens, exactly as typed: a service published behind a reverse proxy on `/pi` is reached at `/pi`, and nothing is appended to it. Write the whole path a browser would need, `piwebapi` included where the service still answers there. | path text | blank (= `piwebapi`) |
| Send over plain HTTP | Steps this one device down from HTTPS to clear HTTP. Off means HTTPS, the normal PI Web API transport. The panel states the consequence: on plain HTTP the bearer token or password is sent unencrypted on every request. Use it only for a PI Web API that answers on no other transport. | on / off | off |
| Username | Account for **HTTP Basic** authentication, used only when no bearer token is set. Empty (with no token) leaves the requests anonymous. | Free text | empty |
| Password | The password paired with the username. Protected at rest per Windows user; a secret entered under another Windows account shows as unreadable and must be re-entered. | Free text | empty |
| Bearer token | A token sent as `Authorization: Bearer …` on every request. When set it **wins over** the username/password pair. Protected at rest the same way. | Token text | empty |

On connect the driver verifies the service root (HEAD, falling back to GET). Over
HTTPS, the service's TLS certificate is accepted when Windows trusts it, or when you
approved that very certificate under [Equipment access](#equipment-access) on this
driver's page. The poll interval is configurable: the device default (1000 ms) applies
to every tag that does not state its own.

## Prepare PI Web API {#prepare-pi-web-api}

The driver signs in with a user name and password over HTTP Basic, or with a bearer token. PI
Web API comes with Kerberos as its only authentication method, and the driver does not speak
Kerberos, so a newly installed service usually refuses the station until one of these is done
on the PI Web API server:

| Way in | Where it is set | Then |
| --- | --- | --- |
| Basic authentication | PI Web API Admin Utility, page Authentication Options: tick Basic and apply. Or PI System Explorer, Configuration database, the System Configuration element under OSIsoft > PI Web API > the instance's name: add Basic to the AuthenticationMethods attribute and check the change in. Restart the PI Web API service. | Username and Password on the device's Connection card hold a Windows account the PI System accepts; a domain account is written DOMAIN\user |
| Bearer token | PI Web API set up with AVEVA Identity Manager (Bearer authentication) | The token goes in the device's Bearer token box |

When the service answers 401 without offering Basic, the device's page says so, with these
steps, in place of the driver's English error; when it offers Basic and refuses the account
the device sent, the page says the user name or the password was refused and points to the
Connection card. Either notice goes away by itself once the service answers. The journal and
the agent read the same steps. A bearer token the service refuses is said in the driver's own
words.

## Tag addressing {#tag-addressing}

The tag's **PI path** field accepts four forms:

| Form | Looks like | How it is resolved |
|---|---|---|
| AF attribute path | `\\AFServer\Database\Element\SubElement\|Attribute` | Looked up once through `attributes?path=…` to obtain the attribute's WebId |
| PI point path | `\\PIServer\TagName` | Looked up once through `points?path=…` to obtain the point's WebId |
| WebId | The opaque WebId string itself | Used directly (recognized as a long token with no `\`, `\|` or `/`) |
| Relative URL | `streams/{webId}/value`, `streamsets/…`, `attributes?…`, `points?…` | Sent as-is under the service root |

Path lookups are cached for 12 hours, so steady-state polling does not repeat
them. For the first three forms the read GETs the stream's **snapshot value**
(`streams/{webId}/value`) and extracts the JSON `Value` field; a relative URL is
read literally, so point it at an endpoint that answers with a value document. The
result is converted to the tag's declared data type.

The archive's own verdict on the sample is read with it. A value the archive marks
as **not good**, as **questionable**, or as **substituted** (a number entered by
hand rather than measured) is not a reading of the equipment, so it is not
published as one: the tag goes to bad quality and the reason says which of the
three it was. The same happens when the response carries no value, or answers with
a digital state rather than a single value, in which case the state's name is part
of the reason. Nothing is invented in their place, and no document arrives as if it
were the measurement.

A read PI Web API refuses (a status outside the success range, such as an account
without read access to the point) reads as bad quality too, and the reason names the
status and what the service said with it (`HTTP 403 Forbidden: …`). A path the service
does not know says so, naming the path. An empty address, an address in none of the four
forms, and an answer that does not read as the declared type give the reason as well. A
service that does not answer at all is the device's connection failing: the device reports it
and reconnects, and its tags point to it.

Examples:

- `\\PI-SRV01\FURNACE.TEMP`: a classic PI point.
- `\\AF-SRV\Plant\Line 3\Furnace|Temperature`: an AF attribute.
- `streams/F1DPmNQx2kqBk0qbIVMoxAVBJw/value`: a raw stream URL, useful when you
  already hold the WebId from another tool.

## Writes {#writes}

Tags with a writable access mode write through PI Web API's stream endpoint: a
POST of `{"Timestamp":"*","Value":…}` (timestamp `*` means now) to
`streams/{webId}/value`. The write needs a resolvable WebId, so it works for tags
addressed by AF path, PI point path, WebId, and by a relative `streams/…` URL as
well: the WebId is read out of that URL and the write lands on that stream's value
endpoint, whatever read-side sub-resource (`recorded`, say) the address carried past
it. Three relative forms are refused, because each answers with a document rather
than with one stream's value and a write would address the wrong resource:
`streamsets/…`, `attributes?…` and `points?…`. The refusal names the accepted forms.
Whether the write lands also depends on the PI Web API being configured for writes
and the account having write access to the point. A write PI Web API refuses is answered with the status and what the service said with it (for instance `HTTP 403 Forbidden: …`), so whoever wrote the value reads why.

The value you type in the tag's write box is the engineering value; the tag's
conversion stages are reversed before the raw value goes on the wire, as described
on the [Connector](connector) page.

## Supported data types {#supported-data-types}

Boolean, Int32, Int64, Float, Double and String. Numeric PI points are typically
Float or Double. A digital state is not a single value, so a point that answers with
one reads as bad quality naming the state, whatever type the tag declares.

## Commands {#commands}

Beyond reading and writing points, a PI Web API endpoint can be asked to do something, and
which requests it accepts is the service's own business. Declare each one on the device, in
the **Commands** card of its page: a name, the relative URL it is POSTed to under the
service root, and optionally the name of the one value it takes, which travels as the
request body. The row's Run verb sends it and reports what the service answered; the command
also becomes a method on the device in this station's own OPC UA address space. A request the
service refuses is answered with the status and what the service said with it, in the same
words as a refused write.

## Discovery {#discovery}

The **Discover** button reads one service. Put its address and the AF element the walk
starts from in the driver page's Scan scope card, separated by a `#`:
`https://pi-host/piwebapi#\\AF-SRV\Plant\Line 3`. The scan resolves that element, walks
every element under it, and offers the device with one point per attribute, each addressed
by its own stream. The scan reads the service without credentials, because it runs before
the device that would hold them exists, so a PI Web API that authenticates every request
answers nothing and the device is added by hand instead: add the service by host and add
tags by their AF or PI paths, as the add-a-device flow on the [Connector](connector) page
describes.

A PI device's page shows no **Discover tags**: the walk starts from an AF element, which the device does not hold, so a device's points come from this scan or are added by hand (see [Discovering a device's tags](connector-discovery#discovering-a-devices-tags)).

## Equipment access {#equipment-access}

A PI Web API whose port has no certificate assigned creates and uses a self-signed
certificate of its own, which no root installed in Windows vouches for. That root does not
need to be installed on this computer. The first connection is refused, the device reads
**Waiting for certificate approval** in the tree and on its page, whose **Review
certificate** button opens this card on the certificate, and the certificate waits under
**Equipment access** at the end of the AVEVA PI driver's page, the same card the OPC UA
driver's page carries, until you decide:

| Group | What it lists | What you can do |
|---|---|---|
| Waiting for approval | Each refused certificate, under the name it claims: its SHA-256 fingerprint, the address it was met at, when it last tried and how many times, and its details (subject, issuer, domain names, validity dates). The one a device's Review certificate opened is marked Selected for review. | **Approve** accepts the certificate from the device's next connection attempt. **Block** keeps refusing it without listing it here again. **Discard all pending certificates** empties the list without approving or blocking anything. |
| Approved equipment | The certificates you approved or imported, with who decided and when, and the address each was last met at. | **Withdraw approval** closes the device's connection and returns its certificate to the list. **Import certificate** approves a public certificate file you already have (.der, .cer, .crt or .pem) before the first connection. |
| Blocked equipment | The certificates you blocked. A blocked certificate is refused even if Windows trusts it. | **Unblock** returns the certificate to the list, without approving it. |

Check the fingerprint with whoever manages the PI server before you approve it. An approval
accepts that certificate and no other, and only within its validity dates; it stands in for
the root Windows lacks and for the name the certificate carries, so a PI Web API dialed by its
IP address connects although its certificate names the server, and nothing else about the
certificate is relaxed. When the service answers an address whose certificate you approved
with another one (a renewed certificate, another certificate bound to the port), reading
stops, the new one waits here, and the station raises "Certificate changed: `<name>`" with a
**Review** button. A certificate Windows already trusts is accepted as before and never
appears here; nothing is approved automatically.

The driver's own failure says the reason instead of a nameless TLS error: "This equipment's
certificate (the first 16 characters of the fingerprint) is waiting for your approval under
Equipment access on the AVEVA PI driver's page. Reading starts once you approve it." A
blocked one reads "…is blocked at this station. Review it under Equipment access on the AVEVA
PI driver's page." A certificate outside its validity dates, revoked or with a broken
signature is refused with that reason and is never listed, since no approval makes it sound.
A scan of the service from the Scan scope card meets the same decisions: an unknown
certificate ends the scan with that sentence and waits here.

The decisions are kept in the station's data folder, under `ua\pki\aveva-pi`, and survive a
restart. Only a role that may configure the Connector is drawn the verbs, and they act only
in the station's own window: a browser on another device reads the card without changing it,
and no agent tool approves a certificate (`connector_browse` reports the waiting device with
`awaitingCertificate`). The list holds up to 100 certificates waiting for approval; once it
is full, a new one is still refused but not listed, and the card says so.
