@using System.Text.Json @using ZB.MOM.WW.OtOpcUa.Admin.Components.Pages.Modbus @using ZB.MOM.WW.OtOpcUa.Admin.Services @using ZB.MOM.WW.OtOpcUa.Configuration.Entities @inject DriverInstanceService DriverSvc @inject NamespaceService NsSvc

DriverInstances

@if (_drivers is null) {

Loading…

} else if (_drivers.Count == 0) {

No drivers configured in this draft.

} else {
Configured drivers
@foreach (var d in _drivers) { }
DriverInstanceIdNameTypeNamespace
@d.DriverInstanceId @d.Name @if (string.Equals(d.DriverType, "Focas", StringComparison.OrdinalIgnoreCase)) { @d.DriverType } else { @d.DriverType } @d.NamespaceId
} @if (_showForm && _namespaces is not null) {
Add driver
Type string must match the driver's registered factory name; this dropdown wraps the canonical names.
@if (string.Equals(_type, "Modbus", StringComparison.OrdinalIgnoreCase)) { @* #147 — typed editor for Modbus drivers. The generic textarea is a fall-back for driver types that haven't yet shipped a typed editor. *@ } else {
Phase 1: generic JSON editor — per-driver schema validation arrives in each driver's phase (decision #94).
}
@if (_error is not null) {
@_error
}
} @code { [Parameter] public long GenerationId { get; set; } [Parameter] public string ClusterId { get; set; } = string.Empty; private List? _drivers; private List? _namespaces; private bool _showForm; private string _name = string.Empty; private string _type = "Modbus"; private string _nsId = string.Empty; private string _config = "{}"; private string? _error; // #147 — typed editor model for Modbus drivers. Defaults match ModbusDriverOptions // defaults so an unedited form produces config equivalent to the historical // pre-typed-editor wire output. Serialised to _config on Save when type=Modbus. private ModbusOptionsEditor.ModbusOptionsViewModel _modbusOptions = new(); private static readonly JsonSerializerOptions ModbusJsonOptions = new() { WriteIndented = true }; protected override async Task OnParametersSetAsync() => await ReloadAsync(); private async Task ReloadAsync() { _drivers = await DriverSvc.ListAsync(GenerationId, CancellationToken.None); _namespaces = await NsSvc.ListAsync(GenerationId, CancellationToken.None); _nsId = _namespaces.FirstOrDefault()?.NamespaceId ?? string.Empty; } private async Task SaveAsync() { _error = null; if (string.IsNullOrWhiteSpace(_name) || string.IsNullOrWhiteSpace(_nsId)) { _error = "Name and Namespace are required"; return; } try { // #147 — for Modbus drivers serialize the typed editor model into the DriverConfig // JSON column. Other driver types still use the raw textarea contents until each // ships its own typed editor (decision #94 — per-driver schema validation arrives // per driver phase). var configJson = string.Equals(_type, "Modbus", StringComparison.OrdinalIgnoreCase) ? SerializeModbusOptions(_modbusOptions) : _config; await DriverSvc.AddAsync(GenerationId, ClusterId, _nsId, _name, _type, configJson, CancellationToken.None); _name = string.Empty; _config = "{}"; _modbusOptions = new(); _showForm = false; await ReloadAsync(); } catch (Exception ex) { _error = ex.Message; } } /// /// Maps the view-model field names onto the JSON shape ModbusDriverFactoryExtensions /// consumes. Hand-rolled because the DTO uses millisecond / byte field flavours that the /// view model exposes as TimeSpan-derived integers; a System.Text.Json round-trip would /// emit the .NET-native names instead. /// private static string SerializeModbusOptions(ModbusOptionsEditor.ModbusOptionsViewModel m) => JsonSerializer.Serialize(new { host = m.Host, port = m.Port, unitId = m.UnitId, family = m.Family.ToString(), melsecSubFamily = m.MelsecSubFamily.ToString(), keepAlive = new { enabled = m.KeepAliveEnabled, timeMs = m.KeepAliveTimeSec * 1000, intervalMs = m.KeepAliveIntervalSec * 1000, retryCount = m.KeepAliveRetryCount, }, reconnect = new { initialDelayMs = m.ReconnectInitialDelayMs, maxDelayMs = m.ReconnectMaxDelayMs, backoffMultiplier = m.ReconnectBackoffMultiplier, }, maxRegistersPerRead = m.MaxRegistersPerRead, maxRegistersPerWrite = m.MaxRegistersPerWrite, maxCoilsPerRead = m.MaxCoilsPerRead, maxReadGap = m.MaxReadGap, useFC15ForSingleCoilWrites = m.UseFC15ForSingleCoilWrites, useFC16ForSingleRegisterWrites = m.UseFC16ForSingleRegisterWrites, writeOnChangeOnly = m.WriteOnChangeOnly, tags = Array.Empty(), }, ModbusJsonOptions); }