Files
HECO2/TestProgram/PCDashBoard/MainWindow.xaml
T
jeon a502322188 chore: HERV 통합 저장소 재초기화 커밋
손상된 .git 히스토리(missing tree)로 재초기화 후 작업트리 전체 커밋.
.claude/ 만 제외(로컬 에이전트 설정). 구 저장소 백업(.git_corrupt_backup/) 포함.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:32:17 +09:00

356 lines
28 KiB
XML

<Window x:Class="ErvDashboard.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ErvDashboard"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="HuevenEco DL 각실제어시스템 대시보드"
Height="1000" Width="1600"
MinHeight="680" MinWidth="1080" MaxHeight="1200" MaxWidth="1920"
Background="{StaticResource AppBg}"
FontFamily="Segoe UI, Malgun Gothic">
<Window.Resources>
<local:AirQualityToBrushConverter x:Key="AqBrush"/>
<local:LevelToBrushConverter x:Key="LevelBrush"/>
<local:BoolToBrushConverter x:Key="OnOffBrush"/>
<local:BoolToOnOffConverter x:Key="OnOffText"/>
</Window.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- 헤더 + 통신 -->
<RowDefinition Height="*"/> <!-- 본문 -->
</Grid.RowDefinitions>
<!-- ============ 헤더 / 통신 ============ -->
<Border Grid.Row="0" Style="{StaticResource Card}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="HuevenEco DL 각실제어시스템"
FontSize="20" FontWeight="Bold" Foreground="{StaticResource TextPrimary}"/>
<TextBlock Text="각실제어 대시보드 · RS-485 115200 N81" FontSize="12"
Foreground="{StaticResource TextSecondary}"/>
</StackPanel>
<Border Width="1" Background="{StaticResource CardBorder}" Margin="14,4"/>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="만든이 : 전경선" FontSize="12" Foreground="{StaticResource TextSecondary}"/>
<TextBlock Text="만든날 : 2026.06.3" FontSize="12" Foreground="{StaticResource TextSecondary}"/>
</StackPanel>
</StackPanel>
<!-- 통신 제어 -->
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
<Ellipse x:Name="ConnLed" Width="12" Height="12" Fill="{StaticResource Bad}"
VerticalAlignment="Center" Margin="0,0,6,0"/>
<TextBlock x:Name="ConnText" Text="미연결" Style="{StaticResource FieldLabel}" Margin="0,0,12,0"/>
<TextBlock Text="포트" Style="{StaticResource FieldLabel}" Margin="0,0,6,0"/>
<ComboBox x:Name="PortCombo" Width="110" Margin="0,0,6,0"/>
<Button Content="↻" Style="{StaticResource FlatButton}" Click="RefreshPorts_Click" Padding="10,7"/>
<Button x:Name="ConnectBtn" Content="연결" Style="{StaticResource FlatButton}" Click="Connect_Click"/>
<Button x:Name="DisconnectBtn" Content="연결해제" Style="{StaticResource FlatButton}" Click="Disconnect_Click" IsEnabled="False"/>
<Border Width="1" Background="{StaticResource CardBorder}" Margin="6,2"/>
<Button x:Name="StartBtn" Content="통신시작" Style="{StaticResource FlatButton}" Click="StartComm_Click" IsEnabled="False"/>
<Button x:Name="StopBtn" Content="통신중지" Style="{StaticResource FlatButton}" Click="StopComm_Click" IsEnabled="False"/>
</StackPanel>
</Grid>
</Border>
<!-- ============ 본문 ============ -->
<Grid Grid.Row="1" Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<!-- 좌측: 제어 + 각실 -->
<ScrollViewer Grid.Column="0" VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- ERV 제어·상태 -->
<Border Style="{StaticResource Card}">
<StackPanel>
<TextBlock Text="ERV 제어 · 상태" Style="{StaticResource CardTitle}"/>
<!-- 전원 + 풍량 -->
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="전원" Style="{StaticResource FieldLabel}" Margin="0,0,8,0"/>
<Button x:Name="PowerBtn" Width="86" Content="OFF"
Style="{StaticResource FlatButton}" Click="Power_Click"/>
<TextBlock Text="ERV 리셋" Style="{StaticResource FieldLabel}" Margin="14,0,8,0"/>
<Button x:Name="ResetBtn" Width="86" Content="OFF"
Style="{StaticResource FlatButton}" Click="Reset_Click"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBlock Text="풍량" Style="{StaticResource FieldLabel}" Margin="0,0,8,0"/>
<!-- 풍량 0~4단. Tag=int(풍량 단수), Click=Fan_Click. 강조/활성은 RefreshControls 가 처리 -->
<StackPanel x:Name="FanPanel" Orientation="Horizontal">
<Button x:Name="Fan0" Content="0" Width="40" Style="{StaticResource FlatButton}" Click="Fan_Click">
<Button.Tag><sys:Int32>0</sys:Int32></Button.Tag>
</Button>
<Button x:Name="Fan1" Content="1" Width="40" Style="{StaticResource FlatButton}" Click="Fan_Click">
<Button.Tag><sys:Int32>1</sys:Int32></Button.Tag>
</Button>
<Button x:Name="Fan2" Content="2" Width="40" Style="{StaticResource FlatButton}" Click="Fan_Click">
<Button.Tag><sys:Int32>2</sys:Int32></Button.Tag>
</Button>
<Button x:Name="Fan3" Content="3" Width="40" Style="{StaticResource FlatButton}" Click="Fan_Click">
<Button.Tag><sys:Int32>3</sys:Int32></Button.Tag>
</Button>
<Button x:Name="Fan4" Content="4" Width="40" Style="{StaticResource FlatButton}" Click="Fan_Click">
<Button.Tag><sys:Int32>4</sys:Int32></Button.Tag>
</Button>
</StackPanel>
</StackPanel>
</Grid>
<!-- 운전모드. Tag=string(ModeDefs.tag), Click=Mode_Click. 순서는 코드의 ModeDefs 와 동일 -->
<TextBlock Text="운전모드" Style="{StaticResource FieldLabel}" Margin="0,0,0,4"/>
<StackPanel x:Name="ModePanel" Orientation="Horizontal" Margin="0,0,0,12">
<Button x:Name="ModeVent" Content="환기" Tag="Vent" Width="86" Style="{StaticResource FlatButton}" Click="Mode_Click"/>
<Button x:Name="ModeAuto" Content="자동" Tag="Auto" Width="86" Style="{StaticResource FlatButton}" Click="Mode_Click"/>
<Button x:Name="ModeAir" Content="공청" Tag="AirClean" Width="86" Style="{StaticResource FlatButton}" Click="Mode_Click"/>
<Button x:Name="ModeBypass" Content="바이패스" Tag="Bypass" Width="86" Style="{StaticResource FlatButton}" Click="Mode_Click"/>
<!-- (꺼짐)예약 0~8시간 : N시간 뒤 ERV 전원 OFF -->
<Border Width="1" Background="{StaticResource CardBorder}" Margin="14,2,14,2"/>
<TextBlock Text="(꺼짐)예약" Style="{StaticResource FieldLabel}" VerticalAlignment="Center" Margin="0,0,6,0"/>
<ComboBox x:Name="ReserveCombo" Width="78" VerticalAlignment="Center" SelectedIndex="0"
SelectionChanged="Reserve_Changed">
<ComboBoxItem Content="해제"/>
<ComboBoxItem Content="1시간"/>
<ComboBoxItem Content="2시간"/>
<ComboBoxItem Content="3시간"/>
<ComboBoxItem Content="4시간"/>
<ComboBoxItem Content="5시간"/>
<ComboBoxItem Content="6시간"/>
<ComboBoxItem Content="7시간"/>
<ComboBoxItem Content="8시간"/>
</ComboBox>
<TextBlock Text="{Binding ReserveText}" Style="{StaticResource FieldValue}"
VerticalAlignment="Center" Margin="10,0,0,0"/>
<!-- 설정 : 공기질 센서 히스테리시스 / 풍량 VSP -->
<Border Width="1" Background="{StaticResource CardBorder}" Margin="14,2,14,2"/>
<TextBlock Text="설정" Style="{StaticResource FieldLabel}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<Button Content="공기질 센서 히스테리시스 ▸" Style="{StaticResource FlatButton}" Click="OpenHyst_Click"/>
<Button Content="풍량 VSP ▸" Style="{StaticResource FlatButton}" Click="OpenVsp_Click" Margin="6,0,0,0"/>
</StackPanel>
<!-- 자동모드 프리셋 : 자동 선택 시에만 활성. 공기질 판정 임계(=히스테리시스 임계)를
선택 프리셋으로 전환. 기본값 표준(NORMAL). Tag=HystPreset 이름, Click=Preset_Click -->
<StackPanel x:Name="PresetPanel" Orientation="Horizontal" Margin="0,0,0,12">
<Button x:Name="PresetEco" Content="절전 (ECO)" Tag="Eco" Width="116" Style="{StaticResource FlatButton}" Click="Preset_Click"/>
<Button x:Name="PresetNormal" Content="표준 (NORMAL)" Tag="Normal" Width="116" Style="{StaticResource FlatButton}" Click="Preset_Click"/>
<Button x:Name="PresetTurbo" Content="쾌속 (TURBO)" Tag="Turbo" Width="116" Style="{StaticResource FlatButton}" Click="Preset_Click"/>
</StackPanel>
<!-- 시나리오모드 + 후드 연동 + 설정 (한 줄 배치) -->
<TextBlock Text="시나리오모드" Style="{StaticResource FieldLabel}" Margin="0,0,0,4"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
<Button x:Name="SmartSleepBtn" Content="스마트수면" Style="{StaticResource FlatButton}" Click="SubMode_Click" Tag="SmartSleep"/>
<Button x:Name="ComfortCookBtn" Content="쾌적조리" Style="{StaticResource FlatButton}" Click="SubMode_Click" Tag="ComfortCook"/>
<Button x:Name="ReliefRecoverBtn" Content="안심회복" Style="{StaticResource FlatButton}" Click="SubMode_Click" Tag="ReliefRecover"/>
<!-- 후드 연동 -->
<Border Width="1" Background="{StaticResource CardBorder}" Margin="14,2,14,2"/>
<TextBlock Text="후드 연동" Style="{StaticResource FieldLabel}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<Button x:Name="HoodBtn" Width="86" Content="OFF" Style="{StaticResource FlatButton}" Click="Hood_Click"/>
<!-- 후드 연동 ON 시 통신연결 상태 : 패킷 수신중 '후드 연결' / 없으면 '후드 연결 안됨' -->
<TextBlock x:Name="HoodConnText" Style="{StaticResource FieldValue}" FontSize="13"
VerticalAlignment="Center" Margin="8,0,0,0"/>
<!-- 스마트수면 시간설정 : 스마트수면 ON 일 때만 활성. 종료 시각 도달 시 자동 해제+이전모드 복귀 -->
<Border Width="1" Background="{StaticResource CardBorder}" Margin="14,2,14,2"/>
<Button x:Name="SmartSleepSetBtn" Content="스마트수면 시간설정 ▸" Style="{StaticResource FlatButton}"
Click="OpenSmartSleep_Click" IsEnabled="False"/>
</StackPanel>
</StackPanel>
</Border>
<!-- 자동운전 상태 -->
<Border Style="{StaticResource Card}">
<StackPanel>
<TextBlock Text="자동운전 상태 (표시 전용)" Style="{StaticResource CardTitle}"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="동작:" Style="{StaticResource FieldLabel}" Margin="0,0,6,0"/>
<Border Style="{StaticResource ReadOnlyBadge}">
<TextBlock Text="{Binding AutoStateText}" Style="{StaticResource FieldValue}" FontSize="13"/>
</Border>
<TextBlock Text="(분산 / 집중)" Style="{StaticResource FieldLabel}" Margin="8,0,0,0"/>
<TextBlock Text="합산부하점수:" Style="{StaticResource FieldLabel}" Margin="18,0,6,0"/>
<Border Style="{StaticResource ReadOnlyBadge}">
<TextBlock Text="{Binding TotalLoadScoreText}" Style="{StaticResource FieldValue}" FontSize="13"/>
</Border>
</StackPanel>
<TextBlock Text="각실 부하점수 / 최종 풍량" Style="{StaticResource FieldLabel}" Margin="0,0,0,6"/>
<ItemsControl ItemsSource="{Binding Rooms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="4"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{StaticResource Track}" CornerRadius="8" Margin="3" Padding="10,8">
<StackPanel>
<TextBlock Text="{Binding Name}" Style="{StaticResource FieldLabel}" HorizontalAlignment="Center"/>
<TextBlock HorizontalAlignment="Center" Style="{StaticResource FieldValue}" FontSize="22"
Text="{Binding LoadScore}"/>
<TextBlock HorizontalAlignment="Center" Style="{StaticResource FieldLabel}"
Text="{Binding FinalVolume, StringFormat=풍량 {0}}"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<!-- 각실 제어·상태 -->
<Border Style="{StaticResource Card}">
<StackPanel>
<TextBlock Text="각실 제어 · 상태" Style="{StaticResource CardTitle}"/>
<ItemsControl x:Name="RoomItems">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="4"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{StaticResource CardBg}" BorderBrush="{StaticResource CardBorder}"
BorderThickness="1" CornerRadius="10" Margin="3" Padding="10">
<StackPanel>
<!-- 헤더: 이름 + 공기질 LED -->
<Grid>
<TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"
Foreground="{StaticResource TextPrimary}" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<Ellipse Width="14" Height="14" Margin="0,0,6,0"
Fill="{Binding LoadScore, Converter={StaticResource LevelBrush}}"/>
<TextBlock Text="{Binding AirQualityText}" Style="{StaticResource FieldValue}" FontSize="13"/>
</StackPanel>
</Grid>
<!-- 댐퍼 토글 (급기/배기 분리, 2줄 배치) -->
<StackPanel Margin="0,10,0,6">
<StackPanel Orientation="Horizontal" Margin="0,0,0,6">
<TextBlock Text="급기댐퍼" Style="{StaticResource FieldLabel}" Width="60" VerticalAlignment="Center"/>
<Button Width="76" Tag="{Binding RoomId}" Click="DamperSa_Click"
Style="{StaticResource FlatButton}"
IsEnabled="{Binding DataContext.CanRoomControl, RelativeSource={RelativeSource AncestorType=Window}}"
Content="{Binding DamperSaOpen, Converter={StaticResource OnOffText}}"
Background="{Binding DamperSaOpen, Converter={StaticResource OnOffBrush}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="배기댐퍼" Style="{StaticResource FieldLabel}" Width="60" VerticalAlignment="Center"/>
<Button Width="76" Tag="{Binding RoomId}" Click="DamperEa_Click"
Style="{StaticResource FlatButton}"
IsEnabled="{Binding DataContext.CanRoomControl, RelativeSource={RelativeSource AncestorType=Window}}"
Content="{Binding DamperEaOpen, Converter={StaticResource OnOffText}}"
Background="{Binding DamperEaOpen, Converter={StaticResource OnOffBrush}}"/>
</StackPanel>
</StackPanel>
<!-- 센서값 -->
<UniformGrid Columns="2" Margin="0,0,0,4">
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="PM2.5" Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Pm25}" Style="{StaticResource FieldValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="PM10" Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Pm10}" Style="{StaticResource FieldValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="VOC" Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Voc}" Style="{StaticResource FieldValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="CO2" Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Co2}" Style="{StaticResource FieldValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="TEMP" Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Temp, StringFormat={}{0}℃}" Style="{StaticResource FieldValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2">
<TextBlock Text="HUMI." Style="{StaticResource FieldLabel}" Width="54"/>
<TextBlock Text="{Binding Humi, StringFormat={}{0}%}" Style="{StaticResource FieldValue}"/>
</StackPanel>
</UniformGrid>
<!-- LED 디밍 슬라이더 -->
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
<TextBlock Text="LED" Style="{StaticResource FieldLabel}" Width="44" VerticalAlignment="Center"/>
<!-- LED 디밍은 모든 운전모드·시나리오모드에서 변경 가능 (CanRoomControl 게이트 미적용).
드래그/트랙클릭/키보드 모두 전송 — DragStarted+DragCompleted+ValueChanged 조합 -->
<Slider Width="120" Minimum="0" Maximum="9" TickFrequency="1" IsSnapToTickEnabled="True"
IsMoveToPointEnabled="True"
VerticalAlignment="Center" Tag="{Binding RoomId}"
Value="{Binding LedDim, Mode=TwoWay}"
Thumb.DragStarted="Led_DragStarted"
Thumb.DragCompleted="Led_DragCompleted"
ValueChanged="Led_ValueChanged"/>
<TextBlock Text="{Binding LedDim}" Style="{StaticResource FieldValue}" Width="24"
TextAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<!-- 우측: 로그 -->
<Border Grid.Column="1" Style="{StaticResource Card}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Text="로그 데이터" Style="{StaticResource CardTitle}" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<CheckBox x:Name="AutoScrollChk" Content="자동스크롤" IsChecked="True"
Foreground="{StaticResource TextSecondary}" VerticalAlignment="Center" Margin="0,0,8,0"/>
<Button Content="📈 그래프" Style="{StaticResource FlatButton}" Click="OpenGraph_Click" Padding="10,5" Margin="0,0,6,0"/>
<Button Content="저장" Style="{StaticResource FlatButton}" Click="SaveLog_Click" Padding="10,5"/>
<Button Content="지움" Style="{StaticResource FlatButton}" Click="ClearLog_Click" Padding="10,5"/>
</StackPanel>
</Grid>
<Border Grid.Row="1" Background="{StaticResource Track}" CornerRadius="8" Margin="0,4">
<!-- 읽기전용 TextBox : 텍스트 드래그 선택 / Ctrl+C 복사 가능 (ERV 시뮬레이터 로그와 동일) -->
<TextBox x:Name="LogList" IsReadOnly="True" IsReadOnlyCaretVisible="False"
Background="Transparent" BorderThickness="0" Padding="6"
FontFamily="Consolas, D2Coding" FontSize="12"
Foreground="{StaticResource TextPrimary}"
TextWrapping="NoWrap"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/>
</Border>
<TextBlock x:Name="HexLine" Grid.Row="2" Style="{StaticResource FieldLabel}"
TextWrapping="Wrap" Margin="0,4,0,0"/>
</Grid>
</Border>
</Grid>
</Grid>
</Window>