Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/DeviceForms/S7DeviceModel.cs
T
Joseph Doherty 844f93f64f feat(adminui): B2-WP3 driver/device config modals + page-to-form refactor
Extract the 8 typed driver pages into embeddable <Driver>DriverForm bodies
(channel/protocol config) and add per-driver <Driver>DeviceForm bodies
(connection endpoint -> Device.DeviceConfig, v3 endpoint split). New
DriverConfigModal + DeviceModal dispatch by DriverType (DriverTypeNames) for
the /raw tree; Test-connect inside DeviceModal builds the merged Driver+Device
config transiently via DriverDeviceConfigMerger. Routed pages now host the
form bodies and keep working. Round-trip + enum-serialization guard tests for
the Modbus driver form + Modbus device model; retargeted the existing
page-form serialization tests + the _jsonOpts converter guard to the forms.

Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
2026-07-16 03:26:24 -04:00

61 lines
2.6 KiB
C#

using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.DeviceForms;
/// <summary>
/// Typed working model for an S7 <c>Device</c>'s connection endpoint (the v3 endpoint→DeviceConfig
/// split). Authors the <b>PascalCase</b> <c>Host</c>/<c>Port</c>/<c>Rack</c>/<c>Slot</c> keys that
/// <c>S7DriverOptions</c> binds — the exact casing the seed and runtime probe
/// (<c>PropertyNameCaseInsensitive</c>) expect. Preserves unrecognised keys across a load→save.
/// </summary>
public sealed class S7DeviceModel
{
/// <summary>PLC host / IP address.</summary>
public string Host { get; set; } = "127.0.0.1";
/// <summary>ISO-on-TCP port (usually 102).</summary>
public int Port { get; set; } = 102;
/// <summary>PLC rack number (almost always 0).</summary>
public int Rack { get; set; } = 0;
/// <summary>PLC slot number (S7-300/400 = 2; S7-1200/1500 = 0).</summary>
public int Slot { get; set; } = 0;
private System.Text.Json.Nodes.JsonObject _bag = new();
/// <summary>Loads a model from a DeviceConfig JSON string, defaulting absent keys and retaining
/// every original key so fields this editor doesn't expose survive a load→save.</summary>
/// <param name="json">The raw DeviceConfig JSON string, or null for a new/empty device.</param>
/// <returns>The populated <see cref="S7DeviceModel"/>.</returns>
public static S7DeviceModel FromJson(string? json)
{
var o = TagConfigJson.ParseOrNew(json);
return new S7DeviceModel
{
Host = TagConfigJson.GetString(o, "Host") ?? "127.0.0.1",
Port = TagConfigJson.GetInt(o, "Port", 102),
Rack = TagConfigJson.GetInt(o, "Rack", 0),
Slot = TagConfigJson.GetInt(o, "Slot", 0),
_bag = o,
};
}
/// <summary>Serializes this model back to a DeviceConfig JSON string, writing the PascalCase endpoint
/// keys over the preserved key bag.</summary>
/// <returns>The serialised DeviceConfig JSON string.</returns>
public string ToJson()
{
TagConfigJson.Set(_bag, "Host", Host);
TagConfigJson.Set(_bag, "Port", Port);
TagConfigJson.Set(_bag, "Rack", Rack);
TagConfigJson.Set(_bag, "Slot", Slot);
return TagConfigJson.Serialize(_bag);
}
/// <summary>Validation hook; returns an error message or null when the model is valid.</summary>
/// <returns>An error message describing the validation failure, or <c>null</c> when the model is valid.</returns>
public string? Validate()
=> string.IsNullOrWhiteSpace(Host) ? "Host is required." : null;
}