From c75b708b00a9099e79892a71aaa6c2e9241300c0 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Sat, 17 Oct 2026 20:20:06 +0700 Subject: [PATCH 1/5] fix(ux): keep a nominal 4I4V display preset while waiting for publisher without inventing samples --- src/ProcessBus.Core/Models/SvEngineeringScale.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ProcessBus.Core/Models/SvEngineeringScale.cs b/src/ProcessBus.Core/Models/SvEngineeringScale.cs index 9f9bf89c..4ba7dfbb 100644 --- a/src/ProcessBus.Core/Models/SvEngineeringScale.cs +++ b/src/ProcessBus.Core/Models/SvEngineeringScale.cs @@ -12,6 +12,11 @@ public enum SvEngineeringScale public static class SvEngineeringScaleFactors { + // UI preset shown before any publisher is detected. It is not applied to + // an unknown stream until its decoded profile is verified or the operator + // explicitly selects nominal. No electrical values exist during idle. + public const SvEngineeringScale IdlePresentationDefault = SvEngineeringScale.Nominal4I4V; + // This explicitly opted-in 4I+4V lab/nominal profile is 1 mA per // current count and 10 mV per voltage count. It is NOT universal // IEC 61850 SV scaling and must never be auto-selected by svID. From 0304d3fd055eaa6215fbd04bd48ddaa3c18a442f Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Sat, 17 Oct 2026 20:21:04 +0700 Subject: [PATCH 2/5] fix(ux): show nominal display preset while awaiting SV and report waveform LIVE only for active selected stream --- .../ViewModels/MainWindowViewModel.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ProcessBus.App.Wpf/ViewModels/MainWindowViewModel.cs b/src/ProcessBus.App.Wpf/ViewModels/MainWindowViewModel.cs index 936b7ae1..5d03b610 100644 --- a/src/ProcessBus.App.Wpf/ViewModels/MainWindowViewModel.cs +++ b/src/ProcessBus.App.Wpf/ViewModels/MainWindowViewModel.cs @@ -110,6 +110,7 @@ private set _isRunning = value; OnPropertyChanged(); OnPropertyChanged(nameof(CanSwitchCaptureMode)); + OnPropertyChanged(nameof(IsSelectedSvReceiving)); } } @@ -764,6 +765,8 @@ public SvStreamItem? SelectedStream ApplySelectedStreamScale(value?.StreamId); OnPropertyChanged(nameof(SelectedEngineeringScale)); OnPropertyChanged(nameof(EngineeringScaleExplanation)); + OnPropertyChanged(nameof(CanSelectEngineeringScale)); + OnPropertyChanged(nameof(IsSelectedSvReceiving)); RestoreSelectedStreamWorkspace(value); OnPropertyChanged(); OnPropertyChanged(nameof(AnalogValues)); @@ -880,6 +883,11 @@ public int CurrentWorkspaceTabIndex public IReadOnlyList WaveformMarkerOptions { get; } = ["On", "Off"]; public IReadOnlyList EngineeringScaleOptions { get; } = [NominalScaleText, RawScaleText]; + // Before SV discovery this is a display preset only. No incoming samples, + // physical units or fabricated measurements are implied. + public bool CanSelectEngineeringScale => SelectedStream is not null; + public bool IsSelectedSvReceiving => IsRunning && SelectedStream is { IsActive: true }; + private SvEngineeringScale ResolveSelectedStreamScale(string streamId) { if (_explicitSvScales.TryGetValue(streamId, out var explicitMode)) @@ -899,8 +907,9 @@ details is not null && public string SelectedEngineeringScale { - get => SelectedStream is not null && - ResolveSelectedStreamScale(SelectedStream.StreamId) == SvEngineeringScale.Nominal4I4V + get => (SelectedStream is null + ? SvEngineeringScaleFactors.IdlePresentationDefault + : ResolveSelectedStreamScale(SelectedStream.StreamId)) == SvEngineeringScale.Nominal4I4V ? NominalScaleText : RawScaleText; set { @@ -925,7 +934,7 @@ public string SelectedEngineeringScale } public string EngineeringScaleExplanation => SelectedStream is null - ? "Select an SV stream to see its measurement units." + ? "Waiting for publisher. Nominal 4I+4V is a display preset, not a measurement; no values until recognized SV data arrives." : SelectedEngineeringScale == NominalScaleText ? "Assumed 4I+4V nominal: 1 mA / 10 mV per count. Display estimate only; not calibrated or SCL-verified. Choose Raw counts anytime." : "Raw SV counts: no electrical units inferred. Use nominal 4I+4V only when its layout is confirmed."; @@ -2182,6 +2191,8 @@ private void SynchronizeSelectedStreamRow() _selectedStream = refreshed; RestoreSelectedStreamWorkspace(refreshed); OnPropertyChanged(nameof(SelectedStream)); + OnPropertyChanged(nameof(IsSelectedSvReceiving)); + OnPropertyChanged(nameof(CanSelectEngineeringScale)); OnPropertyChanged(nameof(AnalogValues)); OnPropertyChanged(nameof(Phasors)); OnPropertyChanged(nameof(Waveform)); @@ -2218,6 +2229,8 @@ private void SyncUiSelectionToRuntimeStream(string? streamId) OnPropertyChanged(nameof(SelectedStream)); OnPropertyChanged(nameof(SelectedEngineeringScale)); OnPropertyChanged(nameof(EngineeringScaleExplanation)); + OnPropertyChanged(nameof(CanSelectEngineeringScale)); + OnPropertyChanged(nameof(IsSelectedSvReceiving)); } private void RestoreSelectedStreamWorkspace(SvStreamItem? stream) @@ -2546,6 +2559,7 @@ private void RaiseAll(DateTime now, bool force = false) { _lastGlobalRaiseUtc = now; OnPropertyChanged(nameof(StreamStatusText)); + OnPropertyChanged(nameof(IsSelectedSvReceiving)); OnPropertyChanged(nameof(OperatorCaptureSummaryText)); OnPropertyChanged(nameof(DataSourceName)); OnPropertyChanged(nameof(IsLiveMode)); From 599fa0a85b5591e582bc1f66d2c5548f9a7b1c17 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Sat, 17 Oct 2026 20:21:25 +0700 Subject: [PATCH 3/5] fix(ui): hide misleading waveform LIVE while no selected publisher and display nominal preset disabled until SV arrives --- src/ProcessBus.App.Wpf/MainWindow.xaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ProcessBus.App.Wpf/MainWindow.xaml b/src/ProcessBus.App.Wpf/MainWindow.xaml index 97dfe7b8..f51ea27b 100644 --- a/src/ProcessBus.App.Wpf/MainWindow.xaml +++ b/src/ProcessBus.App.Wpf/MainWindow.xaml @@ -2002,7 +2002,7 @@