> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/aveva-pi-system-integration.md).

# AVEVA PI System Integration

This guide describes how to integrate the AVEVA PI System (formerly OSIsoft PI) with Connectware. You configure a service commissioning file that writes time-series data from the shop floor to a PI Point and reads the latest recorded values back into the MQTT topic hierarchy. A complete example file is available at the end of this guide.

## Objectives

* Establishing a connection between Connectware and the PI Web API with basic authentication.
* Resolving the WebId of a PI Point.
* Writing single and multiple time-series values to a PI Point.
* Reading the latest recorded value of a PI Point into an MQTT topic.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* A running AVEVA PI System with the PI Web API installed and reachable from Connectware. Basic authentication must be enabled on the PI Web API instance.
* A PI Point (tag) on the PI Data Archive that you want to write to or read from, and an account with write access to it.
* Access to the [Admin UI](/2-4-2/access/admin-ui.md) with sufficient [user permissions](/2-4-2/access/user-management.md).
* Basic knowledge of MQTT and the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), and [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)).

## Connectware and PI System Integration

The PI Web API is the RESTful interface of the PI System. It is served under the `/piwebapi` base path of its host, for example `https://pi-server.example.com/piwebapi`, on port 443 by default. Connectware communicates with it through the [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md).

Time-series data of a PI Point is read and written through the Stream controller of the PI Web API. Every PI Point is addressed by its WebId, an opaque string that the PI Web API generates. This guide uses the following Stream actions:

* `POST /streams/{webId}/value`: Writes one value to the PI Point.
* `POST /streams/{webId}/recorded`: Writes multiple recorded values to the PI Point in one request.
* `GET /streams/{webId}/end`: Returns the latest recorded value of the PI Point.

For the complete reference of these actions, see the [Stream controller in the PI Web API reference](https://docs.aveva.com/bundle/pi-web-api-reference/page/help/controllers/stream.html).

The PI Web API supports Kerberos, basic, bearer, and anonymous authentication, and enables Kerberos by default. Connectware does not support Kerberos. Add `Basic` to the `AuthenticationMethods` configuration item of your PI Web API instance to enable basic authentication. For more information, see [Authentication methods in the PI Web API documentation](https://docs.aveva.com/bundle/pi-web-api/page/1023024.html).

The MQTT topics in this guide follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The mappings subscribe with wildcards across all levels, so any machine in the hierarchy is picked up without changing the integration.

### Resolving the WebId of a PI Point

The Stream actions address a PI Point by its WebId, not by its tag name. You resolve the WebId once and set it as a parameter when you install the service. The Point controller returns a PI Point by its path, which consists of the name of the PI Data Archive server and the tag name in the form `\\<server>\<tag>`.

Query the WebId with an HTTP client of your choice, for example with curl:

{% code lineNumbers="true" %}

```bash
curl --user ${PI_USERNAME} --get 'https://pi-server.example.com/piwebapi/points' \
  --data-urlencode 'path=\\PISRV01\Line1.Press01.Temperature'
```

{% endcode %}

* `PISRV01`: The name of your PI Data Archive server.
* `Line1.Press01.Temperature`: The tag name of the PI Point.

The `--data-urlencode` option encodes the backslashes of the path for you. You can also open the URL in a browser, which encodes the path automatically. The response contains the WebId of the PI Point:

{% code lineNumbers="true" %}

```json
{
  "WebId": "F1DP000000000000000000000000000000000000",
  "Name": "Line1.Press01.Temperature",
  "Path": "\\\\PISRV01\\Line1.Press01.Temperature",
  "PointType": "Float32"
}
```

{% endcode %}

The default WebId encodes the path of the PI Point, so it stays valid as long as the tag is not renamed. Each PI Point has its own WebId. To integrate multiple PI Points, repeat the resolution step and add one endpoint per PI Point.

### PI Web API Connection Properties

The connection to the PI Web API requires the hostname, the credentials for basic authentication, and the WebId of the PI Point. We add them as parameters to the service commissioning file, so you can set them when you install the service.

Do not worry about copying the service commissioning file snippets together into one, the complete example file is available at the end of this guide.

* `piWebApiHost`: The hostname of the PI Web API server, without the scheme. For example, `pi-server.example.com`.
* `piUsername` and `piPassword`: The credentials for basic authentication. The PI Web API maps them to a Windows account, so the username may include a domain, for example `DOMAIN\pi-writer`.
* `piPointWebId`: The WebId of the PI Point, resolved as described in [Resolving the WebId of a PI Point](#resolving-the-webid-of-a-pi-point).
* `pollInterval`: The interval in milliseconds at which Connectware polls the latest recorded value.
* `topicRoot`: The root of the MQTT topic hierarchy. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  piWebApiHost:
    description: Hostname of the PI Web API server
    type: string
    default: pi-server.example.com

  piUsername:
    description: Username for basic authentication against the PI Web API
    type: string

  piPassword:
    description: Password for basic authentication against the PI Web API
    type: string

  piPointWebId:
    description: WebId of the PI Point to write to and read from
    type: string
    default: F1DP000000000000000000000000000000000000

  pollInterval:
    description: Polling interval for reading the latest recorded value, in milliseconds
    type: integer
    default: 5000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise
```

{% endcode %}

### PI Web API Connection

To connect to the PI Web API, we set up a `Cybus::Connection` resource that uses the HTTP/REST connector with basic authentication. The `prefix` property applies the `/piwebapi` base path to all endpoints of the connection, so the endpoint paths stay identical to the Stream actions of the PI Web API reference.

{% code lineNumbers="true" %}

```yaml
resources:
  piWebApiConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref piWebApiHost
        port: 443
        prefix: /piwebapi
        auth:
          username: !ref piUsername
          password: !ref piPassword
```

{% endcode %}

On-premises PI Web API installations often use self-signed certificates. In this case, add the root CA certificate as Base64-encoded PEM file content in the `caCert` property of the connection. For all TLS-related connection properties, see [HTTP Connection Properties](/2-4-2/connectors/enterprise-connectors/http-rest/httpconnection.md).

{% hint style="warning" %}
The connection also accepts `trustAllCertificates: true`, which disables certificate validation entirely. Do not use this option in production. Use the `caCert` property instead.
{% endhint %}

### Writing a Value to a PI Point

The `POST /streams/{webId}/value` action writes one value to the PI Point per request. The request body is a JSON object with a `Timestamp` and a `Value` property.

We define a write endpoint for this path and a mapping that feeds it from the MQTT topic hierarchy. The HTTP/REST connector expects the request body in the `body` property of the message (see [Publishing Data to REST Servers](/2-4-2/connectors/enterprise-connectors/http-rest.md#publishing-data-to-rest-servers)). Connectware endpoints publish machine data as a JSON object with a `timestamp` in milliseconds and a `value`. The `transform` rule converts this format into the request body that the PI Web API expects, using the JSONata function `$fromMillis` to turn the millisecond timestamp into an ISO 8601 string.

{% code lineNumbers="true" %}

```yaml
valueWriteEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref piWebApiConnection
    write:
      path: !sub '/streams/${piPointWebId}/value'

valueWriteMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/process-values'
        publish:
          endpoint: !ref valueWriteEndpoint
        rules:
          - transform:
              expression: '{ "body": { "Timestamp": $fromMillis(timestamp), "Value": value } }'
```

{% endcode %}

Any message published to a matching topic, for example `enterprise/hamburg/assembly/line-1/press-01/process-values`, now writes one value to the PI Point:

{% code lineNumbers="true" %}

```json
{
  "timestamp": 1752666000000,
  "value": 42.1
}
```

{% endcode %}

This example writes all matching topics to one PI Point. To write each machine to its own PI Point with a single endpoint, override the endpoint path per message instead of configuring it statically. For more information, see [Path Override for Write Operations](/2-4-2/connectors/enterprise-connectors/http-rest.md#path-override-for-write-operations).

### Writing Multiple Values in One Request

For buffered or high-frequency data, the `POST /streams/{webId}/recorded` action writes multiple recorded values in one request. The request body is a JSON array of objects with `Timestamp` and `Value` properties. The mapping expects an array of the same `timestamp` and `value` objects as in the single-value case and converts each entry.

{% code lineNumbers="true" %}

```yaml
recordedWriteEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref piWebApiConnection
    write:
      path: !sub '/streams/${piPointWebId}/recorded'

recordedWriteMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/process-values-batch'
        publish:
          endpoint: !ref recordedWriteEndpoint
        rules:
          - transform:
              expression: '{ "body": [ $.{ "Timestamp": $fromMillis(timestamp), "Value": value } ] }'
```

{% endcode %}

A message on a matching topic is a JSON array:

{% code lineNumbers="true" %}

```json
[
  { "timestamp": 1752666000000, "value": 42.1 },
  { "timestamp": 1752666001000, "value": 42.3 },
  { "timestamp": 1752666002000, "value": 42.2 }
]
```

{% endcode %}

### Reading the Latest Value of a PI Point

For the opposite direction, a subscribe endpoint polls the `GET /streams/{webId}/end` action at the configured interval. This action returns the latest recorded value of the PI Point. A mapping publishes the result to an MQTT topic, where any other Connectware service can pick it up, for example to write a setpoint back to a PLC.

{% code lineNumbers="true" %}

```yaml
latestValueEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref piWebApiConnection
    subscribe:
      path: !sub '/streams/${piPointWebId}/end'
      interval: !ref pollInterval

latestValueMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref latestValueEndpoint
        publish:
          topic: !sub '${topicRoot}/pi/latest-value'
```

{% endcode %}

The HTTP/REST connector wraps every response in a JSON object with a `timestamp` and a `value` property. The `value` property contains the response of the PI Web API, including the quality flags of the PI System:

{% code lineNumbers="true" %}

```json
{
  "timestamp": 1752666005123,
  "value": {
    "Timestamp": "2026-07-16T12:20:02Z",
    "Value": 42.2,
    "UnitsAbbreviation": "",
    "Good": true,
    "Questionable": false,
    "Substituted": false
  }
}
```

{% endcode %}

The related `GET /streams/{webId}/value` action returns the value at a requested time instead, which the PI Web API interpolates for interpolated PI Points. Use it in place of the `end` path if you need the current interpolated value rather than the latest recorded one.

## Verifying the Integration

1. Install the service and set the parameters with the values for your PI Web API instance.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI. If the connection does not reach the connected state, verify that the PI Web API certificate is trusted by Connectware.
3. Publish a test message such as `{ "timestamp": 1752666000000, "value": 42.1 }` to `enterprise/hamburg/assembly/line-1/press-01/process-values`, for example with an MQTT client or the Admin UI.
4. The result of every HTTP request is published to the `/res` topic of the endpoint. Use the [Data Explorer](/2-4-2/monitoring/data-explorer.md) to inspect it. If the PI Web API rejects a request, for example with status 401 for wrong credentials, the message on the `/res` topic contains an `error` property with the HTTP status.
5. Check the value in the PI System, for example in PI System Explorer or PI Vision. With the read mapping installed, the value also appears on the `enterprise/pi/latest-value` topic after the next polling interval.

## Service Commissioning File Example

{% file src="/files/Y994Tg2LGyFBRsE8BQUt" %}

{% code title="aveva-pi-system-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# AVEVA PI System Integration (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file for the bidirectional integration between
  Connectware and the AVEVA PI System via the PI Web API (Example)

metadata:
  name: AVEVA PI System Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  piWebApiHost:
    description: Hostname of the PI Web API server
    type: string
    default: pi-server.example.com

  piUsername:
    description: Username for basic authentication against the PI Web API
    type: string

  piPassword:
    description: Password for basic authentication against the PI Web API
    type: string

  piPointWebId:
    description: WebId of the PI Point to write to and read from
    type: string
    default: F1DP000000000000000000000000000000000000

  pollInterval:
    description: Polling interval for reading the latest recorded value, in milliseconds
    type: integer
    default: 5000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise

resources:
  # Connection to the PI Web API using basic authentication
  piWebApiConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref piWebApiHost
        port: 443
        prefix: /piwebapi
        auth:
          username: !ref piUsername
          password: !ref piPassword
        # If the PI Web API server uses a self-signed certificate, add the
        # root CA certificate as Base64-encoded PEM file content:
        # caCert: <BASE64_ENCODED_PEM>

  # Writes one value per message to the PI Point
  valueWriteEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref piWebApiConnection
      write:
        path: !sub '/streams/${piPointWebId}/value'

  valueWriteMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/process-values'
          publish:
            endpoint: !ref valueWriteEndpoint
          rules:
            - transform:
                expression: '{ "body": { "Timestamp": $fromMillis(timestamp), "Value": value } }'

  # Writes multiple recorded values per message to the PI Point
  recordedWriteEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref piWebApiConnection
      write:
        path: !sub '/streams/${piPointWebId}/recorded'

  recordedWriteMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/process-values-batch'
          publish:
            endpoint: !ref recordedWriteEndpoint
          rules:
            - transform:
                expression: '{ "body": [ $.{ "Timestamp": $fromMillis(timestamp), "Value": value } ] }'

  # Polls the latest recorded value of the PI Point
  latestValueEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref piWebApiConnection
      subscribe:
        path: !sub '/streams/${piPointWebId}/end'
        interval: !ref pollInterval

  latestValueMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref latestValueEndpoint
          publish:
            topic: !sub '${topicRoot}/pi/latest-value'
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/aveva-pi-system-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
