> 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/machine-connectivity/robots-sensors-shop-floor-devices/connecting-an-ifm-io-link-master.md).

# Connecting an ifm IO-Link Master

This guide shows you how to read sensor data from an ifm IO-Link master with an IoT interface (AL13xx family, for example the AL1350) using the Connectware [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md) and map it into an ISA-95 style MQTT topic hierarchy. The ifm IoT Core exposes process data, device information, and diagnostics of the IO-Link master and its connected sensors as a JSON-over-HTTP interface, so no fieldbus configuration is required. In more detail, the following topics are covered:

* Understanding the ifm IoT Core addressing and its `getdata` service
* Polling the process data of the IO-Link ports with `subscribe` endpoints
* Decoding the hexadecimal process data with a transform rule
* Reading the application tag of the IO-Link master on demand with a `read` endpoint
* Creating the [service commissioning file](/2-4-2/data-flows/service-commissioning-files.md)
* Mapping the data into an ISA-95 style MQTT topic hierarchy
* Verifying data in the [Data Explorer](/2-4-2/monitoring/data-explorer.md)

This guide focuses on the ifm IoT Core specifics. For a general introduction to the HTTP/REST connector, including write operations and OAuth 2.0 authentication, see [HTTP/REST](/2-4-2/connectors/enterprise-connectors/http-rest.md).

A complete example file is available at the end of this guide.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* An ifm IO-Link master with IoT interface (AL13xx family) whose IoT port is reachable over Ethernet from Connectware. This guide uses the four-port AL1350; other masters of the family expose the same IoT Core interface.
* At least one IO-Link sensor connected to a port of the IO-Link master.
* 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)).

## Understanding the ifm IoT Core Interface

The IO-Link master stores a device description as a structured JSON object. All parameters, process data, diagnostic data, and device information are data points in this tree, and you access them by calling services such as `getdata` (read a value) or `setdata` (write a value) on a data point. The complete tree of your device is returned by the `gettree` service, and the operating instructions of your IO-Link master document every data point. The current operating instructions are linked on the product page of your device, for example on the [ifm AL1350 product page](https://www.ifm.com/us/en/product/AL1350).

{% hint style="info" %}
To discover all data points that your device offers, open `http://192.168.1.100/gettree` (with the IP address of your device) in a browser. The IoT Core returns the complete device description as a JSON object.
{% endhint %}

The following data points are used in this guide:

| Data point                                       | Description                                        | Access |
| ------------------------------------------------ | -------------------------------------------------- | ------ |
| `/devicetag/applicationtag`                      | Name (application tag) of the IO-Link master       | rw     |
| `/iolinkmaster/port[n]/iolinkdevice/pdin`        | Process input data of the IO-Link device on port n | r      |
| `/iolinkmaster/port[n]/iolinkdevice/productname` | Product name of the IO-Link device on port n       | r      |

The port index `n` counts from 1, so the data points of the physical port X01 are under `port[1]`.

### Reading Data Points with HTTP Requests

The IoT Core accepts two equivalent request forms:

* **GET requests** with the data point and service in the URL path: `http://192.168.1.100/iolinkmaster/port[1]/iolinkdevice/pdin/getdata`
* **POST requests** to the device address with the command as a JSON body: `{"code": "request", "cid": 4711, "adr": "/iolinkmaster/port[1]/iolinkdevice/pdin/getdata"}`

Both forms return the same JSON object:

{% code lineNumbers="true" %}

```json
{
  "cid": 4711,
  "data": { "value": "03C9" },
  "code": 200
}
```

{% endcode %}

The `cid` is a correlation ID for matching requests and responses, `data.value` carries the value of the data point, and `code` is the IoT Core diagnostic code, where `200` means OK. Since the GET form addresses each data point with its own URL path, it maps directly onto the `subscribe` operation of the HTTP/REST connector, which polls a path with GET requests at a regular interval. This guide therefore uses the GET form throughout.

### Authentication

By default, the IoT Core accepts requests without authentication on HTTP port 80. Newer firmware versions offer a security mode that restricts access with a password and the fixed username `administrator`. If security mode is active on your device, add Basic Auth credentials to the connection with the `auth` property and switch the `scheme` property to `https`:

{% code lineNumbers="true" %}

```yaml
connection:
  scheme: https
  host: 192.168.1.100
  port: 443
  trustAllCertificates: true # The IO-Link master uses a self-signed certificate
  auth:
    username: administrator
    password: ${IFM_PASSWORD}
```

{% endcode %}

* Replace `${IFM_PASSWORD}` with the password configured on the IO-Link master.

For details on the security mode of your device, see the operating instructions of your IO-Link master.

## Decoding the IO-Link Process Data

The `pdin` data point returns the process input data as a hexadecimal string, for example `"03C9"`. How this string is structured depends entirely on the connected sensor: the IO Device Description (IODD) of the sensor defines which bits carry which measurement. You can download the IODD of your sensor from [IODDfinder](https://ioddfinder.io-link.com).

As a worked example, the operating instructions of the AL1350 describe the ifm TN2531 temperature sensor. Its process value `"03C9"` decodes as follows:

* `0x03C9` is `0b1111001001` in binary.
* Bits 2 to 15 carry the temperature value: `0b11110010` equals 242.
* The resolution is 0.1 °C, so the current temperature is 24.2 °C.

Dropping the two lowest bits is a division by four, so a [transform rule](/2-4-2/data-flows/rule-engine/data-processing-rules.md#transform) can decode the value with integer arithmetic:

{% code lineNumbers="true" %}

```yaml
rules:
  - transform:
      expression: |
        {
          "timestamp": timestamp,
          "value": $floor($number("0x" & value.data.value) / 4) / 10
        }
```

{% endcode %}

This expression covers positive temperature values. For sensors with signed values, scaling factors, or multiple values packed into one process data frame, adapt the expression to the IODD of your sensor. The [Rule Sandbox](/2-4-2/data-flows/rule-engine/rule-sandbox.md) is a convenient place to test the expression with real payloads before deploying it.

## Writing the Service Commissioning File

The service commissioning file contains all connection and mapping details. Do not worry about copying the snippets together into one file, the complete example file is available at the end of this guide.

### Description and Metadata

These sections contain general information about the service commissioning file. Only the metadata name is required.

{% code lineNumbers="true" %}

```yaml
description: >
  Service commissioning file that reads IO-Link process data from an ifm
  IO-Link master through the ifm IoT Core JSON-over-HTTP interface and maps
  it into an ISA-95 style MQTT topic hierarchy (Example)

metadata:
  name: ifm IO-Link Master Example
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0
```

{% endcode %}

### Parameters and Definitions

We define the network address of the IO-Link master as parameters, so you can set them when you install the service. The IoT Core listens on the standard HTTP port 80.

The MQTT topics in this guide follow an ISA-95 style equipment hierarchy (`<enterprise>/<site>/<area>/<line>`). We define the prefix once in the `definitions` section and reuse it in every mapping with `!sub`.

{% code lineNumbers="true" %}

```yaml
parameters:
  ifmHost:
    description: Hostname or IP address of the IoT port of the ifm IO-Link master
    type: string
    default: 192.168.1.100

  ifmPort:
    description: HTTP port of the ifm IoT Core interface
    type: integer
    default: 80

definitions:
  MQTT_TOPIC_PREFIX: enterprise/hamburg/assembly/line-1
```

{% endcode %}

### Cybus::Connection

The connection resource establishes the HTTP connection to the IoT Core. The `connectionStrategy` object controls how Connectware retries failed connection attempts with increasing delays. For all connection properties, including authentication, see [HTTP Connection Properties](/2-4-2/connectors/enterprise-connectors/http-rest/httpconnection.md).

By default, the HTTP/REST connector probes the health of the server on the root path. The `probeMethod` and `probePath` properties point the probing at an IoT Core address that always answers, so the connection state reflects the availability of the IoT Core interface itself.

{% code lineNumbers="true" %}

```yaml
resources:
  ifmConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      targetState: connected
      connection:
        scheme: http
        host: !ref ifmHost
        port: !ref ifmPort
        probeMethod: GET
        probePath: /devicetag/applicationtag/getdata
        connectionStrategy:
          initialDelay: 1000
          maxDelay: 30000
          incrementFactor: 2
```

{% endcode %}

### Cybus::Endpoint

Each `subscribe` endpoint polls one IoT Core URL with GET requests at the configured interval. The `path` is the data point followed by the `getdata` service. Without any rules, the endpoint publishes the complete IoT Core return object, so the message on the broker looks like this:

{% code lineNumbers="true" %}

```json
{
  "timestamp": 1784194200354,
  "value": {
    "cid": -1,
    "data": { "value": "03C9" },
    "code": 200
  }
}
```

{% endcode %}

A transform rule on the endpoint unwraps the nested structure. The first endpoint polls the process data of port X01 and decodes the TN2531 temperature value as explained in [Decoding the IO-Link Process Data](#decoding-the-io-link-process-data). The second endpoint polls port X02 and publishes the raw hexadecimal string, which is the right starting point for any sensor whose IODD you have not modeled in a transform rule yet.

{% code lineNumbers="true" %}

```yaml
temperaturePort1:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref ifmConnection
    subscribe:
      path: /iolinkmaster/port[1]/iolinkdevice/pdin/getdata
      interval: 1000
    rules:
      - transform:
          expression: |
            {
              "timestamp": timestamp,
              "value": $floor($number("0x" & value.data.value) / 4) / 10
            }

rawProcessDataPort2:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref ifmConnection
    subscribe:
      path: /iolinkmaster/port[2]/iolinkdevice/pdin/getdata
      interval: 1000
    rules:
      - transform:
          expression: |
            {
              "timestamp": timestamp,
              "value": value.data.value
            }
```

{% endcode %}

Device information changes rarely, so polling it continuously would be wasteful. A `read` endpoint requests its path on demand instead: whenever a message arrives on the `/req` topic of the endpoint, Connectware sends one GET request and publishes the response on the `/res` topic (see [Operation Results](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md#operation-results)). The following endpoint reads the application tag of the IO-Link master. The explicit `topic` property gives the endpoint a readable topic below the service root.

{% code lineNumbers="true" %}

```yaml
applicationTag:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref ifmConnection
    topic: device-info/application-tag
    read:
      path: /devicetag/applicationtag/getdata
```

{% endcode %}

The same pattern works for any other informational data point, for example `/iolinkmaster/port[1]/iolinkdevice/productname/getdata` to read the product name of the sensor connected to port X01.

### Cybus::Mapping

The mapping publishes each polled endpoint on a topic of the ISA-95 hierarchy. The `read` endpoint needs no mapping because it is addressed directly through its `/req` and `/res` topics.

{% code lineNumbers="true" %}

```yaml
mapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref temperaturePort1
        publish:
          topic: !sub '${MQTT_TOPIC_PREFIX}/port-1/temperature'
      - subscribe:
          endpoint: !ref rawProcessDataPort2
        publish:
          topic: !sub '${MQTT_TOPIC_PREFIX}/port-2/process-data-raw'
```

{% endcode %}

With this mapping, the temperature measured by the sensor on port X01 is published on the topic `enterprise/hamburg/assembly/line-1/port-1/temperature`.

## Installing the Service Commissioning File

1. Install the service commissioning file. See [Installing Services](/2-4-2/data-flows/services/managing/installing.md).
2. Enable the service. See [Enabling Services](/2-4-2/data-flows/services/managing/enabling.md).

**Result:** The service is enabled. Connectware establishes the HTTP connection to the IO-Link master and polls the configured IoT Core URLs.

## Verifying the Data

Open the [Data Explorer](/2-4-2/monitoring/data-explorer.md) and subscribe to `enterprise/hamburg/assembly/line-1/#`. Each topic carries a JSON object with the keys `timestamp` and `value`:

{% code lineNumbers="true" %}

```json
{
  "timestamp": 1784194200354,
  "value": 24.2
}
```

{% endcode %}

A few plausibility checks for the first readings:

* The temperature on `port-1/temperature` is plausible for the environment of the sensor.
* The raw value on `port-2/process-data-raw` is a hexadecimal string that changes when the state at the sensor changes.

If the connection does not reach the **Connected** state, open `http://192.168.1.100/devicetag/applicationtag/getdata` (with the IP address of your device) in a browser. If no JSON object is returned, verify the network path to the IoT port of the IO-Link master and check whether security mode requires credentials. If the value on a topic is `null` or missing, no IO-Link device is connected on that port, or the IoT Core returned a diagnostic code other than `200`: remove the transform rule temporarily to inspect the complete return object, or open the polled URL in a browser.

### Reading the Application Tag on Demand

The `read` endpoint is triggered over MQTT. Using an MQTT client such as `mosquitto_pub` (see [Connecting an MQTT Client to Publish and Subscribe Data](/2-4-2/guides/machine-connectivity/gateways-generic-protocols/connecting-an-mqtt-client-to-publish-and-subscribe-data.md)), publish an empty JSON object to the `/req` topic of the endpoint:

{% code lineNumbers="true" %}

```bash
mosquitto_pub -h localhost -p 1883 -u ${MQTT_USER} -P ${MQTT_PASSWORD} \
  -t 'services/${SERVICE_ID}/device-info/application-tag/req' -m '{}'
```

{% endcode %}

* Replace `${MQTT_USER}` and `${MQTT_PASSWORD}` with the credentials of an MQTT user that has permissions on the service topics.
* Replace `${SERVICE_ID}` with the ServiceID of the installed service.

Connectware sends one GET request to the IoT Core and publishes the response on `services/${SERVICE_ID}/device-info/application-tag/res`, where the `result` property contains the IoT Core return object with the application tag as `data.value`.

## Service Commissioning File Example

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

{% code title="ifm-io-link-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# Connecting an ifm IO-Link Master (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file that reads IO-Link process data from an ifm
  IO-Link master through the ifm IoT Core JSON-over-HTTP interface and maps
  it into an ISA-95 style MQTT topic hierarchy (Example)

metadata:
  name: ifm IO-Link Master Example
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  ifmHost:
    description: Hostname or IP address of the IoT port of the ifm IO-Link master
    type: string
    default: 192.168.1.100

  ifmPort:
    description: HTTP port of the ifm IoT Core interface
    type: integer
    default: 80

definitions:
  # ISA-95 style topic prefix: <enterprise>/<site>/<area>/<line>
  MQTT_TOPIC_PREFIX: enterprise/hamburg/assembly/line-1

resources:
  # Connection to the ifm IoT Core (JSON over HTTP)
  ifmConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      targetState: connected
      connection:
        scheme: http
        host: !ref ifmHost
        port: !ref ifmPort
        # Probe an IoT Core address that always answers, so that the
        # connection state reflects the availability of the interface.
        probeMethod: GET
        probePath: /devicetag/applicationtag/getdata
        connectionStrategy:
          initialDelay: 1000
          maxDelay: 30000
          incrementFactor: 2

  # Process input data (pdin) of the IO-Link device on port X01.
  # In this example, an ifm TN2531 temperature sensor is connected to X01.
  # The transform rule decodes the hexadecimal string according to the
  # IODD of the sensor: bits 2 to 15 carry the temperature value with a
  # resolution of 0.1 degrees Celsius.
  temperaturePort1:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref ifmConnection
      subscribe:
        path: /iolinkmaster/port[1]/iolinkdevice/pdin/getdata
        interval: 1000
      rules:
        - transform:
            expression: |
              {
                "timestamp": timestamp,
                "value": $floor($number("0x" & value.data.value) / 4) / 10
              }

  # Process input data (pdin) of the IO-Link device on port X02, published
  # as the raw hexadecimal string. Decode it with a transform rule according
  # to the IODD of the connected sensor.
  rawProcessDataPort2:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref ifmConnection
      subscribe:
        path: /iolinkmaster/port[2]/iolinkdevice/pdin/getdata
        interval: 1000
      rules:
        - transform:
            expression: |
              {
                "timestamp": timestamp,
                "value": value.data.value
              }

  # Application tag (name) of the IO-Link master, read on demand by
  # publishing an empty JSON object to the /req topic of this endpoint.
  applicationTag:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref ifmConnection
      topic: device-info/application-tag
      read:
        path: /devicetag/applicationtag/getdata

  mapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref temperaturePort1
          publish:
            topic: !sub '${MQTT_TOPIC_PREFIX}/port-1/temperature'
        - subscribe:
            endpoint: !ref rawProcessDataPort2
          publish:
            topic: !sub '${MQTT_TOPIC_PREFIX}/port-2/process-data-raw'
```

{% 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/machine-connectivity/robots-sensors-shop-floor-devices/connecting-an-ifm-io-link-master.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.
