PI Web API Nodes
Read from and write to an OSIsoft / AVEVA PI System directly from pipelines over PI Web API. Each read/write function authored on a PI Web API connection is available as a matching node in the Pipeline Designer.
For connection setup, authentication, the stream-path model, the AF Browser, PI time expressions, and per-function configuration fields, see the PI Web API connection guide.
For the event-driven trigger (Stream Updates), see the PI Web API Trigger node.
Configuration Quick Reference
| Field | What you choose | Details |
|---|---|---|
| Parameters | Connection, Function, Function Parameters, Timeout Override | Select the PI Web API connection profile, pick a function, bind parameters with expression support, and optionally override the timeout. |
| Settings | Description, Timeout (seconds), Retry on Timeout, Retry on Fail, On Error | Node description, maximum execution time, retry behaviour on timeout or failure, and error strategy. All execution settings default to pipeline-level values. |
PI Read Nodes
Read PI streams by path. There are five read node types, one per read function:
Supported Function Types:
| Node | Function | Purpose | Common Use Cases |
|---|---|---|---|
| PI Get Current Value | piwebapi.get_current | Read the single most recent value of a stream | Latest reading on a dashboard, setpoint readback |
| PI Get Recorded Values | piwebapi.get_recorded | Read raw archive events over a time range | Quality investigation, raw backfill |
| PI Get Interpolated Values | piwebapi.get_interpolated | Read interpolated values on a fixed grid | Fixed-cadence charts, regular-rate sinks |
| PI Get Summary Values | piwebapi.get_summary | Read aggregates (avg/min/max/total/…) over a range | Shift/daily reporting |
| PI Get Streamset (Bulk) | piwebapi.get_streamset | Read many streams in one call (snapshot or historical) | Dashboards, per-element fan-out |
Node Configuration
| Parameter | Type | Required | Description |
|---|---|---|---|
| Connection | Selection | Yes | PI Web API connection profile to use |
| Function | Selection | Yes | A read function of the matching type from the selected connection |
| Function Parameters | Dynamic | Varies | Auto-populated from the function schema (e.g. path/time for Get Current; path/startTime/endTime/… for the historical reads; paths/mode/… for Streamset). See the PI connection functions for field-level details. |
| Timeout Override | Number (seconds) | No | Override the default function timeout |
All function parameters support expression syntax ({{ expression }}) for dynamic values from the pipeline context, and ((paramName)) template placeholders where the function defines them.
Input
The node receives the output of the previous node as input. Input data can be referenced in function parameter expressions using $input.
Output Structure
Connected nodes wrap the function result in the canonical {result, _metadata} envelope. Access the payload via $node["Name"].result; the execution facts (success, functionId, durationMs, timestamp) live under $node["Name"]._metadata.
Get Current Value — a single decoded value:
{
"result": {
"timestamp": "2026-05-21T08:00:00Z",
"value": 72.5,
"unitsAbbreviation": "°C",
"good": true,
"questionable": false,
"substituted": false,
"annotated": false,
"quality": "good"
},
"_metadata": { "success": true, "functionId": "<function-id>", "durationMs": 18, "timestamp": "2026-05-21T08:00:00Z" }
}
| Field | Type | Description |
|---|---|---|
result.value | any | The decoded value — numeric, string, or digital-state depending on the tag's PointType |
result.timestamp | string | PI source timestamp for the value (UTC) |
result.good | boolean | PI's good flag |
result.questionable | boolean | PI's questionable flag |
result.substituted | boolean | PI's substituted flag |
result.annotated | boolean | PI's annotated flag |
result.quality | string | good, uncertain or bad, derived from the flags — every value envelope on this page carries it |
result.unitsAbbreviation | string | Engineering units abbreviation (may be empty) |
Get Recorded / Get Interpolated — result.items, an array of value envelopes, plus result.count:
{
"result": {
"items": [
{ "timestamp": "2026-05-21T08:00:03Z", "value": 72.4, "unitsAbbreviation": "°C", "good": true, "questionable": false, "substituted": false, "annotated": false },
{ "timestamp": "2026-05-21T08:00:11Z", "value": 72.6, "unitsAbbreviation": "°C", "good": true, "questionable": false, "substituted": false, "annotated": false }
],
"count": 2
},
"_metadata": { "success": true, "functionId": "<function-id>", "durationMs": 42, "timestamp": "2026-05-21T08:00:00Z" }
}
Get Summary — one item per bucket; each carries the aggregation type and only the good quality flag:
{
"result": {
"items": [
{ "type": "Average", "timestamp": "2026-05-21T08:00:00Z", "value": 72.48, "unitsAbbreviation": "°C", "good": true }
],
"count": 1
},
"_metadata": { "success": true, "functionId": "<function-id>", "durationMs": 55, "timestamp": "2026-05-21T08:00:00Z" }
}
Get Streamset — a flat result.items array in requested-path order, plus a by-path result.streams map and a result.failures map; the mode read is a fact about the call, at _metadata.mode:
The call's own facts ride along under _metadata next to the four every connected node carries. Every node delivers _metadata.method (the operation that ran), _metadata.connectionId (the connection it ran over) and _metadata.protocol (piwebapi). A single-stream read or write adds _metadata.path (the stream path as requested) and _metadata.webId (the WebID it resolved to). Get Streamset adds _metadata.mode (current or recorded), _metadata.requested, _metadata.resolved and _metadata.returned — how many paths you asked for, how many resolved to a stream, and how many PI answered with, which is how a partly-resolved streamset is diagnosed.
{
"result": {
"items": [
{ "path": "\\\\PISERVER\\Production\\Boiler1|Temperature", "webId": "F1AbEx...", "name": "Temperature", "value": 72.5, "timestamp": "2026-05-21T08:00:00Z", "good": true, "questionable": false, "substituted": false, "annotated": false, "unitsAbbreviation": "°C" },
{ "path": "\\\\PISERVER\\Production\\Boiler1|Pressure", "webId": "F1AbCd...", "name": "Pressure", "value": 4.1, "timestamp": "2026-05-21T08:00:00Z", "good": true, "questionable": false, "substituted": false, "annotated": false, "unitsAbbreviation": "bar" }
],
"streams": { "\\\\PISERVER\\Production\\Boiler1|Temperature": { "webId": "F1AbEx...", "path": "\\\\PISERVER\\Production\\Boiler1|Temperature", "name": "Temperature", "items": [ { "timestamp": "2026-05-21T08:00:00Z", "value": 72.5, "unitsAbbreviation": "°C", "good": true, "questionable": false, "substituted": false, "annotated": false } ], "count": 1 } },
"failures": {},
"mode": "current"
},
"_metadata": { "success": true, "functionId": "<function-id>", "durationMs": 63, "timestamp": "2026-05-21T08:00:00Z" }
}
Access pattern in downstream nodes:
{{ $node["PI Get Current Value"].result.value }}
{{ $node["PI Get Recorded Values"].result.items[0].value }}
{{ $node["PI Get Summary Values"].result.items[0].value }}
{{ $node["PI Get Streamset (Bulk)"].result.items[0].value }}
A path that fails to resolve does not fail the whole Streamset read. The failing path appears in result.items as an entry carrying an error field, and again in result.failures (path → message); every other stream returns normally. Check result.failures if you need to detect partial results.
PI Write Node
Write a value to a PI Point or AF attribute.
Supported Function Type:
| Node | Function | Purpose | Common Use Cases |
|---|---|---|---|
| PI Write Value | piwebapi.write_value | Write one value with optional timestamp and units | Setpoint writeback, downstream-computed annotations |
Node Configuration
| Parameter | Type | Required | Description |
|---|---|---|---|
| Connection | Selection | Yes | PI Web API connection profile to use |
| Function | Selection | Yes | A piwebapi.write_value function from the selected connection |
| Function Parameters | Dynamic | Varies | Auto-populated from the function schema (path, value, timestamp, units). The value, timestamp, and units parameters support ((paramName)) templates and {{ expression }} — see the PI connection functions. |
| Timeout Override | Number (seconds) | No | Override the default function timeout |
Use expressions like {{ $node["PI Get Current Value"].result.value }} to feed a dynamic value into the value parameter.
Input
The node receives the output of the previous node as input.
Output Structure
{
"result": {
"path": "\\\\PISERVER\\Production\\Boiler1|Setpoint",
"webId": "F1AbSp...",
"value": 42.5,
"timestamp": ""
},
"_metadata": { "success": true, "functionId": "<function-id>", "durationMs": 27, "timestamp": "2026-05-21T08:00:00Z" }
}
| Field | Type | Description |
|---|---|---|
result.path | string | The stream path that was written |
result.webId | string | The resolved WebID of the target stream |
result.value | any | Echo of the value written (after type coercion — "42.5" becomes 42.5) |
result.timestamp | string | Echo of the timestamp supplied; empty means PI stamped the write with its current server time |
A type mismatch, a bad unit, or a missing stream returns success: false with PI's own error message, and nothing is written.
Always validate values in a Condition node before writing to PI. A setpoint written back to a PI Point can drive downstream control and reporting. Numeric and boolean strings are coerced to real JSON types before sending, so "42" is written as the number 42 — confirm the target tag's PointType accepts the value.
Settings Tab
All PI Web API node types share the same Settings tab:
| Setting | Type | Default | Description |
|---|---|---|---|
| Description | Text | — | Optional description displayed on the node |
| Timeout (seconds) | Number | Pipeline default | Maximum time the node may run before timing out |
| Retry on Timeout | Toggle | Pipeline default | Automatically retry the node if it times out |
| Retry on Fail | Toggle | Pipeline default | Automatically retry the node if it fails |
| On Error | Selection | Pipeline default | Error strategy: Pipeline Default (the pipeline's Error Handling setting), Stop Pipeline or Continue Execution |
When left at their defaults, these settings inherit from the pipeline-level execution configuration.
Use the Test Function button in the function form (on the connection page) to validate every PI read/write function against the live PI server before wiring it into a pipeline. It's the fastest way to catch a wrong path, a bad time expression, or a write-type mismatch — and the AF Browser confirms exact paths.