AWS IoT Greengrass Modbus Adapter Testing

AWS IoT Greengrass doesn't talk Modbus natively — it talks Modbus through the AWS Labs Modbus-TCP and Modbus-RTU protocol adapter components, which poll devices and hand data off over local IPC to whatever component you write to forward it onward. That extra hop, and the fact that this is a community/labs component rather than a fully managed service, means it's worth understanding exactly what it does and doesn't do before you deploy it to a real edge device. This guide covers the adapter's configuration, IPC interface, how data actually reaches AWS IoT Core, and how to test the whole chain against a simulator first.

What the Greengrass Modbus Adapter Actually Is

AWS IoT Greengrass v2 doesn't ship first-party, GA support for Modbus as a protocol. Instead, AWS Labs — AWS's open-source/community engineering org, not the core managed-service team — publishes the aws-greengrass-labs-modbus-tcp-protocol-adapter component (and a matching Modbus-RTU adapter for serial devices) on GitHub under an Apache-2.0 license. You deploy it as a normal Greengrass component: either grab a prebuilt artifact or build it yourself with Gradle, then publish and deploy it through the standard Greengrass component/deployment workflow, the same way you'd deploy any other component to a fleet of core devices.

Because it's a labs component rather than a fully managed AWS service, treat it as a well-documented reference implementation you're responsible for testing, deploying, and — if your use case needs something the default doesn't cover — extending yourself, not an opaque black box with the same support SLA as core Greengrass.

Architecture: Adapter, IPC, and the Cloud

The critical architectural detail to get right before building on this: the Modbus adapter component only talks to other components on the same Greengrass core, over local IPC pub/sub. It has no direct connection to AWS IoT Core or the cloud.

Modbus Device (PLC/meter)  →  Modbus-TCP Adapter Component  →  Local IPC (pub/sub)  →  Your Component  →  AWS IoT Core
[TCP, port 502]                  [Greengrass core device]           [modbus/request|response/{device}]  [subscribes, forwards]   [MQTT / cloud]

Getting Modbus data into the cloud is a two-component job by design: the adapter handles Modbus polling and IPC exposure, and a second component — one you write, or a suitable existing one — subscribes to that IPC data and republishes it northbound. This separation is intentional and matches Greengrass's general component model: single-purpose components composed together, not one monolithic Modbus-to-cloud binary.

Configuring the Modbus-TCP Adapter Component

The component's recipe configuration defines one or more Modbus TCP devices under a Modbus → Endpoints → Devices structure. Each device entry needs:

FieldDescriptionDefault
HostIP address or hostname of the Modbus TCP server (device or gateway)— (required)
PortModbus TCP port502
TimeoutCommunication timeout in seconds5
Unit IDSlave/device address on the Modbus connection0
NameArbitrary device name used as the last segment of the IPC topic — must be unique per configured device— (required)
// Example recipe configuration snippet — one configured device
{
  "Modbus": {
    "Endpoints": {
      "Devices": [
        {
          "Name": "line1-plc",
          "Host": "192.168.1.50",
          "Port": 502,
          "UnitId": 1,
          "Timeout": 5
        }
      ]
    }
  }
}

Requesting Reads and Writes Over IPC

Other components request Modbus operations by publishing a JSON request to a per-device local IPC topic and subscribing to the matching response topic:

Request topic:  modbus/request/line1-plc
Response topic: modbus/response/line1-plc

// Example request payload
{
  "id": "req-001",
  "type": "ReadHoldingRegisters",
  "address": 0,
  "quantity": 10
}

// Example response payload
{
  "id": "req-001",
  "success": true,
  "data": [1500, 220, 0, 0, 1, ...]
}

The request is correlated to its response by the id field, which matters because IPC pub/sub is asynchronous — your component needs to match responses back to the request that triggered them rather than assuming strict ordering. This is Greengrass local IPC, not MQTT: it never leaves the core device, and it uses the Greengrass IPC SDK (available for Python, Java, and other supported languages) rather than an MQTT client library.

Getting Data to AWS IoT Core

Since the adapter itself is IPC-only, forwarding Modbus data to the cloud means writing (or deploying) a bridging component that:

  1. Subscribes to modbus/response/{device} for each configured device
  2. Optionally applies scaling, byte-order combination for 32-bit values, or filtering
  3. Publishes the result northbound — either directly to AWS IoT Core using the IoT Core MQTT IPC service (simplest, good for a reliable connection), or through Stream Manager if the site has an unreliable uplink and you need buffering, batching, and store-and-forward before the data lands in S3, Kinesis, or IoT Analytics

Which of the two northbound options to use is a real design decision, not a default to skip past: IoT Core MQTT IPC is simpler and gives you live data in near-real-time, but has no built-in buffering if connectivity drops — Stream Manager exists specifically to handle that gap for remote or cellular sites where dropped connectivity is the normal case, not the exception.

IPC Access Control: A Common Deployment Gotcha

Greengrass IPC pub/sub is permission-gated, not open by default — this is the single most common reason a working local test suddenly fails after deployment. Both the adapter component and any component that wants to talk to it over modbus/request/* and modbus/response/* need an explicit accessControl policy in their recipe, under the aws.greengrass.ipc.pubsub service identifier, granting the aws.greengrass#PublishToTopic and aws.greengrass#SubscribeToTopic operations for the relevant topic resources:

// Recipe snippet — granting a bridging component pub/sub access to one device's topics
"ComponentConfiguration": {
  "DefaultConfiguration": {
    "accessControl": {
      "aws.greengrass.ipc.pubsub": {
        "com.example.ModbusBridge:pubsub:1": {
          "policyDescription": "Allow access to line1-plc Modbus topics",
          "operations": [
            "aws.greengrass#PublishToTopic",
            "aws.greengrass#SubscribeToTopic"
          ],
          "resources": [
            "modbus/request/line1-plc",
            "modbus/response/line1-plc"
          ]
        }
      }
    }
  }
}

Miss this, and the symptom isn't a clean error — it's usually a silent timeout, because the subscribing component simply never receives anything on a topic it wasn't authorized to see. When a request/response flow that worked in a quick manual test stops working after a full deployment, check the access control policy on both sides (the adapter's own recipe and your bridging component's recipe) before assuming the adapter itself is broken.

Adapter vs. Node-RED vs. a Custom Python Bridge

The Greengrass Modbus adapter, a Node-RED Modbus flow, and a hand-rolled Python bridge (e.g. using pymodbus) all accomplish the same core task — polling Modbus registers and forwarding the data — but differ in where they fit operationally:

ApproachFits best when
Greengrass Modbus adapterAlready standardized on Greengrass for fleet deployment/monitoring across many edge devices; want Modbus polling managed the same way as every other component
Node-RED flowWant fast, visual flow-based development and easy protocol translation (MQTT, HTTP, database) without necessarily being tied to Greengrass's deployment model
Custom Python/pymodbus bridgeNeed tight control over polling logic, error handling, or integration with an existing Python codebase not built around either Greengrass components or Node-RED flows

None of these is universally "correct" — the deciding factor is usually what deployment and fleet-management tooling you're already committed to, not which one is technically superior at the Modbus layer itself.

Testing Against a Simulator Before Real Hardware

Point the adapter's device configuration at a Modbus TCP slave simulator instead of a real PLC while developing and testing:

Greengrass Core (Modbus-TCP Adapter)  →  TCP 502  →  Modbus Slave Simulator
[Deployed component, dev/test core device]              [ModbusSimulator on a bench machine]

Configure ModbusSimulator to run as a Modbus TCP slave on the IP:port your adapter's device entry points to, and preload registers with distinctive test values. Then, using the AWS IoT Greengrass CLI's local pub/sub commands (or a small test component you write for this purpose), publish a request to modbus/request/{device name} and confirm the response on modbus/response/{device name} matches what the simulator has:

  • Configuration validation: confirm the adapter connects, and that the unit ID and timeout you configured actually match the simulator's settings
  • Read verification: request several function types (holding registers, coils) and confirm the returned data matches the simulator's preloaded values
  • Write verification: if your workflow needs writes, confirm a write request lands correctly by reading the register back afterward
  • Failure handling: stop the simulator and confirm the adapter's response indicates a clear failure rather than hanging or crashing the component, then restart it and confirm recovery
  • End-to-end path: once the adapter itself checks out, bring your cloud-forwarding component online too and confirm data changed in the simulator actually appears in AWS IoT Core or wherever it's ultimately headed

Doing this on a bench, before the Greengrass core is deployed to a real edge site, catches configuration and IPC-wiring mistakes while they cost you a five-minute redeploy — not a truck roll to a site with a live PLC you can't casually experiment against. It's also the cheapest place to catch access control policy mistakes: if a request published to modbus/request/{device} gets no response at all rather than an explicit error, check both components' accessControl blocks before assuming the adapter itself, or the simulator, is at fault.

Once the adapter and IPC wiring check out against the simulator, repeat the same test sequence with your northbound bridging component in the loop, watching AWS IoT Core's MQTT test client (or your Stream Manager destination) to confirm a value change in the simulator's registers actually completes the full round trip end to end. Treat that full-path test, not just the adapter-to-IPC step alone, as the real acceptance criteria before scheduling a deployment to a site with live equipment.

Download ModbusSimulator to Test Your Greengrass Modbus Adapter →

Frequently Asked Questions

How does AWS IoT Greengrass connect to Modbus devices?

Through the AWS Labs Modbus-TCP and Modbus-RTU protocol adapter components — Greengrass v2 components, not a first-party GA service — which poll devices and expose data to other components over local IPC pub/sub, not directly to AWS IoT Core.

Is the Modbus-TCP protocol adapter an official AWS component?

It's an open-source, Apache-2.0 AWS Labs project on GitHub — a reference implementation you deploy and test yourself, not a fully managed GA service with the same support commitments as core Greengrass.

How do I configure the Modbus-TCP protocol adapter component?

Under Modbus/Endpoints/Devices in the component recipe: host, port (502 default), timeout (5s default), unit ID (0 default), and a unique device name used in the IPC topic.

How does a component request a Modbus read/write through the adapter?

By publishing a JSON request to modbus/request/{device name} and subscribing to modbus/response/{device name}, correlated by a request ID — this is Greengrass local IPC pub/sub, not MQTT, and it stays on the core device.

How does Modbus data actually reach AWS IoT Core or the cloud?

Via a second component you write that subscribes to the adapter's response topic and republishes northbound, using IoT Core MQTT IPC directly or Stream Manager for buffered store-and-forward through unreliable connectivity.

What's the difference between this adapter and a generic MQTT bridge or Node-RED?

The adapter runs within Greengrass's component deployment/lifecycle model, which matters mainly if you're already standardized on Greengrass fleet management — the core Modbus polling task itself is equivalent to what Node-RED or a Python bridge accomplishes.

How do I test the Modbus-TCP adapter before connecting it to a real PLC?

Point its device configuration at a Modbus TCP slave simulator, deploy to a dev/test Greengrass core, and use the Greengrass CLI's local pub/sub commands to verify request/response behavior against known simulator register values.

Does the Modbus-RTU adapter component work the same way?

Yes — same IPC request/response concept and topic pattern, configured with serial parameters (baud rate, parity, COM/serial path) instead of a TCP host and port.

Test Your Greengrass Modbus Pipeline Without Real Hardware

ModbusSimulator acts as a fully configurable Modbus TCP or RTU slave for validating the AWS IoT Greengrass Modbus adapter's configuration, IPC wiring, and error handling before it ever touches a PLC. Free tier available.

Download Free tier → Learn More