> 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/analytics-monitoring-alerting/power-bi-integration.md).

# Power BI Integration

This guide describes how to integrate Microsoft Power BI with Connectware. You configure a service commissioning file that pushes live shop floor data into a Power BI streaming semantic model, so dashboard tiles update within seconds of a machine publishing a value. A complete example file is available at the end of this guide.

## Objectives

* Creating a streaming semantic model in the Power BI service.
* Establishing a connection between Connectware and the Power BI REST API.
* Pushing shop floor data from MQTT topics into the streaming semantic model.
* Visualizing the live data on a Power BI dashboard.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* A Power BI account with permission to create dashboards and semantic models in a workspace of the Power BI service. Power BI Desktop is not required.
* 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 Power BI Integration

Power BI accepts real-time data through streaming semantic models, formerly known as streaming datasets. When you create a streaming semantic model in the Power BI service, Power BI generates a push URL on `api.powerbi.com`. The URL contains a resource key that authenticates the request, so no OAuth configuration is required. Connectware sends rows to this URL through the [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md), one POST request per MQTT message.

{% hint style="warning" %}

## Retirement of Real-Time Streaming in Power BI

Microsoft is retiring real-time streaming in Power BI. You can create new streaming semantic models until October 31, 2027. Existing streaming semantic models continue to work after that date. For new projects, Microsoft recommends [Real-Time Intelligence in Microsoft Fabric](https://learn.microsoft.com/en-us/fabric/real-time-intelligence/overview), where an Eventstream ingests the data instead. Eventstream custom endpoints accept data through the Kafka protocol, which you can address with the Connectware [Kafka connector](/2-4-2/connectors/enterprise-connectors/kafka.md). For more information, see [Real-time streaming in Power BI](https://learn.microsoft.com/en-us/power-bi/connect-data/service-real-time-streaming) in the Microsoft documentation.
{% endhint %}

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

### Creating a Streaming Semantic Model in Power BI

You create the streaming semantic model in the Power BI service and define its row schema there. The field names and types must match the data that Connectware sends later.

1. In the Power BI service, open an existing dashboard or create a new one.
2. Select **Edit** > **Add a tile**.
3. Select **Custom Streaming Data** and select **Next**.
4. Select **Add streaming semantic model**.
5. Select **API** and select **Next**.
6. Enter a name for the semantic model and define the values from the stream. This guide uses the fields `timestamp` (DateTime), `line` (Text), and `temperature` (Number).
7. Enable **Historic data analysis** if you want to build reports on the collected data. Without it, Power BI keeps the data only in a temporary cache for streaming tiles and discards it after about one hour.
8. Select **Create**.

Power BI now shows the push URL of the semantic model. It has the following form:

{% code lineNumbers="true" %}

```
https://api.powerbi.com/beta/<tenant-id>/datasets/<dataset-id>/rows?key=<resource-key>
```

{% endcode %}

{% hint style="danger" %}
The resource key authorizes anyone to push data into the semantic model, without any further authentication. Treat the push URL like a credential.
{% endhint %}

### Power BI Connection Properties

The connection to Power BI requires the parts of the push URL. 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.

* `tenantId`: The first identifier in the push URL, after `/beta/`.
* `datasetId`: The identifier in the push URL, after `/datasets/`.
* `pushKey`: The resource key, the value of the `key` query parameter. Copy it exactly as it appears in the push URL, it is already URL-encoded.
* `topicRoot`: The root of the MQTT topic hierarchy. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  tenantId:
    description: Tenant ID from the push URL of the streaming semantic model
    type: string
    default: 00000000-0000-0000-0000-000000000000

  datasetId:
    description: Dataset ID from the push URL of the streaming semantic model
    type: string
    default: 00000000-0000-0000-0000-000000000000

  pushKey:
    description: Resource key from the push URL (the value of the key query parameter)
    type: string

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

{% endcode %}

### Power BI Connection

To connect to the Power BI REST API, we set up a `Cybus::Connection` resource that uses the HTTP/REST connector. The connection only defines the host, because the resource key in the endpoint path handles the authentication.

{% code lineNumbers="true" %}

```yaml
resources:
  powerBiConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: api.powerbi.com
        port: 443
```

{% endcode %}

### Pushing Shop Floor Data to Power BI

The rows endpoint of the streaming semantic model expects a POST request with a JSON array of rows as the body. Each row is an object whose property names match the fields that you defined in the schema.

We define a write endpoint for the rows 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)). The `transform` rule wraps the incoming payload into the rows array and adds the current time as the `timestamp` field, so machines can publish their data without knowing about these conventions.

{% code lineNumbers="true" %}

```yaml
powerBiRowsEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref powerBiConnection
    write:
      path: !sub '/beta/${tenantId}/datasets/${datasetId}/rows?key=${pushKey}'

powerBiRowsMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/telemetry'
        publish:
          endpoint: !ref powerBiRowsEndpoint
        rules:
          - transform:
              expression: '{ "body": [ $merge([$, { "timestamp": $now() }]) ] }'
```

{% endcode %}

Any message published to a matching topic, for example `enterprise/hamburg/assembly/line-1/press-01/telemetry`, now becomes one row in the semantic model. The property names in the payload must match the schema fields:

{% code lineNumbers="true" %}

```json
{
  "line": "line-1",
  "temperature": 42.1
}
```

{% endcode %}

The transform rule turns this payload into the rows array that Power BI expects as the request body:

{% code lineNumbers="true" %}

```json
[
  {
    "line": "line-1",
    "temperature": 42.1,
    "timestamp": "2026-07-16T09:00:00.000Z"
  }
]
```

{% endcode %}

If your machines already publish a timestamp, remove the `$merge` call and use `{ "body": [ $ ] }` instead. Power BI accepts DateTime values in ISO 8601 format.

### Ingestion Limits

Power BI limits how fast you can push data. A streaming semantic model accepts up to five requests per second with up to 15 KB per request. With **Historic data analysis** enabled, the model is also a push semantic model, which accepts one request per second with up to 16 MB per request and up to one million rows per hour. A request that exceeds the streaming limit but stays within the push limit still stores the data, but streaming tiles temporarily fail. For details, see [Real-time streaming in Power BI](https://learn.microsoft.com/en-us/power-bi/connect-data/service-real-time-streaming) in the Microsoft documentation.

Connectware sends one request per MQTT message. If your machines publish faster than the limits allow, reduce the message rate before it reaches the endpoint, for example with [Rule Engine](/2-4-2/data-flows/rule-engine.md) rules that filter or aggregate the data.

### Visualizing the Data in Power BI

To display the live data, add a streaming tile to a dashboard:

1. On the dashboard, select **Edit** > **Add a tile**.
2. Select **Custom Streaming Data** and select **Next**.
3. Select your streaming semantic model and select **Next**.
4. Choose a visualization type, for example a line chart with `timestamp` as the axis and `temperature` as the value.

If you enabled **Historic data analysis**, you can additionally build regular Power BI reports on the semantic model, with the full set of report features such as filtering and data alerts.

## Verifying the Integration

1. Install the service and set the parameters to the values from your push URL.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI.
3. Publish a test message with the schema fields to `enterprise/hamburg/assembly/line-1/press-01/telemetry`, for example with an MQTT client or the Admin UI.
4. Check that the streaming tile on your dashboard updates within a few seconds.
5. 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 Power BI rejects a request, the message on the `/res` topic contains an `error` property with the HTTP status. A `404 Not Found` status usually means that the dataset ID or the resource key is wrong, and a `400 Bad Request` status usually means that the rows do not match the schema.

## Service Commissioning File Example

{% file src="/files/2KPyY9dIKhajfqfykoEJ" %}

{% code title="power-bi-example.yml" lineNumbers="true" expandable="true" %}

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

description: >
  Service commissioning file for pushing live shop floor data from
  Connectware into a Power BI streaming semantic model (Example)

metadata:
  name: Power BI Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  tenantId:
    description: Tenant ID from the push URL of the streaming semantic model
    type: string
    default: 00000000-0000-0000-0000-000000000000

  datasetId:
    description: Dataset ID from the push URL of the streaming semantic model
    type: string
    default: 00000000-0000-0000-0000-000000000000

  pushKey:
    description: Resource key from the push URL (the value of the key query parameter)
    type: string

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

resources:
  # Connection to the Power BI REST API
  powerBiConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: api.powerbi.com
        port: 443

  # Pushes rows into the streaming semantic model
  # The resource key in the URL authenticates the request
  powerBiRowsEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref powerBiConnection
      write:
        path: !sub '/beta/${tenantId}/datasets/${datasetId}/rows?key=${pushKey}'

  # Wraps every MQTT message into a rows array and adds a timestamp
  powerBiRowsMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/telemetry'
          publish:
            endpoint: !ref powerBiRowsEndpoint
          rules:
            - transform:
                expression: '{ "body": [ $merge([$, { "timestamp": $now() }]) ] }'
```

{% 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/analytics-monitoring-alerting/power-bi-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.
