From 132e7b63f6e1121ea84670d1ccd80f437f16116d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 24 Jul 2026 14:19:15 -0400 Subject: [PATCH] feat(modbus-rtu): add Transport selector to the AdminUI Modbus driver form Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW --- .../Shared/Drivers/Forms/ModbusDriverForm.razor | 15 +++++++++++++++ .../Uns/ModbusDriverFormModelTests.cs | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/ModbusDriverForm.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/ModbusDriverForm.razor index f0959d1a..0c34a768 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/ModbusDriverForm.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/ModbusDriverForm.razor @@ -27,6 +27,16 @@ } +
+ + + @foreach (var e in Enum.GetValues()) + { + + } + +
RtuOverTcp = talk raw RTU frames to a serial→Ethernet gateway; must match the gateway's mode.
+
@@ -290,6 +300,9 @@ public ModbusFamily Family { get; set; } = ModbusFamily.Generic; public MelsecFamily MelsecSubFamily { get; set; } = MelsecFamily.Q_L_iQR; + // Wire transport (Tcp = Modbus/TCP MBAP; RtuOverTcp = RTU framing over a serial→Ethernet gateway) + public ModbusTransportMode Transport { get; set; } = ModbusTransportMode.Tcp; + // Transport flags public bool AutoReconnect { get; set; } = true; public int IdleDisconnectTimeoutSeconds { get; set; } = 0; @@ -337,6 +350,7 @@ TimeoutSeconds = (int)o.Timeout.TotalSeconds, Family = o.Family, MelsecSubFamily = o.MelsecSubFamily, + Transport = o.Transport, AutoReconnect = o.AutoReconnect, IdleDisconnectTimeoutSeconds = o.IdleDisconnectTimeout.HasValue ? (int)o.IdleDisconnectTimeout.Value.TotalSeconds : 0, MaxRegistersPerRead = o.MaxRegistersPerRead, @@ -387,6 +401,7 @@ MaxReadGap = (ushort)Math.Clamp(MaxReadGap, 0, 65535), Family = Family, MelsecSubFamily = MelsecSubFamily, + Transport = Transport, WriteOnChangeOnly = WriteOnChangeOnly, AutoReconnect = AutoReconnect, KeepAlive = new ModbusKeepAliveOptions diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/ModbusDriverFormModelTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/ModbusDriverFormModelTests.cs index c7e47597..59c90bc2 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/ModbusDriverFormModelTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/ModbusDriverFormModelTests.cs @@ -61,4 +61,15 @@ public sealed class ModbusDriverFormModelTests json.ShouldContain("\"family\":\"MELSEC\""); // enum-as-name (not a number), camelCase key json.ShouldNotContain("\"family\":0", Case.Sensitive); // never the numeric enum form } + + [Fact] + public void Round_trip_preserves_Transport_mode() + { + var form = new ModbusDriverForm.FormModel { Transport = ModbusTransportMode.RtuOverTcp }; + var json = JsonSerializer.Serialize(form.ToOptions(), JsonOpts); + var back = ModbusDriverForm.FormModel.FromOptions( + JsonSerializer.Deserialize(json, JsonOpts)!); + back.Transport.ShouldBe(ModbusTransportMode.RtuOverTcp); + json.ShouldContain("\"transport\":\"RtuOverTcp\""); // name string, never a number + } }