PI System Nodes
Read from and write to an AVEVA PI Data Archive directly from pipelines, through the MaestroHub PI Agent. Each read or write function authored on a PI System connection is available as a matching node in the Pipeline Designer.
For connection setup, the PI Agent, the tag model, time expressions and per-function configuration fields, see the AVEVA PI System connection guide.
For the streaming trigger, see the PI System Trigger node.
The PI System connector reaches PI through the MaestroHub PI Agent, a Windows service you install inside the plant network. Download it from https://portal.maestrohub.com/downloads/plugins and see the installation guide.
Configuration quick reference
| Field | What you choose | Details |
|---|---|---|
| Parameters | Connection, Function, Function Parameters, Timeout Override | Select the PI System 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, and error strategy. All default to pipeline-level values. |
PI System read nodes
There are four read node types, one per read function:
| Node | Function | Purpose | Common use cases |
|---|---|---|---|
| PI System Get Current Value | pisystem.get_current | The latest value of one or more points | Dashboard readings, setpoint readback |
| PI System Get Recorded Values | pisystem.get_recorded | Raw archived values over a time range | History backfill, post-incident traces |
| PI System Get Interpolated Values | pisystem.get_interpolated | Values resampled at a fixed interval | Aligning several tags onto one timeline |
| PI System Get Summary Values | pisystem.get_summary | Aggregates computed at the archive | Shift and daily reporting |
Node configuration
| Parameter | Type | Required | Description |
|---|---|---|---|
| Connection | Selection | Yes | PI System connection profile to use |
| Function | Selection | Yes | A read function of the matching type from that connection |
| Function Parameters | Dynamic | Varies | Auto-populated from the function schema — paths for Get Current; plus startTime / endTime and the mode's own fields for the historical reads. See the connection guide for field-level detail. |
| Timeout Override | Number (seconds) | No | Override the function's default timeout |
All function parameters support {{ expression }} syntax for dynamic values from the pipeline context, and ((paramName)) placeholders where the function defines them.
Input
The node receives the previous node's output as input, referenceable in parameter expressions as $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.
All four read types return the same result shape, which is what makes them easy to swap:
{
"result": {
"mode": "current",
"values": [
{ "path": "\\\\PISRV01\\SINUSOID", "t": "2026-09-01T08:00:00Z", "v": 42.5, "q": "good" },
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T07:59:58Z", "v": 118.2, "q": "good" }
],
"count": 2,
"truncated": false,
"failed": [],
"pages": 1
},
"_metadata": {
"success": true,
"functionId": "<function-id>",
"durationMs": 18,
"timestamp": "2026-09-01T08:00:00Z"
}
}
| Field | Type | Description |
|---|---|---|
_metadata.mode | string | current, recorded, interpolated or summary — a fact about the call, delivered with the execution facts |
result.values | array | One entry per value returned |
result.values[].path | string | The path exactly as the function requested it |
result.values[].t | string | Timestamp, ISO 8601 UTC |
result.values[].v | number | string | boolean | null | The value |
result.values[].q | string | Quality — good, uncertain or bad |
result.values[].systemState | number | Present only when v is null — the PI system-state code explaining why |
result.count | number | Length of values |
_metadata.truncated | boolean | true when the result was cut short rather than complete |
result.failed | array | One {path, error} per path that could not be read |
_metadata.pages | number | How many requests were issued to the agent |
_metadata.method, _metadata.connectionId, _metadata.protocol | string | The call's other facts: the operation, the connection it ran over, and pisystem |
Access pattern in downstream nodes:
{{ $node["PI System Get Current Value"].result.values[0].v }}
{{ $node["PI System Get Current Value"].result.count }}
{{ $node["PI System Get Recorded Values"]._metadata.truncated }}
Because values is an array even for a single tag, a downstream JavaScript node usually iterates it:
const rows = $node["PI System Get Current Value"].result.values;
return rows
.filter((r) => r.q === "good")
.map((r) => ({ tag: r.path, value: r.v, at: r.t }));
A path that cannot be read does not fail the node. It appears in result.failed with its own reason while every other tag returns normally, and _metadata.success stays true.
If a missing tag should stop the pipeline, test it explicitly — for example with a Condition node on {{ $node["PI System Get Current Value"].result.failed.length }}.
truncated on history readsA recorded or interpolated read returns at most 100,000 values per request. When more data existed than the request could return, _metadata.truncated is true and the result is partial.
Set Maximum Values on the function above one request's worth to page the range automatically. A pipeline that ignores truncated will silently process an incomplete window.
PI System Write Values node
Write a batch of values to PI points.
| Node | Function | Purpose | Common use cases |
|---|---|---|---|
| PI System Write Values | pisystem.write | Write one or more values, each with its own outcome | Setpoint writeback, pushing lab results into PI |
Node configuration
| Parameter | Type | Required | Description |
|---|---|---|---|
| Connection | Selection | Yes | PI System connection profile to use |
| Function | Selection | Yes | A pisystem.write function from that connection |
| Function Parameters | Dynamic | Varies | values (the rows to write) and option (existing-value handling). Both support ((paramName)) templates and {{ expression }}. |
| Timeout Override | Number (seconds) | No | Override the function's default timeout |
The values parameter is the node's payload. It accepts an array of objects, each with a path, a value, and an optional timestamp:
{{ $input[0].result }}
If the function's values parameter is left empty, the node's input is used as the batch — so a node that emits rows of the right shape can feed the write directly.
Output structure
{
"result": {
"successCount": 2,
"failureCount": 1,
"results": [
{ "path": "\\\\PISRV01\\TESTTAG", "success": true },
{ "path": "\\\\PISRV01\\TESTTAG2", "success": true },
{ "path": "\\\\PISRV01\\NOPE", "success": false, "error": "point not found" }
],
"queued": false
},
"_metadata": {
"success": true,
"functionId": "<function-id>",
"durationMs": 31,
"timestamp": "2026-09-01T08:00:00Z"
}
}
| Field | Type | Description |
|---|---|---|
result.successCount | number | How many items were written |
result.failureCount | number | How many items failed |
result.results | array | One entry per item, in the order supplied. error is present only on a failure. |
result.queued | boolean | true when PI was unavailable and the batch entered the agent's retry queue |
result.queuedNote | string | Present only when queued is true |
Access pattern:
{{ $node["PI System Write Values"].result.successCount }}
{{ $node["PI System Write Values"].result.failureCount }}
_metadata.success: trueThe node succeeds if the call succeeded. Individual items fail independently, so a batch where every item failed still returns _metadata.success: true with failureCount equal to the batch size.
Gate on result.failureCount — not on _metadata.success — if a failed item should stop the pipeline or raise an alert.
queued: true is not a completed writeWhen PI is unavailable the agent accepts the batch into a bounded, in-memory retry queue. Those values have not been written, and the queue does not survive the agent stopping. Treat queued: true as "accepted, outcome unknown".
A value written to PI can drive downstream control, reporting and alarms. Bound the value with a Condition node, or gate it behind an explicit operator action, before the write reaches PI.
Batches over 10,000 items are split automatically. The write is therefore not atomic — each item succeeds or fails on its own.
What these nodes cannot do
| Browse | Tag browsing has no pipeline node. It is the Tag Browser's engine — a question about the connection, not a step in a pipeline. |
| Agent Status | Health has no pipeline node either; it drives the connection's Health tab. |
| AF attributes | Paths containing a | are refused. Use the underlying PI point, or the PI Web API nodes. |
| Store-and-forward | PI writes are not buffered by MaestroHub. A write that cannot be delivered is reported as a failure for the pipeline to handle. |
See the connection guide's Limitations for the full list, including digital points reading back as ordinals and summary values carrying no label.
Settings tab
All PI System 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 inherit from the pipeline-level execution configuration.
Use Test Function on the function form to validate a read or write against the live PI System before putting it in a pipeline. It prompts for any ((parameter)) values and shows the real result — the fastest way to catch a wrong path, an unsupported time expression, or an AF path that should have been a PI point.