namespace ErvProtocol { // STATUS(0x81) 1프레임을 디코드한 결과 (PC_ERV_Protocol.md 4장) // 필드는 raw 수치(byte/int). 소비자(WPF)가 필요 시 enum 으로 캐스팅. public sealed class StatusRecord { public byte Power; // 0/1 public byte RunMode; // 1환기 2자동 3공청 4바이패스 public byte AutoState; // 0분산 1집중 public byte FanMode; // 0~4 public byte SubMode; // 비트맵 bit0수면 bit1조리 bit2회복 public byte Hood; // 비트맵 bit0=연동Enable / bit1=연동운전중 / bit2=후드 통신연결(폴응답 생존) public bool HoodEnable => (Hood & 0x01) != 0; // 후드연동 활성 public bool HoodRunning => (Hood & 0x02) != 0; // 후드연동에 의한 운전중 public bool HoodConnected => (Hood & 0x04) != 0; // 후드 485 통신 연결됨(ERV가 폴 응답 수신중) public byte HystPreset; // 0 ECO 1 NORMAL 2 TURBO public int HystPm25; public int HystPm10; public int HystVoc; public int HystCo2; public int ErrorCode; // 비트맵 public byte Reset; // ERV 리셋 토글 0/1 public int ReserveRemainSec; // (꺼짐)예약 잔여 초 (0=예약없음) — STATUS 끝 블록 public readonly RoomRecord[] Rooms = new RoomRecord[4]; // 풍량 VSP 9엔트리 (VspInfo.Labels 순서: 환기1~4, 바이패스, 공청1~4) public readonly VspEntry[] Vsp = new VspEntry[9]; // 히스테리시스 프리셋별 데드밴드(하강) [0]=ECO [1]=NORMAL [2]=TURBO public readonly HystSet[] HystTable = new HystSet[3]; // 모드(프리셋)별 오염단계 임계 경계표 [0]=ECO [1]=NORMAL [2]=TURBO public readonly ThrSet[] ThrTable = new ThrSet[3]; public StatusRecord() { for (int i = 0; i < 4; i++) Rooms[i] = new RoomRecord(); for (int i = 0; i < 9; i++) Vsp[i] = new VspEntry(); for (int i = 0; i < 3; i++) HystTable[i] = new HystSet(); for (int i = 0; i < 3; i++) ThrTable[i] = new ThrSet(); } } // 히스테리시스 한 프리셋의 데드밴드(하강폭) public sealed class HystSet { public int Pm25; public int Pm10; public int Voc; public int Co2; } // 한 프리셋의 오염단계 임계(각 오염원별 레벨 1~4 상한 경계) public sealed class ThrSet { public int[] Co2 = new int[4]; // L1~L4 상한 public int[] Pm25 = new int[4]; public int[] Pm10 = new int[4]; public int[] Voc = new int[4]; } public sealed class VspEntry { public int Sa; // 급기 풍량 설정값 public int Ea; // 배기 풍량 설정값 } // 풍량 VSP 엔트리 인덱스 ↔ 라벨/group/index 매핑 (PC_ERV_Protocol.md 3.5) public static class VspInfo { public static readonly string[] Labels = { "환기1", "환기2", "환기3", "환기4", "바이패스", "공청1", "공청2", "공청3", "공청4" }; // InfluxDB 태그/JSON 용 ASCII 키 public static readonly string[] Keys = { "vent1", "vent2", "vent3", "vent4", "bypass", "air1", "air2", "air3", "air4" }; // group: 0 Vent / 1 Bypass / 2 AirClean public static readonly int[] Group = { 0, 0, 0, 0, 1, 2, 2, 2, 2 }; // index: Vent/AirClean 1~4, Bypass 1 public static readonly int[] Index = { 1, 2, 3, 4, 1, 1, 2, 3, 4 }; public const int Count = 9; } public sealed class RoomRecord { public byte Damper; // 비트맵 : bit0=급기(SA) 열림 / bit1=배기(EA) 열림 public bool DamperSa => (Damper & 0x01) != 0; // 급기 댐퍼 열림 public bool DamperEa => (Damper & 0x02) != 0; // 배기 댐퍼 열림 public int Pm25; public int Pm10; public int Voc; public int Co2; public byte AirQuality; // 1매우나쁨~4좋음 public byte LedDim; // 0~9 public int LoadScore; // 부하점수 public byte FinalVolume; // 최종풍량 public byte Temp; // 온도(℃) — STATUS 끝 블록(offset 230~) public byte Humi; // 습도(%) — STATUS 끝 블록(offset 230~) } }