> 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/plcs-industrial-controllers/connecting-a-schneider-modicon-m580-plc.md).

# Connecting a Schneider Modicon M580 PLC

This guide shows you how to read data from a Schneider Electric Modicon M580 PLC with the Connectware [Modbus/TCP connector](/2-4-2/connectors/shop-floor-connectors/modbus-tcp.md) and map it into an ISA-95 style MQTT topic hierarchy. Unlike a power meter with a fixed register map, the register layout of a PLC is defined by your automation project. This guide therefore teaches you how to derive the Modbus addresses from the located variables of your own EcoStruxure Control Expert project. In more detail, the following topics are covered:

* Checking the Modbus/TCP server of the M580 CPU
* Making PLC data available as located variables in EcoStruxure Control Expert
* Deriving Modbus register addresses from `%MW` addresses
* Decoding 16-bit and 32-bit values with the correct `dataType`
* Creating the [service commissioning file](/2-4-2/data-flows/service-commissioning-files.md)
* Mapping the values 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 Modicon M580 specifics. The closely related Modicon M340 exposes its `%MW` memory over Modbus/TCP in the same way, so the example works for both controllers. For a general introduction to the Modbus/TCP connector, including function codes and write operations, see [Connecting & Integrating a Modbus/TCP Server](/2-4-2/guides/machine-connectivity/gateways-generic-protocols/connecting-and-integrating-a-modbus-tcp-server.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.
* A Schneider Electric Modicon M580 (or M340) that is reachable over Ethernet from Connectware.
* The PLC application in EcoStruxure Control Expert (formerly Unity Pro), or at least a list of the located variables and their `%MW` addresses.
* 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)).

## Checking the Modbus/TCP Server of the CPU

The M580 CPU runs a Modbus/TCP server on port 502 on its embedded Ethernet ports. This is the same port that Control Expert uses to go online with the controller over Ethernet, so if Control Expert can connect to the CPU from your engineering workstation, the Modbus/TCP server is reachable on that network. Connectware acts as a Modbus/TCP client and polls the server; no communication function blocks are required in the PLC program for reading.

{% hint style="warning" %}
On M580 CPUs with the cybersecurity features of newer firmware versions, access control can restrict which clients reach the Modbus server. If the connection cannot be established although the network path is fine, open the **Security** tab of the CPU Ethernet configuration in Control Expert and check that the IP address of Connectware (or its subnet) is authorized to access the Modbus/TCP server on port 502. For details, see the [Modicon M580 Hardware Reference Manual](https://www.se.com/us/en/download/document/EIO0000001578/).
{% endhint %}

The default unit ID 1 of the Connectware Modbus connection works for an M580 that you address directly by its IP address. If the TCP connection is established but every request fails with an exception response, set the `unitId` connection property to 255, the value that the Modbus/TCP specification defines for a directly addressed server. If you reach the PLC through a Modbus gateway instead, set `unitId` to the address of the PLC behind the gateway.

## Making Data Available as Located Variables

The Modbus/TCP server of the M580 serves the `%MW` memory words of the controller. Only located variables are visible to Modbus clients: a variable must have a `%MW` address assigned in the **Address** column of the Control Expert data editor. Unlocated variables have no register address and cannot be read over Modbus.

The following located variables are used in this guide. They are project-specific examples — replace the names, types, and addresses with the located variables of your own project:

| Variable             | IEC data type | Located address | Words | Content                   |
| -------------------- | ------------- | --------------- | ----: | ------------------------- |
| `machineState`       | INT           | `%MW100`        |     1 | Machine state code        |
| `partsCounter`       | DINT          | `%MW102`        |     2 | Produced parts counter    |
| `coolantTemperature` | REAL          | `%MW104`        |     2 | Coolant temperature in °C |

A 32-bit value (DINT, UDINT, REAL) occupies two consecutive `%MW` words, so do not locate another variable on the second word. On the M340, 32-bit located variables must start at an even `%MW` address; following the same rule on the M580 keeps your projects portable.

## Deriving the Modbus Register Addresses

The M580 maps its memory words directly to Modbus holding registers, which you read with function code 3: the located variable at `%MW`*n* is read at Modbus address *n*. The mapping is zero-based, so `%MW0` corresponds to address 0 and `%MW100` to address 100. The `address` property of a Connectware Modbus endpoint expects exactly this raw protocol address.

{% hint style="info" %}
Modbus tools and device documentation that use the traditional register numbering show `%MW100` as holding register 40101 (or 400101 in six-digit notation), because that convention starts counting at 40001. If you copy addresses from such a source, subtract the 40001 offset to get the value for the `address` property.
{% endhint %}

For the example variables, this results in the following endpoint settings:

| Variable             | `fc` | `address` | `length` | `dataType`              |
| -------------------- | ---: | --------: | -------: | ----------------------- |
| `machineState`       |    3 |       100 |        1 | `int16BE`               |
| `partsCounter`       |    3 |       102 |        2 | `int32BE` (see below)   |
| `coolantTemperature` |    3 |       104 |        2 | `floatBEWS` (see below) |

### Decoding 16-Bit Values

A Modbus register is 16 bits long and is transmitted with the most significant byte first. An IEC `INT` located on a single `%MW` word therefore maps to `dataType: int16BE` with `length: 1`, and a `UINT` maps to `uint16BE`. With the `dataType` property set, Connectware decodes the register and publishes a plain JSON number. For all available data types, see [Modbus/TCP Endpoint Properties](/2-4-2/connectors/shop-floor-connectors/modbus-tcp/modbusendpoint.md).

### 32-Bit Values and Word Order

A 32-bit value spans two registers, and the order of the two words is the most common source of implausible Modbus values. Control Expert stores 32-bit values with the least significant word at the lower address: a REAL located at `%MW104` keeps its low word in `%MW104` and its high word in `%MW105`, the same layout as the `%MD` double words that overlap two `%MW` words. When Connectware reads the two registers, the low word arrives first, an order that many Modbus tools call word-swapped or Modicon order. Connectware decodes both orders:

* `dataType: floatBEWS` — IEEE 754 float, big-endian bytes with word swap. This matches the default layout of a REAL located on `%MW` words.
* `dataType: floatBE` — IEEE 754 float with the most significant word first. Use this if your setup delivers the standard Modbus word order, for example because the PLC application arranges the words itself or a gateway swaps them.

Because gateways and application code can change the word order, verify it against a known value: write a distinctive test value such as `123.456` into the located REAL variable from a Control Expert animation table and check which `dataType` reproduces it in Connectware. The wrong word order does not fail, it produces a valid but implausible number, for example an extremely small or astronomically large value.

{% hint style="warning" %}
For 32-bit integers, Connectware provides `int32BE` and `uint32BE` (most significant word first) but no word-swap variant. Verify the counter against the value in Control Expert. If the words arrive swapped — small counter values then appear as large numbers — exchange the two words in the PLC application before you expose them to Modbus.
{% endhint %}

## 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 located variables from a Schneider
  Electric Modicon M580 PLC over Modbus/TCP and maps them into an ISA-95
  style MQTT topic hierarchy (Example)

metadata:
  name: Schneider Modicon M580 Example
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0
```

{% endcode %}

### Parameters and Definitions

We define the network address of the PLC as parameters, so you can set them when you install the service. The default Modbus/TCP port is 502.

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:
  m580Host:
    description: Hostname or IP address of the Modicon M580
    type: string
    default: 192.168.1.100

  m580Port:
    description: Modbus/TCP port of the Modicon M580
    type: integer
    default: 502

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

{% endcode %}

### Cybus::Connection

The connection resource establishes the Modbus/TCP connection to the CPU. The `connectionStrategy` object controls how Connectware retries failed connection attempts with increasing delays. For all connection properties, including `unitId`, see [Modbus/TCP Connection Properties](/2-4-2/connectors/shop-floor-connectors/modbus-tcp/modbusconnection.md).

{% code lineNumbers="true" %}

```yaml
resources:
  m580Connection:
    type: Cybus::Connection
    properties:
      protocol: Modbus
      targetState: connected
      connection:
        host: !ref m580Host
        port: !ref m580Port
        connectionStrategy:
          initialDelay: 1000
          maxDelay: 30000
          incrementFactor: 2
```

{% endcode %}

### Cybus::Endpoint

Each endpoint polls one located variable. The `address` value is the `%MW` number, and `length` is the number of words the IEC data type occupies. The machine state is polled every second, the counter and the temperature every two seconds.

{% code lineNumbers="true" %}

```yaml
machineState:
  type: Cybus::Endpoint
  properties:
    protocol: Modbus
    connection: !ref m580Connection
    subscribe:
      fc: 3
      address: 100
      length: 1
      dataType: int16BE
      interval: 1000

partsCounter:
  type: Cybus::Endpoint
  properties:
    protocol: Modbus
    connection: !ref m580Connection
    subscribe:
      fc: 3
      address: 102
      length: 2
      dataType: int32BE
      interval: 2000

coolantTemperature:
  type: Cybus::Endpoint
  properties:
    protocol: Modbus
    connection: !ref m580Connection
    subscribe:
      fc: 3
      address: 104
      length: 2
      dataType: floatBEWS
      interval: 2000
```

{% endcode %}

{% hint style="info" %}
If you poll many endpoints, enable [batch read processing](/2-4-2/connectors/shop-floor-connectors/modbus-tcp.md#batch-read-processing) on the connection. Connectware then combines reads of neighboring registers, such as the example variables at addresses 100 to 105, into a single request.
{% endhint %}

### Cybus::Mapping

The mapping publishes each endpoint on a topic of the ISA-95 hierarchy.

{% code lineNumbers="true" %}

```yaml
mapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref machineState
        publish:
          topic: !sub '${MQTT_TOPIC_PREFIX}/state'
      - subscribe:
          endpoint: !ref partsCounter
        publish:
          topic: !sub '${MQTT_TOPIC_PREFIX}/counter/parts'
      - subscribe:
          endpoint: !ref coolantTemperature
        publish:
          topic: !sub '${MQTT_TOPIC_PREFIX}/temperature/coolant'
```

{% endcode %}

With this mapping, the parts counter of the line is published on the topic `enterprise/hamburg/assembly/line-1/counter/parts`, and every other value follows the same pattern.

## 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 Modbus/TCP connection to the M580 and polls the configured registers.

## 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`, where the value is the decoded variable:

{% code lineNumbers="true" %}

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

{% endcode %}

A few plausibility checks for the first readings:

* Compare each value with an animation table in Control Expert that shows the same located variables. The values must match.
* The parts counter only increases, and it increases in steps of one.
* Write a test value such as `123.456` into the REAL variable from the animation table. If Connectware shows a different, implausible number, switch the `dataType` between `floatBEWS` and `floatBE`.

If the connection does not reach the **Connected** state, verify that port 502 is reachable from Connectware and that the access control settings of the CPU authorize the Connectware IP address. If values arrive but look implausible, the register decoding does not match: check that `address`, `length`, and `dataType` correspond to the located variable, that the address is not shifted by the 40001 register numbering offset, and that the word order of 32-bit values is correct.

## Service Commissioning File Example

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

{% code title="modicon-m580-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# Connecting a Schneider Modicon M580 PLC (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file that reads located variables from a Schneider
  Electric Modicon M580 PLC over Modbus/TCP and maps them into an ISA-95
  style MQTT topic hierarchy (Example)

metadata:
  name: Schneider Modicon M580 Example
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  m580Host:
    description: Hostname or IP address of the Modicon M580
    type: string
    default: 192.168.1.100

  m580Port:
    description: Modbus/TCP port of the Modicon M580
    type: integer
    default: 502

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

resources:
  # Connection to the Modbus/TCP server of the M580 CPU
  m580Connection:
    type: Cybus::Connection
    properties:
      protocol: Modbus
      targetState: connected
      connection:
        host: !ref m580Host
        port: !ref m580Port
        connectionStrategy:
          initialDelay: 1000
          maxDelay: 30000
          incrementFactor: 2

  # The %MW addresses below are project-specific examples. Replace them with
  # the located variables of your own Control Expert project. The located
  # variable %MWn is read at Modbus address n with function code 3.

  # INT at %MW100: one register, decoded as int16BE.
  machineState:
    type: Cybus::Endpoint
    properties:
      protocol: Modbus
      connection: !ref m580Connection
      subscribe:
        fc: 3
        address: 100
        length: 1
        dataType: int16BE
        interval: 1000

  # DINT at %MW102 and %MW103: two registers. int32BE expects the most
  # significant word at the lower address. Verify against a known value;
  # if the words arrive swapped, exchange them in the PLC application.
  partsCounter:
    type: Cybus::Endpoint
    properties:
      protocol: Modbus
      connection: !ref m580Connection
      subscribe:
        fc: 3
        address: 102
        length: 2
        dataType: int32BE
        interval: 2000

  # REAL at %MW104 and %MW105: two registers. floatBEWS matches the default
  # word order of located variables in Control Expert (least significant
  # word first). If values look implausible, use floatBE instead.
  coolantTemperature:
    type: Cybus::Endpoint
    properties:
      protocol: Modbus
      connection: !ref m580Connection
      subscribe:
        fc: 3
        address: 104
        length: 2
        dataType: floatBEWS
        interval: 2000

  mapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref machineState
          publish:
            topic: !sub '${MQTT_TOPIC_PREFIX}/state'
        - subscribe:
            endpoint: !ref partsCounter
          publish:
            topic: !sub '${MQTT_TOPIC_PREFIX}/counter/parts'
        - subscribe:
            endpoint: !ref coolantTemperature
          publish:
            topic: !sub '${MQTT_TOPIC_PREFIX}/temperature/coolant'
```

{% 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/plcs-industrial-controllers/connecting-a-schneider-modicon-m580-plc.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.
