ModbusDeviceKit 1.0.1
See the version list below for details.
dotnet add package ModbusDeviceKit --version 1.0.1
NuGet\Install-Package ModbusDeviceKit -Version 1.0.1
<PackageReference Include="ModbusDeviceKit" Version="1.0.1" />
<PackageVersion Include="ModbusDeviceKit" Version="1.0.1" />
<PackageReference Include="ModbusDeviceKit" />
paket add ModbusDeviceKit --version 1.0.1
#r "nuget: ModbusDeviceKit, 1.0.1"
#:package ModbusDeviceKit@1.0.1
#addin nuget:?package=ModbusDeviceKit&version=1.0.1
#tool nuget:?package=ModbusDeviceKit&version=1.0.1
ModbusDeviceKit
🇬🇧 English | 🇹🇷 Türkçe
dotnet add package ModbusDeviceKit
A .NET 8 library that reads Modbus RTU/TCP devices (load cells, torque sensors, temperature/pressure transmitters…) described by JSON profile files. When a new device brand arrives, you add a JSON profile instead of hand-coding its register map.
- Reads every register in one call and merges adjacent registers into a single Modbus request
Int16/UInt16/Int32/UInt32/Float32/Int64/UInt64/Float64/BoolwithABCD/CDAB/BADC/DCBAbyte orders- Named, scaled results:
value = raw × scale + offset − tare - Tare/calibration:
ApplyTareAsync()(averaged samples),ApplyTare(),SetTare(),ClearTare() - Retries with Polly (constant/linear/exponential backoff, jitter) and automatic reconnect when the link drops
- Meaningful exceptions:
DeviceTimeoutException,DeviceConnectionException,DeviceSlaveException… - Modbus RTU (serial port), Modbus TCP and RTU-over-TCP (serial-to-Ethernet converters), built on NModbus
- Fully async and thread-safe; several devices can share one RS-485 line (transport)
Quick start
using ModbusDeviceKit;
await using var reader = await DeviceReader.CreateFromFileAsync("device-profile.json");
await reader.ConnectAsync();
DeviceReading reading = await reader.ReadAsync();
double force = reading["Force"]; // scaled value with tare applied
RegisterValue temp = reading.GetRegister("Temperature");
Console.WriteLine($"{temp.Value} {temp.Unit} (raw: {temp.RawValue})");
Dictionary<string, double> values = reading.ToDictionary();
await reader.ApplyTareAsync(samples: 10); // zero every register with "allowTare": true
To create the transport yourself (e.g. several devices on the same RS-485 line):
using System.IO.Ports;
using ModbusDeviceKit.Profiles;
using ModbusDeviceKit.Transport;
await using var bus = new ModbusRtuTransport("COM3", 19200, Parity.Even);
using var loadCell = new DeviceReader(DeviceProfile.LoadFromFile("loadcell.json"), bus);
using var torque = new DeviceReader(DeviceProfile.LoadFromFile("torque.json"), bus);
Profile format
{
"deviceName": "LoadCell_XYZ123", // required
"protocol": "ModbusRTU", // ModbusRTU | ModbusTCP | ModbusRtuOverTcp
"slaveId": 1,
"byteOrder": "ABCD", // default byte order: ABCD | CDAB | BADC | DCBA
"connection": { // used by DeviceReader.Create / ModbusTransportFactory
"serial": { "portName": "COM3", "baudRate": 9600, "parity": "None", "dataBits": 8, "stopBits": "One" },
"tcp": { "host": "192.168.1.50", "port": 502 },
"connectTimeoutMs": 3000, "readTimeoutMs": 500, "writeTimeoutMs": 500
},
"retry": { "maxRetries": 3, "delayMs": 100, "maxDelayMs": 2000, "backoff": "Exponential", "useJitter": true },
"readOptions": { "maxRegistersPerRead": 120, "maxAddressGap": 0, "interRequestDelayMs": 5 },
"registers": [
{ "name": "Force", "address": 100, "dataType": "Float32", "scale": 0.01, "unit": "N", "allowTare": true },
{ "name": "Temperature", "address": 102, "dataType": "Int16", "scale": 0.1, "offset": -0.5, "unit": "C" },
{ "name": "AdcCounts", "address": 200, "registerType": "Input", "dataType": "Int32", "byteOrder": "CDAB" },
{ "name": "Overload", "address": 0, "registerType": "DiscreteInput", "dataType": "Bool" }
]
}
| Register field | Default | Description |
|---|---|---|
name |
— | Unique name (case-insensitive) |
address |
— | Zero-based protocol address (40101 → 100) |
registerType |
Holding |
Holding (FC03), Input (FC04), Coil (FC01), DiscreteInput (FC02) |
dataType |
UInt16 |
Bool is required for Coil/DiscreteInput |
byteOrder |
profile value | Per-register byte order |
scale / offset |
1 / 0 | Calibration: raw × scale + offset |
tare / allowTare |
0 / false | Initial tare; include the register in ApplyTare() (tare all) |
unit, description |
— | Informational |
Profiles are validated on load. Unknown fields (e.g. a "scael" typo) and inconsistent values are reported
together in a single DeviceProfileException with the full error list. Comments are allowed in the JSON.
Error handling
Every connect/read operation is retried according to the retry settings. Timeouts, CRC/IO errors, dropped
connections, "Slave Device Busy" (6), "Acknowledge" (5) and "Gateway Target Failed To Respond" (11) are treated as
transient. Requests the device explicitly rejects, such as "Illegal Data Address", are not retried.
| Exception | When |
|---|---|
DeviceTimeoutException |
The device did not answer in any attempt |
DeviceConnectionException |
The port/socket could not be opened |
DeviceSlaveException |
The device returned a Modbus exception response (ExceptionCode, ExceptionName) |
DeviceCommunicationException |
CRC/framing/IO error (also the base class of the timeout and slave exceptions) |
DeviceProfileException |
The profile is invalid (Errors list) |
All of them derive from ModbusDeviceKitException. Communication errors carry DeviceName, SlaveId and
Attempts; connection errors carry Endpoint and Attempts.
Console sample
dotnet run --project samples/ModbusDeviceKit.ConsoleSample # device-profile.json, every 5 s
dotnet run --project samples/ModbusDeviceKit.ConsoleSample -- my-device.json --interval 2
dotnet run --project samples/ModbusDeviceKit.ConsoleSample -- --simulate # no hardware, built-in simulator
While running: T = tare (average of 5 samples), C = clear tare, Q/Esc = quit.
Build, test, pack
dotnet build
dotnet test
dotnet pack src/ModbusDeviceKit -c Release -o artifacts
License
MIT © Semih Bener
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- NModbus (>= 3.0.83)
- Polly.Core (>= 8.8.0)
- System.IO.Ports (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.1: English README (Turkish version: README.tr.md on GitHub). No code changes.
1.0.0: Initial release - JSON device profiles, Modbus RTU / TCP / RTU-over-TCP transports, block reads, byte-order support, tare/calibration, Polly retries.