@ -13,7 +13,6 @@ using System.Windows.Threading;
using SmartAquaViewer.Controls ;
using SmartAquaViewer.DataAnalysis ;
using SmartAquaViewer.Model ;
using static SmartAquaViewer . Model . Enums ;
namespace SmartAquaViewer.ViewModel
{
@ -22,6 +21,7 @@ namespace SmartAquaViewer.ViewModel
public string? Name { get ; init ; } // 바인딩 경로 키 (예: "Tank.DOValue")
public string? Display { get ; init ; } // UI 표시명 (예: "DO (mg/L)")
public Type ? DataType { get ; init ; } // typeof(double), typeof(DateTime) 등
public StepFieldKind Kind { get ; init ; }
}
public class MonitoringViewModel : INotifyPropertyChanged
@ -100,6 +100,22 @@ namespace SmartAquaViewer.ViewModel
}
}
private StepFieldKind _selectedKind = StepFieldKind . Sensor ; // 기본값은 센서
public StepFieldKind SelectedKind
{
get = > _selectedKind ;
set
{
if ( _selectedKind ! = value )
{
_selectedKind = value ;
OnPropertyChanged ( ) ;
// 라디오 변경 시 Y 후보 재구성
RebuildFieldCandidates ( ) ;
}
}
}
public bool IsTankAndLine
{
get = > SelectedTab . Equals ( MonitorTab . Tank ) & & SelectedGraphType . Equals ( GraphType . LINE ) ;
@ -209,6 +225,7 @@ namespace SmartAquaViewer.ViewModel
}
}
}
# endregion
public ICommand ChangeDrawerStatusCommand { get ; }
@ -272,6 +289,16 @@ namespace SmartAquaViewer.ViewModel
var showRegression = ShowRegression ;
GraphControlVM . SetScatterPlot ( WaterQualityList , xFieldScatter , yFiledScatter , markerSIze , showRegression ) ;
break ;
case GraphType . STEP :
var xFieldStep = SelectedXField ? . Name = = "RecordedTime" ? SelectedXField : null ;
var tFieldsStep = SelectedYFields ;
var yFiledStep = SelectedYField ;
var showMarkerStep = ShowMarkers ;
if ( SelectedKind . Equals ( StepFieldKind . Status ) )
GraphControlVM . SetStatusSeriesStopPlot ( WaterQualityList , yFiledStep , showMarkerStep ) ;
else
GraphControlVM . SetStepPlot ( WaterQualityList , SelectedTab , xFieldStep , tFieldsStep , showMarkerStep ) ;
break ;
default :
break ;
}
@ -322,30 +349,63 @@ namespace SmartAquaViewer.ViewModel
if ( SelectedTab = = MonitorTab . Tank )
{
AvailableFields . Add ( new FieldItem { Name = "Tank.Number" , Display = "수조" , DataType = typeof ( int ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.DOValue" , Display = "DO (mg/L)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.PH" , Display = "pH" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.ORP" , Display = "ORP (mV)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.Temperature" , Display = "온도 (℃)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.FlowRate" , Display = "유량 (m³/s)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.Number" , Display = "수조" , DataType = typeof ( int ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.DOValue" , Display = "DO (mg/L)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.PH" , Display = "pH" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.ORP" , Display = "ORP (mV)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.Temperature" , Display = "온도 (℃)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Tank.FlowRate" , Display = "유량 (m³/s)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
}
else if ( SelectedTab = = MonitorTab . Filter )
{
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpPH" , Display = "섬프 pH" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpORP" , Display = "섬프 ORP (mV)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpWaterLevel" , Display = "섬프 수위 (m)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpFlowRate" , Display = "섬프 유량 (m³/s)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpTemperature" , Display = "섬프 수온 (°C)" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.FlowRate" , Display = "순환펌프 유량" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.HeatPumpTemperature" , Display = "히트펌프 온도" , DataType = typeof ( double ) } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpPH" , Display = "섬프 pH" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpORP" , Display = "섬프 ORP (mV)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpWaterLevel" , Display = "섬프 수위 (m)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpFlowRate" , Display = "섬프 유량 (m³/s)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SumpTemperature" , Display = "섬프 수온 (°C)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.FlowRate" , Display = "순환펌프 유량" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.HeatPumpTemperature" , Display = "히트펌프 온도" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.SandFilterPower" , Display = "모래여과기 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.CirculationPumpPower" , Display = "순환펌프 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.InverterControllerStatus" , Display = "인버터 제어기 상태" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.HeatPumpPower" , Display = "히트펌프 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Filtering.AirBlowerPower" , Display = "에어브로와 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
}
else // Sterilizer
{
AvailableFields . Add ( new FieldItem { Name = "Sterilizing.OzoneDissolverPressure" , Display = "용해장치 압력 (kPa)" , DataType = typeof ( double ) } ) ;
// 필요한 다른 수치 필드들 추가
AvailableFields . Add ( new FieldItem { Name = "Sterilizing.OzoneDissolverPressure" , Display = "용해장치 압력 (kPa)" , DataType = typeof ( double ) , Kind = StepFieldKind . Sensor } ) ;
AvailableFields . Add ( new FieldItem { Name = "Sterilizing.OzoneGeneratorPower" , Display = "오존 발생기 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Sterilizing.OzoneDissolverPower" , Display = "오존용해장치 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AvailableFields . Add ( new FieldItem { Name = "Sterilizing.ExcessOzoneDestroyerPower" , Display = "배오존장치 전원" , DataType = typeof ( int ) , Kind = StepFieldKind . Status } ) ;
AddUvPowerFieldsPerId ( WaterQualityList ) ;
}
}
// rows: 현재 그리려는 데이터(필터링/정렬 반영된)
private void AddUvPowerFieldsPerId ( IEnumerable < WaterQualityVO > rows )
{
// 케이스 A: 한 행이 UV 한 대의 상태를 담는 스키마
var idsA = rows
. Select ( r = > r ? . Sterilizing ? . UVSterilizerId )
. Where ( id = > ! string . IsNullOrWhiteSpace ( id ) )
. Distinct ( )
. ToList ( ) ;
foreach ( var id in idsA )
{
// Name 규칙: "Sterilizing.UVSterilizerPower[id=XXX]"
AvailableFields . Add ( new FieldItem
{
Name = $"Sterilizing.UVSterilizerPower[id={id}]" ,
Display = $"자외선 살균기 {id} 전원" ,
DataType = typeof ( int ) ,
Kind = StepFieldKind . Status
} ) ;
}
}
// 그래프 타입이 바뀔 때 후보/기본 선택 재구성
private void RebuildFieldCandidates ( )
{
@ -364,9 +424,22 @@ namespace SmartAquaViewer.ViewModel
SelectedXField = AvailableFields . FirstOrDefault ( f = > f . DataType = = typeof ( DateTime ) )
? ? AvailableFields . FirstOrDefault ( ) ;
IEnumerable < FieldItem > src = AvailableFields . Where ( f = > f . Kind = = SelectedKind ) ;
if ( SelectedGraphType is GraphType . LINE or GraphType . SCATTER or GraphType . BOX )
{
// 수치형만 (LINE/SCATTER/BOX는 연속값 위주)
src = src . Where ( f = > f . DataType = = typeof ( double ) ) ;
}
else if ( SelectedGraphType = = GraphType . STEP )
{
// STEP은 상태 전환에 잘 맞음: int/bool 위주
src = src . Where ( f = > f . DataType = = typeof ( int ) | | f . DataType = = typeof ( bool ) | | f . DataType = = typeof ( double ) ) ;
// (상태가 double로 들어오는 경우도 있을 수 있어 double 허용)
}
// Y축 후보: 수치형
foreach ( var f in AvailableFields . Where ( f = > f . DataType = = typeof ( double ) ) )
YFieldCandidates . Add ( f ) ;
foreach ( var f in src ) YFieldCandidates . Add ( f ) ;
// 기본 선택 세팅 (타입별)
SelectedYFields . Clear ( ) ;