Skip to content

Add Modbus Connection - How To

You can add an Modbus connection through the Kelvin UI, Kelvin SDK and Kelvin API.

Connections can be deployed to both x86_64 and ARM64 devices.

To start click on the Connections menu option from the left side bar menu.

click on the Create Connection button.

Step 1

Select Import Data and Control Setpoints and click Next.

Step 2

Select the Modbus option, select a Version and click Next.

Step 3

Type in a memorable name in the Connection Display Name text input. You can use any letters, numbers and special characters.

The Connection Name text input will be automatically converted and filled in as you type in the Connection Display Name section. The conversion ensures the Connection Name only contains lowercase alphanumeric characters and ., _ or - characters.

Then select which Cluster to deploy the new Connector to.

It is important that the asset is reachable from the selected Cluster.

Step 4

Configure the Modbus connection to the asset. There are a number of optional and mandatory parameters to fill in.

Info

You can choose to use the UI view, or work directly in YAML or JSON format.

For the optional parameters, if you do not fill in any values, the default values will be used.

Parameter Options Description Default Mandatory
Connection Type TCP or RTU Specifies the type of Modbus connection, such as TCP (for Modbus TCP) or RTU (for Modbus RTU). Yes
IP String (IP address) The IP address of the Modbus TCP device to connect to for Modbus TCP connection. Yes
Port Numeric value (port number) The network port number used for Modbus TCP connection. Yes
Serial Port String (serial port identifier) The identifier of the serial port used for Modbus RTU connection. Yes
Serial Mode RS232, RS485 Specifies the serial transmission mode for Modbus RTU. Yes
Slave ID Numeric value The address of the slave device in the Modbus network to communicate with. Yes
Timeout (In Seconds) Numeric value The maximum duration to wait for a response from the slave device before timing out. 5 No
Reconnect Delay (In Seconds) Numeric value The time to wait before attempting to reconnect after a lost connection. 15 No
Request Delay (In Seconds) Numeric value The delay between successive Modbus requests, used to avoid overloading the network or the slave device. 0 No
Minus Offset Numeric value Used to adjust the addressing when reading data, subtracting from the requested address to match device addressing. 0 Yes
Read Chunk Timestamp Sync Boolean (True/False) Specifies whether to synchronize timestamps for each chunk of data read in a transaction. False No
Protocol Debug Boolean (True/False) Enables or disables additional logging for troubleshooting and debugging the Modbus protocol communication. False No
Register Chunk Size Numeric value Defines the size of data chunks (in register units) to be read in each Modbus request. 120 No

Step 5

Select an Asset, Data Stream and fill in the connection and other optional values.

Full descriptions of each column is giving below.

Success

If you have many connection IO to fill in, you can save time with the download/upload csv file option in the top right hand corner of the popup.

Use Microsoft Excel or Google Sheets to fill in all the Connection IO details.

You can only upload one file. Multiple file uploads is not allowed and only the latest selected file will be used.

Header Description Example Mandatory
Asset The Kelvin Asset name (must be lowercase alphanumeric with no spaces) well-01 Yes
DataStream The Kelvin Data Stream name (must be lowercase alphanumeric with no spaces) water-flow Yes
Storage Location of the storage; "none", "node", "node-and-cloud" node-and-cloud No
Address (1-49999) The specific modbus address or register number of the data in the asset. 1023 Yes
Polling Rate (in seconds) How often to pull the data from the asset 30 Yes
Protocol Type Specifies the protocol data type used for interpreting the data. uint32 Yes
Writable Read/Write (RW) or Read Only (RO) RO Yes

Complete the Connection

When everything is validated, then you can click on Connect button to deploy the Connection to the Cluster. It will start automatically, connect to the asset and start collecting data.

API cURL Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
curl -X "POST" \
  'https://<url.kelvin.ai>/api/v4/apps/workloads/create?stopped=false' \
  -H "Authorization: Bearer <Your Current Token>" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "docs-demo-modbus",
  "title": "Docs Demo Modbus",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "cluster_name": "sales-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "casing_pressure",
        "title": "Casing Pressure",
        "data_type_name": "number",
        "unit_name": "pound_per_square_inch"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:doc-motor-01",
        "datastreams": {
          "casing_pressure": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 12500,
              "polling_rate": 30,
              "protocol_type": "float32"
            }
          }
        },
        "properties": {
          "casing_depth": 14076,
          "county": "Reeves",
          "field": "Permian",
          "latitude": 31.984,
          "longitude": -102.744,
          "motor_configuration": "7:9",
          "plc_manufacturer": "Schneider",
          "vsd_type": "GE",
          "well_depth": 14927,
          "well_run": 3
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 218,
        "tcp": {
          "ip": "10.5.0.52",
          "port": 5222
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "privileged": false,
    "environment_vars": [
      {
        "name": "KELVIN_ACP_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_CLUSTER_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_WORKLOAD_NAME",
        "value": "docs-demo-modbus"
      }
    ]
  }
}'

The response will look something like this;

API cURL Example Response
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{
  "name": "docs-demo-modbus",
  "title": "Docs Demo Modbus",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "app_type": "importer",
  "cluster_name": "sales-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "casing_pressure",
        "title": "Casing Pressure",
        "data_type_name": "number",
        "unit_name": "pound_per_square_inch"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:doc-motor-01",
        "datastreams": {
          "casing_pressure": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 12500,
              "polling_rate": 30,
              "protocol_type": "float32"
            }
          }
        },
        "properties": {
          "casing_depth": 14076,
          "county": "Reeves",
          "field": "Permian",
          "latitude": 31.984,
          "longitude": -102.744,
          "motor_configuration": "7:9",
          "plc_manufacturer": "Schneider",
          "vsd_type": "GE",
          "well_depth": 14927,
          "well_run": 3
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 218,
        "tcp": {
          "ip": "10.5.0.52",
          "port": 5222
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "privileged": false,
    "environment_vars": [
      {
        "name": "KELVIN_ACP_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_CLUSTER_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_WORKLOAD_NAME",
        "value": "docs-demo-modbus"
      }
    ]
  },
  "node_name": null,
  "status": {
    "state": "pending_deploy",
    "message": "Pending for deploy",
    "last_seen": "2025-04-04T12:13:20.920272288Z",
    "warnings": null
  },
  "download_status": "pending",
  "download_error": null,
  "staged": null,
  "created_at": "2025-04-04T12:13:20.920272Z",
  "created_by": "krn:user:demo@kelvin.ai",
  "updated_at": "2025-04-04T12:13:20.920272Z",
  "updated_by": "krn:user:demo@kelvin.ai"
}

Then in Kelvin UI under Connections you will see your Connection deployed and running.

If you have any issues in the deployment and the /bridges/deploy fails to run, then you can check its logs.

API Client (Python) Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from kelvin.api.client import Client

# Login
client = Client(config={"url": "https://<url.kelvin.ai>", "username": "<your_username>"})
client.login(password="<your_password>")

# Create Connection
client.app_workloads.create_workload(data={
  "name": "docs-demo-modbus",
  "title": "Docs Demo Modbus",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "cluster_name": "sales-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "casing_pressure",
        "title": "Casing Pressure",
        "data_type_name": "number",
        "unit_name": "pound_per_square_inch"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:doc-motor-01",
        "datastreams": {
          "casing_pressure": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 12500,
              "polling_rate": 30,
              "protocol_type": "float32"
            }
          }
        },
        "properties": {
          "casing_depth": 14076,
          "county": "Reeves",
          "field": "Permian",
          "latitude": 31.984,
          "longitude": -102.744,
          "motor_configuration": "7:9",
          "plc_manufacturer": "Schneider",
          "vsd_type": "GE",
          "well_depth": 14927,
          "well_run": 3
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 218,
        "tcp": {
          "ip": "10.5.0.52",
          "port": 5222
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "privileged": false,
    "environment_vars": [
      {
        "name": "KELVIN_ACP_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_CLUSTER_NAME",
        "value": "sales-01-cluster"
      },
      {
        "name": "KELVIN_WORKLOAD_NAME",
        "value": "docs-demo-modbus"
      }
    ]
  }
})