using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.DeviceForms; /// /// Typed working model for an S7 Device's connection endpoint (the v3 endpoint→DeviceConfig /// split). Authors the PascalCase Host/Port/Rack/Slot keys that /// S7DriverOptions binds — the exact casing the seed and runtime probe /// (PropertyNameCaseInsensitive) expect. Preserves unrecognised keys across a load→save. /// public sealed class S7DeviceModel { /// PLC host / IP address. public string Host { get; set; } = "127.0.0.1"; /// ISO-on-TCP port (usually 102). public int Port { get; set; } = 102; /// PLC rack number (almost always 0). public int Rack { get; set; } = 0; /// PLC slot number (S7-300/400 = 2; S7-1200/1500 = 0). public int Slot { get; set; } = 0; private System.Text.Json.Nodes.JsonObject _bag = new(); /// 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. /// The raw DeviceConfig JSON string, or null for a new/empty device. /// The populated . 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, }; } /// Serializes this model back to a DeviceConfig JSON string, writing the PascalCase endpoint /// keys over the preserved key bag. /// The serialised DeviceConfig JSON string. 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); } /// Validation hook; returns an error message or null when the model is valid. /// An error message describing the validation failure, or null when the model is valid. public string? Validate() => string.IsNullOrWhiteSpace(Host) ? "Host is required." : null; }