Skip to main content
Version: 3.0 (next)

AVEVA PI System AVEVA PI System Integration Guide

Stream and query an AVEVA PI Data Archive at high throughput through the MaestroHub PI Agent — a Windows service you run inside the plant network. MaestroHub connects out to the agent over a single WebSocket; the agent talks to PI on your behalf.

This guide covers installing and connecting the agent, every connection and function field, the tag model, worked examples with real inputs and outputs, and the connector's limitations.

Overview​

The PI System connector provides:

  • High-throughput streaming of PI point values with quality and timestamps
  • Subscriptions by explicit tag list, name wildcard, or AF element subtree
  • Four read modes — current, recorded (raw archive), interpolated (fixed grid), and summary (aggregates)
  • Batch writes with a per-item outcome, so bad paths fail individually rather than failing the batch
  • Automatic gap backfill after a connection or archive outage
  • Tag browsing — search PI points by name, or walk the Asset Framework hierarchy
  • TLS with your own PKI, including private certificate authorities
The PI Agent is required

This connector does not talk to PI directly. It requires the MaestroHub PI Agent running on a Windows machine that can reach your PI Data Archive.

Download it from https://portal.maestrohub.com/downloads/plugins.

The agent is a self-contained Windows x64 build — there is no .NET runtime to install and nothing to compile. MaestroHub then connects out to it, so the agent needs no access to MaestroHub; MaestroHub needs access to the agent.

For step-by-step download, configuration and startup instructions, see the PI Agent Installation Guide.

Which PI connector should I use?​

MaestroHub has two connectors that reach a PI System. They are siblings, not duplicates:

PI System (this connector)PI Web API
How it reaches PIThe MaestroHub PI Agent, installed on a Windows hostPI Web API's REST interface, over HTTPS
Anything to install?Yes — the agentNo
Best forThroughput; streaming many tags at high ratesConvenience; when you cannot install software
AF attributesNot supported — PI points onlySupported
Trigger deliversA batch of values per eventOne value per event

Use PI System when throughput matters. Use PI Web API when the agent cannot be installed, or when you need Asset Framework attribute data.

How the connection works​

MaestroHub  ──── WebSocket (TCP 45283) ───►  PI Agent  ──── PI protocol ───►  PI Data Archive
(Windows) (TCP 5450/5457)

One WebSocket carries two planes: JSON for requests and subscription management, and a compact binary format for value data. The binary plane is what makes high value rates reachable.

Three consequences worth knowing before you start:

  1. MaestroHub dials the agent, not the other way round. The agent listens on TCP 45283; that port must be reachable from the MaestroHub host.
  2. One MaestroHub session per agent. The agent serves a single session at a time and deliberately prefers the newest arrival — a second connection displaces the first. This is why the connector's scaling is fixed at one replica (see Scaling).
  3. The agent keeps running when PI is down. It retries with backoff and reports the problem through its health endpoint, rather than exiting.

Connection configuration​

Navigate to Connect → New Connection → AVEVA PI System. The form has seven tabs.

TabWhat it holdsAvailable before saving?
ConnectionProfile name, description, labels; agent host and portYes
SecurityAPI token, TLS, CA certificate, skip-verifyYes
AdvancedTimeouts, framing, flow controlYes
FunctionsThis connection's functionsYes, but empty until saved
Tag BrowserBrowse the server and build functions from a selectionNo — save first
ScalingReplica settingsNo — save first
HealthLive agent and PI countersNo — save first

The last three need a live connection to call the agent, so they stay disabled until the connection is saved. Each carries the reason in its tooltip. A tab showing a red badge has that many validation errors inside it.

1. Profile information​

FieldDefaultDescription
Profile Name—A descriptive name for this connection (required, max 100 characters). Must be unique across all connections.
Description—Optional description for this connection
Labels—Key-value pairs to categorize the connection (max 10 labels)

2. Connection​

FieldTypeRequiredDefaultDescription
Agent HostTextYes—Hostname or IP of the machine running the PI Agent, e.g. pi-agent.plant.local. With TLS on, this must match the certificate's DNS name.
Agent PortNumberNo45283Port the PI Agent listens on (1–65535)

3. Security​

FieldTypeRequiredDefaultDescription
API TokenText (secret)Yes—The shared token the agent expects — the ApiToken value from the agent's appsettings.json, character for character. Stored encrypted. When editing an existing connection, leave it empty to keep the stored token.
Use TLSToggleNotrueEncrypt the connection. Must match the agent's own EnableTLS setting.
CA Certificate (PEM)TextNo—The certificate authority that signed the agent's certificate, PEM-encoded. Needed when the agent uses a private PKI the MaestroHub host does not already trust — the normal shape of a plant deployment. Leave empty to use the host's own trust store.
Skip Certificate VerificationToggleNofalseAccept any certificate the agent presents. Lab rigs only.
Three things that will cost you an afternoon
  1. The API token is sent with no Bearer prefix. The agent rejects a prefixed token on purpose, so a mistake fails loudly at connect time instead of appearing to work. Do not add a prefix, and watch for a trailing space when pasting.
  2. Use TLS must agree with the agent. If they disagree, the dial fails during the handshake and the error reads like a network problem.
  3. CA Certificate and Skip Certificate Verification are mutually exclusive. Setting both is refused when you save — skipping verification ignores the CA entirely, so the CA you pasted would be silently unused. Pick one.
Leave TLS on outside a lab

This WebSocket carries both your process data and the API token. Over plaintext the token is readable and replayable by anyone on the network path. Turn TLS off only for a loopback connection (agent and MaestroHub on the same machine) or an isolated lab network.

4. Advanced​

Every field here has a working default. Leave all six alone on a first run.

FieldTypeDefaultRangeDescription
Connection Timeout (seconds)Number301–300How long to wait for the WebSocket handshake and the agent's greeting.
Request Timeout (seconds)Number601–3600Deadline for one read, write or browse. The agent applies no deadline of its own, so this is the only bound on a call against a slow archive. Raise it if a wide history read times out.
Heartbeat Interval (seconds)Number305–300How often an application-level heartbeat is sent. Its reply carries the agent's PI connection state, so a live socket over a dead archive is reported unhealthy instead of looking fine.
Maximum Frame Size (bytes)Number4194304 (4 MiB)65536–67108864Largest binary frame accepted. Must be at least the agent's own frame cap, which it advertises when the session opens. Both default to 4 MiB — if you raise one, raise the other. A mismatch is caught when the session opens rather than discovered as a truncated read under load.
Subscribe Batch Size (bytes)Number524288 (512 KiB)65536–1048576How much encoded JSON goes in one subscribe message. The agent discards any control message above 1 MiB, so a large subscription is split into batches. Measured in bytes rather than tag count because PI path lengths vary by an order of magnitude.
Flow Control Window (frames)Number1288–256How many data frames the agent may send before waiting for more credit. This is the outermost ring of backpressure. Raising it above the agent's own buffer inverts the order backpressure is meant to happen in, and is refused.

Testing the connection​

Press Test Connection before saving. This is a real round trip — it dials the agent, completes the handshake and pings — and reports the latency in milliseconds.

Message containsCause
401 / unauthorizedToken mismatch. Check for a Bearer prefix or a trailing space.
connection refusedThe agent is not running, or Agent Port is wrong.
no route / timeoutA firewall, or the agent is bound to 127.0.0.1 while MaestroHub is on another machine.
TLS handshake / certificateUse TLS and the agent's EnableTLS disagree, or the certificate is not trusted and no CA was supplied.
unsupported protocol versionThe agent build is older than the connector. Update the agent.
the PI Agent is reachable but its connection to the PI Data Archive is "Disconnected"MaestroHub reached the agent fine — the problem is between the agent and PI. Check the agent's health endpoint.

After saving, the connection is created active and starts on its own. The Tag Browser, Scaling and Health tabs then become available.

The tag model​

Every read, write and subscription targets PI points, identified by path.

Path shapeExampleNotes
Server-qualified\\PISRV01\SINUSOIDWhat the Tag Browser returns, and what you should store
Bare tag nameSINUSOIDAlso resolves

Whatever you send is echoed back verbatim in results and in failures, so you can match rows to your input.

Asset Framework attribute paths are not supported

The agent provides PI point data access, not AF attribute data access. A path containing a | — for example \\PISRV01\Production\Boiler1|Temperature — is refused with a message that names the limitation:

AF attribute data access is not supported by this agent; use a PI point path.

Where an AF attribute is backed by a PI point, use the underlying point instead. Native AF attributes with no PI point behind them are unreachable through this connector — the value lives in AF, not in the archive. If you need AF attribute data, use the PI Web API connector.

You can still browse the AF hierarchy to find assets, and subscribe to every PI point beneath an AF element.

Tag Browser​

Browsing is not a function you create. It is the tag picker's engine — a question about the connection rather than a step in a pipeline — so it never appears in the function-type picker and has no pipeline node. It surfaces in two places, both calling the same operation:

  • The connection's Tag Browser tab, where a selection becomes a read or subscribe function in one step.
  • The Tag Browser panel beside the tag list on any read or subscribe function form, where a selection fills in that function's tags.

Two modes:

ModeWhat it does
PointsSearch PI points by name. * and ? are wildcards; an empty filter matches everything.
AFWalk the Asset Framework element tree one level at a time.

Results are paged, and Load more fetches the next page.

A filter with non-ASCII characters matches nothing

A browse filter such as Çim* returns zero results even where such tags exist. The PI client encodes outbound names in the host's ANSI code page while the archive holds UTF-8, so any lookup that transmits a non-ASCII name misses. The agent recovers non-ASCII names it can reconstruct without transmitting them, so such tags still appear in unfiltered results and stream normally — it is specifically the filter that cannot match them. The fix is the agent host's code page.

Time expressions​

Time fields accept three forms, and nothing else:

FormExamplesMeaning
RFC 3339 timestamp2026-09-01T08:00:00ZAn absolute instant
Relative offset from now-1h, -30m, -7d, -90sThat much before now
Empty, now, or *Now

An offset must carry a unit — ms, s, m, h, or d (days). A bare number is rejected. A leading + is also accepted (+1h is one hour into the future), which is only meaningful against future-data points.

PI time syntax is not supported

Expressions such as *-1h, t, y, or Monday are not accepted — only the three forms above. This is deliberate: supporting a fraction of PI's time syntax while appearing to support all of it would return real data for the wrong window, and nothing downstream could tell. An unrecognised expression is rejected with a message naming the accepted forms.

Note that -1h (this connector) and *-1h (PI's own syntax, used by the PI Web API connector) mean the same thing but are written differently.

Functions​

Open the connection's Functions tab and click New Function. There are six selectable function types.

FunctionType IDCategoryPurpose
Get Current Valuepisystem.get_currentReadThe most recent value of one or more points
Get Recorded Valuespisystem.get_recordedReadRaw archived values over a time range
Get Interpolated Valuespisystem.get_interpolatedReadValues resampled at a fixed interval
Get Summary Valuespisystem.get_summaryReadAggregates computed at the archive
Write Valuespisystem.writeWriteWrite a batch of values to PI points
Subscribe to Tag Valuespisystem.subscribeTriggerStart a pipeline on every new value
Two operations are internal

Browse Tags and Agent Status are marked internal and do not appear in the picker or the pipeline palette. Browse powers the Tag Browser; Agent Status powers the Health tab. Both are still served at runtime — they are simply not things you create.

The read result shape​

All four read types return the same envelope:

FieldTypeDescription
metadata.modestringcurrent, recorded, interpolated or summary — a fact about the call, delivered with the metadata (_metadata.mode in a pipeline)
valuesarrayOne entry per value returned (see below)
countnumbervalues.length
metadata.truncatedbooleantrue when the result was cut short — see Limits and paging; _metadata.truncated in a pipeline
failedarrayOne {path, error} per path that could not be read
metadata.pagesnumberHow many requests were issued to the agent — metadata, like the two above

Each entry in values:

FieldTypeDescription
pathstringThe path exactly as you sent it
tstringTimestamp, ISO 8601 UTC
vnumber | string | boolean | nullThe value
qstringQuality — good, uncertain or bad
systemStatenumberPresent only when v is null; the PI system-state code explaining why
Partial failure is per tag, not per request

One bad path does not fail the call. It appears in failed with its own reason while every other tag returns normally — so one mistyped tag in a list of hundreds costs only that tag.

Get Current Value (pisystem.get_current)​

Read the most recent archived value of one or more PI points.

FieldTypeRequiredDefaultDescription
Tag PathsListYes—One PI point path per row. Supports ((parameter)) templates.

Example input

FieldValue
Tag Paths\\PISRV01\SINUSOID, \\PISRV01\CDT158, MH.NO.SUCH.TAG

Example output

{
"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,
"failed": [
{ "path": "MH.NO.SUCH.TAG", "error": "point not found" }
]
}

Use cases: show the current temperature of every reactor on a dashboard; read a setpoint before deciding whether to write a new one.

Get Recorded Values (pisystem.get_recorded)​

Read values exactly as the PI Archive stored them — no interpolation, and unevenly spaced, because PI compresses.

FieldTypeRequiredDefaultDescription
Tag PathsListYes—PI point paths to read. Supports templates.
Start TimeTextYes—Range start. RFC 3339 or a relative offset. Supports templates.
End TimeTextNo(now)Range end, same formats. Empty means now. Supports templates.
Maximum ValuesNumberNo0Total values to return across every tag. 0 issues a single request. See below.
Maximum Values Per TagNumberNo0Per-tag cap within each request. 0 uses the agent's default.

Limits and paging​

One request returns at most 100,000 values across all tags.

  • Maximum Values = 0 (the default) issues exactly one request. If the archive held more than that request could return, truncated comes back true — the result is honest about being partial rather than looking complete.
  • Maximum Values greater than 0 pages the time range automatically until that many values are collected. Each page is one round trip, so set it to what you actually need.

Example input

FieldValue
Tag Paths\\PISRV01\CDT158
Start Time-1h
End Time(empty)
Maximum Values0

Example output

{
"values": [
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T07:03:12.421Z", "v": 117.9, "q": "good" },
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T07:19:48.115Z", "v": 118.4, "q": "good" },
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T07:51:03.902Z", "v": 118.2, "q": "good" }
],
"count": 3,
"failed": []
}

Use cases: backfill yesterday's production data into a warehouse; pull the raw trace behind an alarm for a post-incident review.

Get Interpolated Values (pisystem.get_interpolated)​

Read one value per interval across the range, interpolated by PI from archived data. Use this when values from several tags must line up on the same timestamps — raw archived data will not, because each tag compresses independently.

FieldTypeRequiredDefaultDescription
Tag PathsListYes—PI point paths to read. Supports templates.
Start TimeTextYes—Range start. Supports templates.
End TimeTextNo(now)Range end. Empty means now. Supports templates.
Sampling Interval (ms)NumberYes—Milliseconds between successive samples. Must be greater than 0. Supports templates.

Example input

FieldValue
Tag Paths\\PISRV01\CDT158, \\PISRV01\SINUSOID
Start Time2026-09-01T08:00:00Z
End Time2026-09-01T08:02:00Z
Sampling Interval (ms)60000

Example output — note both tags share the same timestamps, which is the point:

{
"values": [
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T08:00:00Z", "v": 118.2, "q": "good" },
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T08:01:00Z", "v": 118.6, "q": "good" },
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T08:02:00Z", "v": 119.1, "q": "good" },
{ "path": "\\\\PISRV01\\SINUSOID", "t": "2026-09-01T08:00:00Z", "v": 42.5, "q": "good" },
{ "path": "\\\\PISRV01\\SINUSOID", "t": "2026-09-01T08:01:00Z", "v": 43.9, "q": "good" },
{ "path": "\\\\PISRV01\\SINUSOID", "t": "2026-09-01T08:02:00Z", "v": 45.2, "q": "good" }
],
"count": 6,
"failed": []
}

Use cases: build an hourly energy profile across several meters; align a dozen sensors onto one timeline before a calculation.

Get Summary Values (pisystem.get_summary)​

Ask PI to calculate aggregates over the range and return only the results. The calculation happens at the archive, so a month of one-second data becomes a handful of numbers on the wire instead of millions of values.

FieldTypeRequiredDefaultDescription
Tag PathsListYes—PI point paths to summarise. Supports templates.
Start TimeTextYes—Range start. Supports templates.
End TimeTextNo(now)Range end. Empty means now. Supports templates.
Summary TypesCheckboxesYesaverageWhich aggregates to compute.

Summary Types are checkboxes, not free text. The available values are:

total, average, minimum, maximum, range, stddev, count, percent_good

Tick one summary type per function

A summary result carries no label saying which summary each value is — the wire format has no field for it. Tick three types and you get three unlabelled values for the same tag, in no documented order, with no way to tell the minimum from the maximum.

Request one summary type per function. If you need an average and a maximum, create two functions.

Example input

FieldValue
Tag Paths\\PISRV01\CDT158
Start Time-24h
End Time(empty)
Summary Typesaverage only

Example output

{
"values": [
{ "path": "\\\\PISRV01\\CDT158", "t": "2026-09-01T08:00:00Z", "v": 118.37, "q": "good" }
],
"count": 1,
"failed": []
}

Use cases: daily average and peak flow for a monthly report; percentage of good data for a sensor health check.

Write Values (pisystem.write)​

Send a batch of values to the archive in one call.

FieldTypeRequiredDefaultDescription
ValuesList of rowsYes—The values to write. Each row is a path, a value, and an optional timestamp. Supports templates.
Existing Value HandlingSelectNoreplaceWhat to do when a value already exists at the same timestamp.

Each row in Values:

ColumnRequiredDescription
pathYesThe PI point to write to
valueYesThe value. Numbers, strings and booleans are all accepted; the agent coerces to the point's actual PI type.
timestampNoRFC 3339 or a relative offset. Empty stamps the value with the current time.

Existing Value Handling options:

OptionBehaviour
replace (default)Overwrite the existing value at that timestamp
insertAdd alongside the existing value
no_replaceKeep the existing value; do not write

Writing a digital state by name. A digital point's state can be written by name rather than by ordinal — write "Open" rather than 1. Note this only works in this direction: reading a digital point returns the ordinal number, not the name (see Limitations).

Example input

FieldValue
Values\\PISRV01\TESTTAG = 12.5 · \\PISRV01\TESTTAG2 = 7.25 at 2026-09-01T08:00:00Z · \\PISRV01\NOPE = 1
Existing Value Handlingreplace

Example output — two writes applied, one path rejected:

{
"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
}
FieldDescription
successCountHow many items were written
failureCountHow many items failed
resultsOne entry per item, in the order you supplied them. error is present only on a failure.
queuedtrue when PI was unavailable and the batch went into the agent's retry queue
queuedNotePresent only when queued is true; explains what that means
queued: true is not a durability guarantee

When PI is unavailable, the agent accepts the batch into a bounded, in-memory retry queue and reports queued: true. Those values have not been written yet, and the queue does not survive the agent stopping.

Treat queued: true as "accepted, outcome unknown" — not as success. If the write must not be lost, check the result and re-issue it yourself.

Writes drive real plant behaviour

A value written to PI can drive downstream control, reporting and alarms. Gate writes behind a Condition node that bounds the value, or behind an explicit operator action, before the write reaches PI.

Batches larger than 10,000 items are split automatically, so a large write is not refused — but it is also not atomic. Each item succeeds or fails on its own.

Subscribe to Tag Values (pisystem.subscribe)​

Register tags for streaming and start a pipeline as values arrive. This function type is a pipeline trigger — see the PI System Trigger node.

FieldTypeRequiredDefaultDescription
Tag PathsListNo—Tags to subscribe explicitly
Name FilterTextNo—Subscribe to every tag matching this pattern; * and ? are wildcards
AF Element PathTextNo—Subscribe to every PI point beneath this Asset Framework element
Maximum TagsNumberNo10000Refuse the subscription if the selectors resolve to more tags than this (1–200,000)
Maximum Values Per EventNumberNo0Split large batches into events of at most this many values. 0 keeps each batch whole.
Include Recovered ValuesToggleNotrueDeliver values the agent recovers after an outage

The three selectors — Tag Paths, Name Filter and AF Element Path — combine. Their union is de-duplicated, so a tag matched twice costs one subscription. At least one must resolve to something: if all three select nothing, the subscription is refused with a message naming all three.

One event carries many values

Unlike most triggers, this one delivers a batch. At full rate, one pipeline execution per value is not a workable shape, so the connector emits one event per decoded frame — up to 8,000 values. Downstream nodes iterate result.values rather than reading a single reading.

Maximum Tags guards against a wildcard quietly claiming the whole archive. When it binds, the error names how many tags actually matched.

Subscription fields are not templatable

Unlike the read and write functions, the subscribe function's fields do not accept ((parameter)) placeholders. A subscription is resolved once when the pipeline is enabled, so there is no execution to take parameter values from.

Some tags will not stream

PI refuses to sign certain points up to a snapshot pipe — future-data points are the common case, and on a real archive they can be several percent of all points. The subscription is still established; those specific tags simply never deliver.

This is reported rather than hidden. Check the Health tab:

  • streaming.subscriptionsNotStreaming — how many are affected
  • connector.tagsNotStreaming — which paths, each with the agent's reason and whether it is retryable

Using parameters​

Path, time and value fields on read and write functions accept ((parameterName)) placeholders. Parameters are detected as you type and appear in the Function Parameters block, where you can set a type, mark them required, and give a default.

Example

  • Function type: Get Recorded Values
  • Tag Paths: ((tag))
  • Start Time: ((from))
  • End Time: ((to))

At execution the pipeline binds tag, from and to, so one function serves many contexts. The same function can be tested from the form — the Test Function dialog prompts for each detected parameter.

Testing functions​

Read and write functions can be tested before saving with Test Function. The dialog shows the resolved configuration, prompts for any ((parameter)) values, runs the function against the live PI System, and renders the result with timing.

You do not need to save the function first.

Subscribe functions cannot be tested this way — they are validated by enabling the pipeline that uses them. Browse and Agent Status are internal and are exercised by the Tag Browser and the Health tab.

Health and Agent Status​

The Health tab (available after saving) shows the agent's own view of itself, refreshed live. Useful fields when something looks wrong:

GroupFieldWhat it tells you
pistateThe agent's connection to PI. Connected is what you want.
streamingsubscriptionsHow many points are actually streaming
streamingsubscriptionsNotStreamingHow many were subscribed but deliver nothing — the number that explains a tag list where some rows never move
throughputvaluesPerSecond1mValues per second over the last minute
flowControlpausedWhether backpressure is currently applied
writesqueueDepthHow many writes are waiting in the agent's retry queue
connectortagsNotStreamingWhich of your paths are not delivering, and why

Scaling​

The Scaling tab is fixed at one replica and cannot be changed.

This is not a limitation of MaestroHub but of the agent: it serves one WebSocket session at a time and deliberately prefers the newest arrival. That is the right behaviour for a redeploy — an ungraceful restart can otherwise leave a dead session holding the slot for minutes — but it means two MaestroHub instances pointed at one agent would evict each other indefinitely, and neither would finish subscribing.

If you need more throughput than one agent provides, run more agents against different tag sets and create one MaestroHub connection per agent.

Pipeline integration​

Functions you author here become nodes in the Pipeline Designer:

  • PI System Get Current Value (connected.pisystem.get_current)
  • PI System Get Recorded Values (connected.pisystem.get_recorded)
  • PI System Get Interpolated Values (connected.pisystem.get_interpolated)
  • PI System Get Summary Values (connected.pisystem.get_summary)
  • PI System Write Values (connected.pisystem.write)
  • PI System Trigger (trigger.pisystem) — starts a pipeline on each batch of streamed values

For node-level details, see the PI System Nodes and PI System Trigger pages.

Common use cases​

Stream a production line into the UNS​

Author a Subscribe function with a Name Filter covering the line's tags, drive it from the PI System Trigger, and route result.values into the Unified Namespace. Each event carries a batch, so iterate the array rather than reading one value.

Nightly history backfill​

Author a Get Recorded Values function with Start Time -24h, set Maximum Values to the volume you expect so the range pages automatically, and drive it from a Schedule trigger into a database or storage node. Check truncated in the result to know whether you got everything.

Shift reporting​

Author a Get Summary Values function with a single summary type (average) over the shift window, and forward the values to a reporting sink. The aggregate is computed at the archive, so the transfer is a handful of numbers.

Setpoint writeback​

Compute a setpoint upstream, validate it with a Condition node, then issue a parameterised Write Values function with ((setpoint)) as the value. Check successCount and results in the output — and remember that queued: true is not yet a write.

Limitations​

These are deliberate and known. They are listed here so you can design around them rather than discover them.

BehaviourWhy
AF attribute paths (anything with a |) are refused.The agent provides PI point data access, not AF attribute data access. Use the underlying PI point, or the PI Web API connector.
Native AF attributes with no PI point behind them are unreachable.The value lives in AF, not in the archive — there is nothing to read.
A digital point reads back as a number, not a state name.The state's ordinal is what crosses the wire. A state name only goes the other way, on a write.
A timestamp point's value reads back as a number.It is carried as Unix-epoch 100-nanosecond ticks, like every other timestamp on the wire.
A 32-bit float point does not read back the exact decimal you wrote.Single-precision rounding: 42.3 becomes 42.29999923706055. This is how the point stores it, not a transport error.
A summary read carries no label saying which summary each value is.The wire format has no field for it. Request one summary type per function.
A browse filter containing non-ASCII characters matches nothing.The PI client transmits names in the host's ANSI code page while the archive holds UTF-8. Affects the filter only — such tags still appear unfiltered and stream normally.
Future-data points cannot be subscribed.PI itself refuses to sign them up to a snapshot pipe. Reported through tagsNotStreaming rather than hidden.
Only one MaestroHub session per agent.The agent serves one session and prefers the newest. See Scaling.
PI time syntax is not supported — only RFC 3339, relative offsets and empty/now.Supporting part of PI's syntax while appearing to support all of it would return real data for the wrong window.
queued: true on a write is not a durability guarantee.The agent's retry queue is in memory and bounded, and does not survive the agent stopping.
Writes are not covered by store-and-forward.If a write cannot be delivered, it is reported as a failure for the pipeline to handle — it is not buffered and retried by MaestroHub.
Agent configuration is read once, at startup.Editing appsettings.json while the agent runs changes nothing until you restart it. "I changed the setting and nothing happened" is usually a missing restart.

Troubleshooting​

Connection​

SymptomCauseFix
Test Connection returns 401Token mismatchCheck the token matches appsettings.json exactly. No Bearer prefix, no trailing space.
Connection refusedAgent not running, or wrong portConfirm the agent is running and Agent Port matches its Port.
Timeout / no routeFirewall, or agent bound to loopbackOpen TCP 45283 from the MaestroHub host; check the agent's ListenAddress is not 127.0.0.1.
TLS handshake failureUse TLS disagrees with the agent, or an untrusted certificateMake both sides agree; supply the CA, or use skip-verify for a lab rig — never both.
Save refused: skip-verify + CA both setThey contradict each otherProvide the CA to verify a private authority, or skip verification for a lab rig.
unsupported protocol versionAgent build is older than the connectorUpdate the agent from the portal.
Reachable, but PI is DisconnectedThe agent cannot reach PIThe problem is between the agent and PI, not MaestroHub. Check the agent's health endpoint and log.

Reads and writes​

SymptomCauseFix
One tag missing from valuesThat path failedLook in failed — it names the path and the reason.
AF attribute data access is not supportedThe path contains a |Use the underlying PI point path.
_metadata.truncated is trueMore data existed than one request returnsSet Maximum Values to page the range, or narrow the window.
Read times outThe archive is slow for that queryRaise Request Timeout; it is the only bound on the call.
A digital tag returns a numberExpectedReads return the ordinal. Map it downstream, or write by name.
Time expression rejectedPI syntax usedUse RFC 3339, a relative offset (-1h), or leave empty for now.
Write reports queued: truePI was unavailableNot yet written. Check PI, and re-issue if the value matters.

Subscriptions​

SymptomCauseFix
Subscription refused: resolved to no tagsSelectors match nothingCheck Tag Paths, Name Filter and AF Element Path; verify spellings in the Tag Browser.
Subscription refused: too many tagsThe selectors exceeded Maximum TagsNarrow the filter, or raise the limit deliberately.
Some tags never deliverPI will not stream themCheck connector.tagsNotStreaming on the Health tab — it names each path and the reason.
Filter with accented characters matches nothingCode-page limitationSubscribe those tags by explicit path, or fix the agent host's code page.
Prove each layer before the next

Most problems resolve fastest bottom-up: confirm the agent reports healthy, then that Test Connection passes, then that the Tag Browser returns tags, then that a Get Current Value function reads one of them. Each step rules out everything below it.