diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ModbusDriverOptions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ModbusDriverOptions.cs
index 642f1902..39a4104e 100644
--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ModbusDriverOptions.cs
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ModbusDriverOptions.cs
@@ -130,6 +130,14 @@ public sealed class ModbusDriverOptions
///
public MelsecFamily MelsecSubFamily { get; init; } = MelsecFamily.Q_L_iQR;
+ ///
+ /// Wire transport selector. (default) is the
+ /// historical Modbus TCP/MBAP framing.
+ /// frames Modbus RTU PDUs (CRC16, no MBAP header) over the same TCP socket — for
+ /// serial-to-Ethernet gateways that bridge RS-485 without re-encapsulating to MBAP.
+ ///
+ public ModbusTransportMode Transport { get; init; } = ModbusTransportMode.Tcp;
+
///
/// When true, the driver suppresses redundant writes: if the most recent
/// successful write to a tag carried value V and a new write of V arrives, the second
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus/ModbusDriverFactoryExtensions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus/ModbusDriverFactoryExtensions.cs
index 5291f0cb..93fdb4a7 100644
--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus/ModbusDriverFactoryExtensions.cs
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus/ModbusDriverFactoryExtensions.cs
@@ -74,6 +74,8 @@ public static class ModbusDriverFactoryExtensions
: ParseEnum(dto.Family, "", driverInstanceId, "Family"),
MelsecSubFamily = dto.MelsecSubFamily is null ? MelsecFamily.Q_L_iQR
: ParseEnum(dto.MelsecSubFamily, "", driverInstanceId, "MelsecSubFamily"),
+ Transport = dto.Transport is null ? ModbusTransportMode.Tcp
+ : ParseEnum(dto.Transport, "", driverInstanceId, "Transport"),
AutoProhibitReprobeInterval = dto.AutoProhibitReprobeMs is { } reprobeMs ? TimeSpan.FromMilliseconds(reprobeMs) : null,
AutoReconnect = dto.AutoReconnect ?? true,
// v3: the deploy artifact (Wave C) populates rawTags with the cluster's authored raw Modbus
@@ -159,6 +161,8 @@ public static class ModbusDriverFactoryExtensions
public string? Family { get; init; }
/// Gets or sets the Melsec subfamily.
public string? MelsecSubFamily { get; init; }
+ /// Gets or sets the wire transport mode (Tcp / RtuOverTcp). Null defaults to Tcp.
+ public string? Transport { get; init; }
/// Gets or sets the automatic prohibition reprobei interval in milliseconds.
public int? AutoProhibitReprobeMs { get; init; }
/// Gets or sets a value indicating whether automatic reconnection is enabled.
diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusTransportConfigRoundTripTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusTransportConfigRoundTripTests.cs
new file mode 100644
index 00000000..343eb379
--- /dev/null
+++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/ModbusTransportConfigRoundTripTests.cs
@@ -0,0 +1,47 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Shouldly;
+using Xunit;
+
+namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests;
+
+public sealed class ModbusTransportConfigRoundTripTests
+{
+ // Mirrors the AdminUI ModbusDriverForm serializer: camelCase + string enums.
+ private static readonly JsonSerializerOptions _adminOpts = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ Converters = { new JsonStringEnumConverter() },
+ };
+
+ [Fact]
+ public void Transport_serializes_as_a_string_not_a_number()
+ {
+ var opts = new ModbusDriverOptions { Host = "10.20.0.50", Port = 4001, Transport = ModbusTransportMode.RtuOverTcp };
+ var json = JsonSerializer.Serialize(opts, _adminOpts);
+ json.ShouldContain("\"transport\":\"RtuOverTcp\"");
+ json.ShouldNotContain("\"transport\":1", Case.Sensitive);
+ }
+
+ [Fact]
+ public void Factory_binds_RtuOverTcp_from_string_config()
+ {
+ const string json = """{ "host": "10.20.0.50", "port": 4001, "transport": "RtuOverTcp" }""";
+ using var driver = ModbusDriverFactoryExtensions.CreateInstance("mb-rtu", json);
+ var opts = (ModbusDriverOptions)typeof(ModbusDriver)
+ .GetField("_options", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
+ .GetValue(driver)!;
+ opts.Transport.ShouldBe(ModbusTransportMode.RtuOverTcp);
+ }
+
+ [Fact]
+ public void Factory_defaults_Transport_to_Tcp_when_omitted()
+ {
+ const string json = """{ "host": "10.0.0.10" }""";
+ using var driver = ModbusDriverFactoryExtensions.CreateInstance("mb-tcp", json);
+ var opts = (ModbusDriverOptions)typeof(ModbusDriver)
+ .GetField("_options", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
+ .GetValue(driver)!;
+ opts.Transport.ShouldBe(ModbusTransportMode.Tcp);
+ }
+}