AWS IoT Greengrass Version 1 entered the extended life phase on June 30, 2023. For more information, see the AWS IoT Greengrass V1 maintenance policy. After this date, AWS IoT Greengrass V1 won't release updates that provide features, enhancements, bug fixes, or security patches. Devices that run on AWS IoT Greengrass V1 won't be disrupted and will continue to operate and to connect to the cloud. We strongly recommend that you migrate to AWS IoT Greengrass Version 2, which adds significant new features and support for additional platforms.
Modbus-RTU Protocol Adapter connector
The Modbus-RTU Protocol Adapter connector polls information from Modbus RTU devices that are in the AWS IoT Greengrass group.
This connector receives parameters for a Modbus RTU request from a user-defined Lambda function. It sends the corresponding request, and then publishes the response from the target device as an MQTT message.
This connector has the following versions.
Version |
ARN |
---|---|
3 |
|
2 |
|
1 |
|
For information about version changes, see the Changelog.
Requirements
This connector has the following requirements:
Connector Parameters
This connector supports the following parameters:
ModbusSerialPort-ResourceId
-
The ID of the local device resource that represents the physical Modbus serial port.
Note
This connector is granted read-write access to the resource.
Display name in the AWS IoT console: Modbus serial port resource
Required:
true
Type:
string
Valid pattern:
.+
ModbusSerialPort
-
The absolute path to the physical Modbus serial port on the device. This is the source path that's specified for the Modbus local device resource.
Display name in the AWS IoT console: Source path of Modbus serial port resource
Required:
true
Type:
string
Valid pattern:
.+
Create Connector Example (AWS CLI)
The following CLI command creates a ConnectorDefinition
with an initial version
that contains the Modbus-RTU Protocol Adapter connector.
aws greengrass create-connector-definition --name MyGreengrassConnectors --initial-version '{ "Connectors": [ { "Id": "MyModbusRTUProtocolAdapterConnector", "ConnectorArn": "arn:aws:greengrass:
region
::/connectors/ModbusRTUProtocolAdapter/versions/3", "Parameters": { "ModbusSerialPort-ResourceId": "MyLocalModbusSerialPort", "ModbusSerialPort": "/path-to-port
" } } ] }'
Note
The Lambda function in this connector has a long-lived lifecycle.
In the AWS IoT Greengrass console, you can add a connector from the group's Connectors page. For more information, see Getting started with Greengrass connectors (console).
Note
After you deploy the Modbus-RTU Protocol Adapter connector, you can use AWS IoT Things Graph to orchestrate interactions between devices in your group. For more information, see Modbus in the AWS IoT Things Graph User Guide.
Input data
This connector accepts Modbus RTU request parameters from a user-defined Lambda function on an MQTT topic. Input messages must be in JSON format.
- Topic filter in subscription
-
modbus/adapter/request
- Message properties
-
The request message varies based on the type of Modbus RTU request that it represents. The following properties are required for all requests:
-
In the
request
object:-
operation
. The name of the operation to execute. For example, specify"operation": "ReadCoilsRequest"
to read coils. This value must be a Unicode string. For supported operations, see Modbus RTU requests and responses. -
device
. The target device of the request. This value must be between0 - 247
.
-
-
The
id
property. An ID for the request. This value is used for data deduplication and is returned as is in theid
property of all responses, including error responses. This value must be a Unicode string.
Note
If your request includes an address field, you must specify the value as an integer. For example,
"address": 1
.The other parameters to include in the request depend on the operation. All request parameters are required except the CRC, which is handled separately. For examples, see Example requests and responses.
-
- Example input: Read coils request
-
{ "request": { "operation": "ReadCoilsRequest", "device": 1, "address": 1, "count": 1 }, "id": "TestRequest" }
Output data
This connector publishes responses to incoming Modbus RTU requests.
- Topic filter in subscription
-
modbus/adapter/response
- Message properties
-
The format of the response message varies based on the corresponding request and the response status. For examples, see Example requests and responses.
Note
A response for a write operation is simply an echo of the request. Although no meaningful information is returned for write responses, it's a good practice to check the status of the response.
Every response includes the following properties:
In the
response
object:-
status
. The status of the request. The status can be one of the following values:-
Success
. The request was valid, sent to the Modbus RTU network, and a response was returned. -
Exception
. The request was valid, sent to the Modbus RTU network, and an exception response was returned. For more information, see Response status: Exception. -
No Response
. The request was invalid, and the connector caught the error before the request was sent over the Modbus RTU network. For more information, see Response status: No response.
-
-
device
. The device that the request was sent to. -
operation
. The request type that was sent. -
payload
. The response content that was returned. If thestatus
isNo Response
, this object contains only anerror
property with the error description (for example,"error": "[Input/Output] No Response received from the remote unit"
).
-
The
id
property. The ID of the request, used for data deduplication.
- Example output: Success
-
{ "response" : { "status" : "success", "device": 1, "operation": "ReadCoilsRequest", "payload": { "function_code": 1, "bits": [1] } }, "id" : "TestRequest" }
- Example output: Failure
-
{ "response" : { "status" : "fail", "error_message": "Internal Error", "error": "Exception", "device": 1, "operation": "ReadCoilsRequest", "payload": { "function_code": 129, "exception_code": 2 } }, "id" : "TestRequest" }
For more examples, see Example requests and responses.
Modbus RTU requests and responses
This connector accepts Modbus RTU request parameters as input data and publishes responses as output data.
The following common operations are supported.
Operation name in request | Function code in response |
---|---|
ReadCoilsRequest | 01 |
ReadDiscreteInputsRequest | 02 |
ReadHoldingRegistersRequest | 03 |
ReadInputRegistersRequest | 04 |
WriteSingleCoilRequest | 05 |
WriteSingleRegisterRequest | 06 |
WriteMultipleCoilsRequest | 15 |
WriteMultipleRegistersRequest | 16 |
MaskWriteRegisterRequest | 22 |
ReadWriteMultipleRegistersRequest | 23 |
The following are example requests and responses for supported operations.
- Read Coils
Request example:
{ "request": { "operation": "ReadCoilsRequest", "device": 1, "address": 1, "count": 1 }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "ReadCoilsRequest", "payload": { "function_code": 1, "bits": [1] } }, "id" : "TestRequest" }
- Read Discrete Inputs
Request example:
{ "request": { "operation": "ReadDiscreteInputsRequest", "device": 1, "address": 1, "count": 1 }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "ReadDiscreteInputsRequest", "payload": { "function_code": 2, "bits": [1] } }, "id" : "TestRequest" }
- Read Holding Registers
Request example:
{ "request": { "operation": "ReadHoldingRegistersRequest", "device": 1, "address": 1, "count": 1 }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "ReadHoldingRegistersRequest", "payload": { "function_code": 3, "registers": [20,30] } }, "id" : "TestRequest" }
- Read Input Registers
Request example:
{ "request": { "operation": "ReadInputRegistersRequest", "device": 1, "address": 1, "value": 1 }, "id": "TestRequest" }
- Write Single Coil
Request example:
{ "request": { "operation": "WriteSingleCoilRequest", "device": 1, "address": 1, "value": 1 }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "WriteSingleCoilRequest", "payload": { "function_code": 5, "address": 1, "value": true } }, "id" : "TestRequest"
- Write Single Register
Request example:
{ "request": { "operation": "WriteSingleRegisterRequest", "device": 1, "address": 1, "value": 1 }, "id": "TestRequest" }
- Write Multiple Coils
Request example:
{ "request": { "operation": "WriteMultipleCoilsRequest", "device": 1, "address": 1, "values": [1,0,0,1] }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "WriteMultipleCoilsRequest", "payload": { "function_code": 15, "address": 1, "count": 4 } }, "id" : "TestRequest" }
- Write Multiple Registers
Request example:
{ "request": { "operation": "WriteMultipleRegistersRequest", "device": 1, "address": 1, "values": [20,30,10] }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "WriteMultipleRegistersRequest", "payload": { "function_code": 23, "address": 1, "count": 3 } }, "id" : "TestRequest" }
- Mask Write Register
Request example:
{ "request": { "operation": "MaskWriteRegisterRequest", "device": 1, "address": 1, "and_mask": 175, "or_mask": 1 }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "MaskWriteRegisterRequest", "payload": { "function_code": 22, "and_mask": 0, "or_mask": 8 } }, "id" : "TestRequest" }
- Read Write Multiple Registers
Request example:
{ "request": { "operation": "ReadWriteMultipleRegistersRequest", "device": 1, "read_address": 1, "read_count": 2, "write_address": 3, "write_registers": [20,30,40] }, "id": "TestRequest" }
Response example:
{ "response": { "status": "success", "device": 1, "operation": "ReadWriteMultipleRegistersRequest", "payload": { "function_code": 23, "registers": [10,20,10,20] } }, "id" : "TestRequest" }
Note
The registers returned in this response are the registers that are read from.
Exceptions can occur when the request format is valid, but the request is not completed successfully. In this case, the response contains the following information:
The
status
is set toException
.The
function_code
equals the function code of the request + 128.The
exception_code
contains the exception code. For more information, see Modbus exception codes.
Example:
{ "response" : { "status" : "fail", "error_message": "Internal Error", "error": "Exception", "device": 1, "operation": "ReadCoilsRequest", "payload": { "function_code": 129, "exception_code": 2 } }, "id" : "TestRequest" }
This connector performs validation checks on the Modbus request. For example, it checks for invalid formats and missing fields. If the validation fails, the connector doesn't send the request. Instead, it returns a response that contains the following information:
The
status
is set toNo Response
.The
error
contains the reason for the error.The
error_message
contains the error message.
Examples:
{ "response" : { "status" : "fail", "error_message": "Invalid address field. Expected <type 'int'>, got <type 'str'>", "error": "No Response", "device": 1, "operation": "ReadCoilsRequest", "payload": { "error": "Invalid address field. Expected <type 'int'>, got <type 'str'>" } }, "id" : "TestRequest" }
If the request targets a nonexistent device or if the Modbus RTU network is not working,
you might get a ModbusIOException
, which uses the No Response format.
{ "response" : { "status" : "fail", "error_message": "[Input/Output] No Response received from the remote unit", "error": "No Response", "device": 1, "operation": "ReadCoilsRequest", "payload": { "error": "[Input/Output] No Response received from the remote unit" } }, "id" : "TestRequest" }
Usage Example
Use the following high-level steps to set up an example Python 3.7 Lambda function that you can use to try out the connector.
Note
-
If you use other Python runtimes, you can create a symlink from Python3.x to Python 3.7.
-
The Get started with connectors (console) and Get started with connectors (CLI) topics contain detailed steps that show you how to configure and deploy an example Twilio Notifications connector.
Make sure you meet the requirements for the connector.
-
Create and publish a Lambda function that sends input data to the connector.
Save the example code as a PY file. Download and unzip the AWS IoT Greengrass Core SDK for Python. Then, create a zip package that contains the PY file and the
greengrasssdk
folder at the root level. This zip package is the deployment package that you upload to AWS Lambda.After you create the Python 3.7 Lambda function, publish a function version and create an alias.
-
Configure your Greengrass group.
-
Add the Lambda function by its alias (recommended). Configure the Lambda lifecycle as long-lived (or
"Pinned": true
in the CLI). -
Add the required local device resource and grant read/write access to the Lambda function.
-
Add the connector and configure its parameters.
-
Add subscriptions that allow the connector to receive input data and send output data on supported topic filters.
Set the Lambda function as the source, the connector as the target, and use a supported input topic filter.
Set the connector as the source, AWS IoT Core as the target, and use a supported output topic filter. You use this subscription to view status messages in the AWS IoT console.
-
-
Deploy the group.
-
In the AWS IoT console, on the Test page, subscribe to the output data topic to view status messages from the connector. The example Lambda function is long-lived and starts sending messages immediately after the group is deployed.
When you're finished testing, you can set the Lambda lifecycle to on-demand (or
"Pinned": false
in the CLI) and deploy the group. This stops the function from sending messages.
Example
The following example Lambda function sends an input message to the connector.
import greengrasssdk import json TOPIC_REQUEST = 'modbus/adapter/request' # Creating a greengrass core sdk client iot_client = greengrasssdk.client('iot-data') def create_read_coils_request(): request = { "request": { "operation": "ReadCoilsRequest", "device": 1, "address": 1, "count": 1 }, "id": "TestRequest" } return request def publish_basic_request(): iot_client.publish(payload=json.dumps(create_read_coils_request()), topic=TOPIC_REQUEST) publish_basic_request() def lambda_handler(event, context): return
Licenses
The Modbus-RTU Protocol Adapter connector includes the following third-party software/licensing:
This connector is released under the
Greengrass Core Software License Agreement
Changelog
The following table describes the changes in each version of the connector.
Version |
Changes |
---|---|
3 |
Upgraded the Lambda runtime to Python 3.7, which changes the runtime requirement. |
2 |
Updated connector ARN for AWS Region support. Improved error logging. |
1 |
Initial release. |
A Greengrass group can contain only one version of the connector at a time. For information about upgrading a connector version, see Upgrading connector versions.