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.

Deploy

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

Here you will see a list of Import Connection Applications available in the App Registry.

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

Step 3

In Step 3 you have a range of options available.

Note

You will only be able to deploy your workload once all options have a green check .

Information

Type in a memorable name in the 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 Display Name section. The conversion ensures the Connection Name only contains lowercase alphanumeric characters and ., _ or - characters.

Configuration

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 Serial Specifies the type of Modbus connection, such as TCP (for Modbus TCP) or Serial (for Modbus RTU). Yes
IP (Visible with TCP connection only) String (IP address) The IP address of the Modbus TCP device to connect to for Modbus TCP connection. Yes
Port (Visible with TCP connection only) Numeric value (port number) The network port number used for Modbus TCP connection. Yes
Serial Port (Visible with Serial connection only) String (serial port identifier) The identifier of the serial port used for Modbus RTU connection. Yes
Serial Mode (Visible with Serial connection only) RS232, RS485 Specifies the serial transmission mode for Modbus RTU. Yes
Baud Rate (Visible with Serial connection only) 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 (bits/s) The communication speed in bits per second used on the serial connection. Must match the slave device setting. Yes
Parity (Visible with Serial connection only) None, Even, Odd Defines the parity error-checking mode for serial communication. Ensures data integrity by adding a parity bit if enabled. N No
Data Bits (Visible with Serial connection only) 7, 8 Sets the number of data bits in each character frame. Typically 8 for Modbus RTU communication. 8 No
RTS Mode (Visible with Serial connection only) NONE, UP, DOWN Controls the RTS (Request To Send) signal behavior when using RS485. Determines line driver enabling mode. UP No
RTS Delay (Visible with Serial connection only) Numeric value (milliseconds) The delay applied after toggling RTS before transmitting data, used for proper RS485 line settling. 0 No
Error Recovery (Visible with Serial connection only) Boolean (True/False) Enables automatic recovery attempts from communication errors on serial connections. False No
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

System

Here you will be able to tune all the system variables that are present in the app.yaml file of the Application.

You can choose to edit it using a UI or directly on the YAML or JSON.

Note

Using YAML or JSON is very useful for fast application of settings if you have preset configurations and want to copy/paste them into here.

Env Vars

Here will be shown the list of default Environment Variables and the default values that were set in the app.yaml file of the Application during development.

You can edit these and change both the environment name or value. You can also add addition Environment variables.

Resources

Apply resources available for the Workload.

See Set CPU/Memory Limits for detailed documentation on this section.

Ports

Open ports to your Workload.

Volumes

Mount volumes to your Workload.

Advanced

Choose if you would like to add Privileged mode to the Workload

Optionally choose a health check service for your Workload. These are Kubernetes liveness probes and detailed information can be found on the Kubernetes Website.

Warning

If you use a Health check option, make sure you add code to respond to the liveness probe requests.

IO Mapping

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
Control Writable Read/Write (RW) or Read Only (RO) RO Yes

Cluster

Then select which Cluster to deploy the new Connector to.

Optionally you can also select the Node in the Cluster. If you do not then the system will automatically assign the Node.

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

Deployment

For a standard Workload deployment, choose the Standard option.

Note

Stage Only and Instant Apply are covered in a different documentation section.

When you are ready and you have a green check on all options, you will see the Create button turn blue.

You can then see the status of the Connection in the Connections list going from Pending, Deploying to Running. It will start automatically, connect to the asset and start collecting data.

You can even create and deploy the Connection if the Cluster is offline. It will be placed in a queue with a status of Pending and will be automatically deployed when the Cluster comes back online.

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
curl -X 'POST' \
  'https://beta.kelvininc.com/api/v4/apps/workloads/create?stopped=false' \
  -H "Authorization: Bearer <Your Current Token>" \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "demo-modbus-connection",
  "title": "Demo Modbus Connection",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "app_type": "importer",
  "cluster_name": "beta-cluster-01",
  "node_name": "beta-dev-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "compressor_status",
        "title": "Compressor Status",
        "data_type_name": "boolean"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:beam_pump_01",
        "datastreams": {
          "compressor_status": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 500,
              "polling_rate": 10,
              "protocol_type": "int32"
            }
          }
        },
        "properties": {
          "casing_depth": 11901,
          "county": "Dunn",
          "field": "Williston",
          "latitude": 47.3689,
          "longitude": -103.747,
          "motor_configuration": "3:5",
          "plc_manufacturer": "Siemens",
          "vsd_type": "Weatherford",
          "well_depth": 12726,
          "well_run": 1
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 200,
        "tcp": {
          "ip": "kelvin-modbus-simulator.app",
          "port": 502
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "resources": {
      "requests": {
        "cpu": "250m",
        "memory": "128Mi"
      }
    }
  }
}'

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
{
  "name": "demo-modbus-connection",
  "title": "Demo Modbus Connection",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "app_type": "importer",
  "cluster_name": "beta-cluster-01",
  "runtime": {
    "datastreams": [
      {
        "name": "compressor_status",
        "title": "Compressor Status",
        "data_type_name": "boolean"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:beam_pump_01",
        "datastreams": {
          "compressor_status": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 500,
              "polling_rate": 10,
              "protocol_type": "int32"
            }
          }
        },
        "properties": {
          "casing_depth": 11901,
          "county": "Dunn",
          "field": "Williston",
          "latitude": 47.3689,
          "longitude": -103.747,
          "motor_configuration": "3:5",
          "plc_manufacturer": "Siemens",
          "vsd_type": "Weatherford",
          "well_depth": 12726,
          "well_run": 1
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 200,
        "tcp": {
          "ip": "kelvin-modbus-simulator.app",
          "port": 502
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "resources": {
      "requests": {
        "cpu": "250m",
        "memory": "128Mi"
      }
    },
    "privileged": false
  },
  "node_name": "beta-dev-01-cluster",
  "status": {
    "state": "pending_deploy",
    "message": "Pending for deploy",
    "last_seen": "2025-08-28T05:17:59.818530609Z",
    "warnings": null
  },
  "download_status": "pending",
  "download_error": null,
  "staged": null,
  "created_at": "2025-08-28T05:17:59.81853Z",
  "created_by": "krn:user:demo@kelvin.ai",
  "updated_at": "2025-08-28T05:17:59.81853Z",
  "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
from kelvin.api.client import Client

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

# Create Connection
client.app_workloads.create_workload(data={
  "name": "demo-modbus-connection",
  "title": "Demo Modbus Connection",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "app_type": "importer",
  "cluster_name": "beta-cluster-01",
  "node_name": "beta-dev-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "compressor_status",
        "title": "Compressor Status",
        "data_type_name": "boolean"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:beam_pump_01",
        "datastreams": {
          "compressor_status": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 500,
              "polling_rate": 10,
              "protocol_type": "int32"
            }
          }
        },
        "properties": {
          "casing_depth": 11901,
          "county": "Dunn",
          "field": "Williston",
          "latitude": 47.3689,
          "longitude": -103.747,
          "motor_configuration": "3:5",
          "plc_manufacturer": "Siemens",
          "vsd_type": "Weatherford",
          "well_depth": 12726,
          "well_run": 1
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 200,
        "tcp": {
          "ip": "kelvin-modbus-simulator.app",
          "port": 502
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "resources": {
      "requests": {
        "cpu": "250m",
        "memory": "128Mi"
      }
    }
  }
})

app.yaml

All the information for the Connection is stored in the app.yaml file which is deployed with the Connection Application.

This includes the core information that comes with the Application and all options that are filled in the Kelvin UI or added as the data in the API.

Most of the app.yaml is copied from the default Application app.yaml file. There are options to customize it when deploying. Full information on these parts can be found in the developer tools section here.

There are a number of unique elements of the app.yaml which is deployed with the Connection.

Key Sub Key Descriptions Other Related Keys
runtime A list of all the Connection specific information
datastreams The Data Streams used in the Resources name, title, data_type_name, unit_name
resources A list of all Asset / Data Stream connections Each object in the list is defined in the resource key
resource The KRN of the Asset name and the list of Data Streams datastreams, way, storage, remote, configuration
configuration The global Connection configurations to connect to the physical asset chunk_size, connection, reconnect_delay, request_delay, slave_id, tcp and associated keys, serial and associated keys, timeout, type, debug, minus_offset, timestamp_sync
system System related information
resources Resource allocation for the Connection requests, cpu, memory

In the deployed app.yaml you will have the following options;

Note

If the Modbus uses serial, then swap the tcp configuration key below with this key set;

Serial Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
"serial": {
  "baudrate": 9600,
  "data_bits": 8,
  "error_recovery": false,
  "parity": "N",
  "rts_delay": 0,
  "rts_mode": "UP",
  "serial_mode": "RS232",
  "serial_port": "25",
  "stop_bits": 1
},
app.yaml 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
{
  "name": "demo-modbus-connection",
  "title": "Demo Modbus Connection",
  "app_name": "kelvin-bridge-modbus-client",
  "app_version": "4.5.2",
  "app_type": "importer",
  "cluster_name": "beta-cluster-01",
  "node_name": "beta-dev-01-cluster",
  "runtime": {
    "datastreams": [
      {
        "name": "compressor_status",
        "title": "Compressor Status",
        "data_type_name": "boolean"
      }
    ],
    "resources": [
      {
        "resource": "krn:asset:beam_pump_01",
        "datastreams": {
          "compressor_status": {
            "way": "output",
            "storage": "node-and-cloud",
            "remote": false,
            "configuration": {
              "address": 500,
              "polling_rate": 10,
              "protocol_type": "int32"
            }
          }
        },
        "properties": {
          "casing_depth": 11901,
          "county": "Dunn",
          "field": "Williston",
          "latitude": 47.3689,
          "longitude": -103.747,
          "motor_configuration": "3:5",
          "plc_manufacturer": "Siemens",
          "vsd_type": "Weatherford",
          "well_depth": 12726,
          "well_run": 1
        }
      }
    ],
    "configuration": {
      "chunk_size": 120,
      "connection": {
        "reconnect_delay": 15,
        "request_delay": 0,
        "slave_id": 200,
        "tcp": {
          "ip": "kelvin-modbus-simulator.app",
          "port": 502
        },
        "timeout": 5,
        "type": "tcp"
      },
      "debug": false,
      "minus_offset": 0,
      "timestamp_sync": false
    }
  },
  "system": {
    "resources": {
      "requests": {
        "cpu": "250m",
        "memory": "128Mi"
      }
    }
  }
}