chore: HERV 통합 저장소 재초기화 커밋

손상된 .git 히스토리(missing tree)로 재초기화 후 작업트리 전체 커밋.
.claude/ 만 제외(로컬 에이전트 설정). 구 저장소 백업(.git_corrupt_backup/) 포함.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jeon
2026-06-16 09:29:03 +09:00
commit a502322188
630 changed files with 65126 additions and 0 deletions
@@ -0,0 +1,262 @@
# PCDashBoard ↔ ERV 통신 — API 함수 & 프로토콜 상세 (2026.06.07)
PC 대시보드(ErvDashboard) ↔ ERV 메인보드 통신을 **485 프로토콜을 그대로 사용하되 `IErvApi` 함수로 감싼**
구조(인프로세스 API 파사드)로 정리한 문서. 선로 통신은 변함없이 485 프레임이며, UI 코드는 바이트/프레임을
다루지 않고 의미 있는 API 함수만 호출한다.
---
## 0. 구조 개요
```
[MainWindow.xaml.cs (UI)]
│ _api.SetPower(true) / SetFan(2) / RequestStatus() ...
[IErvApi] ←─ 인터페이스 (TestProgram/PCDashBoard/Api/IErvApi.cs)
[SerialErvApi] ←─ 구현 (Api/SerialErvApi.cs)
│ CtrlFrame 으로 485 프레임 빌드 / FrameParser 로 STATUS 파싱
[SerialChannel] ── RS485 / USB-Serial ── [ERV 메인보드]
```
- 송신 : `IErvApi.SetXxx()``CtrlFrame.Xxx()``0xAA … CRC16` 프레임 생성 → 시리얼 전송
- 수신 : 시리얼 바이트 → `FrameParser``STATUS(0x81)` 디코드 → `StatusReceived(StatusRecord)` 이벤트
- UI 매핑 : `StatusRecord``DashboardState``StatusMapper.Apply()`(UI 측)가 담당 → API 는 UI 비종속
### 파일 구성
| 파일 | 역할 |
|---|---|
| `PCDashBoard/Api/IErvApi.cs` | 통신 API 인터페이스(함수/이벤트 정의) |
| `PCDashBoard/Api/SerialErvApi.cs` | RS485 구현(SerialChannel + FrameParser + CtrlFrame 내장) |
| `PCDashBoard/Api/StatusMapper.cs` | `StatusRecord → DashboardState` 매핑 |
| `PCDashBoard/Protocol/SerialChannel.cs` | 시리얼 포트 송수신(byte) |
| `ErvProtocol/CtrlFrame.cs` | PC→ERV 제어 프레임 빌더 |
| `ErvProtocol/StatusDecoder.cs` | ERV→PC STATUS 디코더 |
| `ErvProtocol/FrameParser.cs` | 0xAA/LEN/CRC 프레임 분리 |
| `ErvProtocol/Enums.cs` | RunMode/SubModeType/HystPreset/AirQuality/AutoState |
---
## 1. API 함수 (IErvApi)
### 1.1 연결
| 함수 / 속성 | 설명 |
|---|---|
| `bool Connect(string port, int baud)` | 시리얼 연결 (대시보드 기본 115200) |
| `void Disconnect()` | 연결 해제 |
| `bool IsConnected { get; }` | 연결 여부 |
| `static string[] SerialErvApi.GetAvailablePorts()` | 사용 가능한 COM 포트 목록 |
| `event Action<bool> ConnectionChanged` | 연결 상태 변경 통지 |
### 1.2 수신
| 함수 / 이벤트 | 설명 |
|---|---|
| `event Action<StatusRecord> StatusReceived` | STATUS(0x81) 디코드 완료 시 발생 |
| `event Action<string> Log` | 프레임 hex / 이벤트 로그 |
| `void RequestStatus()` | STATUS 1회 즉시 요청 (CMD 0x0A) |
| `bool GetRoomStatus(int room, out bool damperSa, out bool damperEa, out AirQuality airQuality, out int led)` | 최근 STATUS 기준 각실(room 1~4) 급기·배기 댐퍼/공기질/LED 조회. 수신 이력 없거나 room 범위 밖이면 false |
### 1.3 제어 함수 ↔ 프로토콜 CMD 매핑
| API 함수 | CMD | PAYLOAD | 비고 |
|---|---|---|---|
| `SetPower(bool on)` | 0x01 | `[onoff]` | 전원 ON/OFF |
| `SetRunMode(RunMode mode)` | 0x02 | `[mode]` | 환기/자동/공청/바이패스 |
| `SetFan(int speed)` | 0x03 | `[speed]` | 0~4, 자동모드 시 무시 |
| `SetSubMode(SubModeType type, bool on)` | 0x04 | `[type][onoff]` | 스마트수면/쾌적조리/안심회복 |
| `SetHood(bool on)` | 0x05 | `[onoff]` | 연동후드 |
| `SetHystPreset(HystPreset preset)` | 0x06 | `[preset]` | ECO/NORMAL/TURBO |
| `SetHystDeadband(int preset, int pm25, int pm10, int voc, int co2)` | 0x07 | `[preset][pm25(2)][pm10(2)][voc(2)][co2(2)]` | 프리셋별 히스(하강) 값 |
| `SetDiffuserDamper(int room, int type, bool open)` | 0x08 | `[room][type][onoff]` | room 1~4, type 0=급기(SA)/1=배기(EA) |
| `SetDiffuserLed(int room, int dim)` | 0x09 | `[room][dim]` | dim 0~9 |
| `RequestStatus()` | 0x0A | (없음) | 상태 요청 |
| `SetReset(bool on)` | 0x0B | `[onoff]` | ERV 리셋 토글 |
| `SetVsp(int group, int index, int sa, int ea)` | 0x0C | `[group][index][sa(2)][ea(2)]` | 풍량 VSP 1엔트리 |
| `SetHystThreshold(int preset, int pollutant, int l1, int l2, int l3, int l4)` | 0x0D | `[preset][pollutant][L1(2)][L2(2)][L3(2)][L4(2)]` | 오염단계 임계 |
| `SetReserve(int hours)` | 0x0E | `[hours]` | (꺼짐)예약 0~8시간(0=해제) |
- `room` : 1=거실, 2=침실1, 3=침실2, 4=침실3
- `type`(댐퍼) : 0=급기(SA) / 1=배기(EA)
- `group` : 0=환기(Vent) / 1=바이패스(Bypass) / 2=공청(AirClean)
- `pollutant` : 0=CO2 / 1=PM2.5 / 2=PM10 / 3=VOC
- 멀티바이트(2) 값은 **빅엔디안**
### 1.4 데모
| 함수 | 설명 |
|---|---|
| `void InjectDemoStatus(int tick)` | 합성 STATUS 를 수신 경로로 주입(시리얼 없이 UI 테스트) |
### 1.5 enum 정의 (ErvProtocol/Enums.cs)
```
RunMode : Off=0, Vent=1, Auto=2, AirClean=3, Bypass=4
AutoState : Distribute=0(분산), Focus=1(집중)
HystPreset : Eco=0, Normal=1, Turbo=2
AirQuality : VeryBad=1, Bad=2, Normal=3, Good=4
SubModeType : SmartSleep=1, ComfortCook=2, ReliefRecover=3
```
---
## 2. 사용법
### 2.1 초기화 / 이벤트 등록
```csharp
readonly DashboardState _state = new();
readonly IErvApi _api = new SerialErvApi();
// 로그 / 연결상태 / STATUS 수신
_api.Log += Log;
_api.ConnectionChanged += b => Dispatcher.BeginInvoke(() => OnConnectionChanged(b));
_api.StatusReceived += rec => Dispatcher.BeginInvoke(() =>
{
StatusMapper.Apply(rec, _state); // StatusRecord → UI 모델
LogStatusSnapshot();
});
```
> `SerialErvApi` 이벤트는 시리얼 수신(백그라운드) 스레드에서 발생하므로, UI 갱신은
> `Dispatcher.BeginInvoke` 로 마샬링한다.
### 2.2 연결 / 상태 요청
```csharp
var ports = SerialErvApi.GetAvailablePorts(); // COM 목록
_api.Connect("COM3", 115200); // 연결
_api.RequestStatus(); // 최초 STATUS 요청
...
_api.Disconnect();
```
### 2.3 제어 송신 (예)
```csharp
_api.SetPower(true); // 전원 ON
_api.SetRunMode(RunMode.Auto); // 자동
_api.SetFan(2); // 풍량 2단
_api.SetSubMode(SubModeType.ComfortCook, true); // 쾌적조리 ON
_api.SetHood(true); // 연동후드 ON
_api.SetReserve(3); // 3시간 후 꺼짐 예약
_api.SetDiffuserDamper(1, 0, true); // 거실 급기(SA) 댐퍼 열림
_api.SetDiffuserDamper(1, 1, false); // 거실 배기(EA) 댐퍼 닫힘
_api.SetDiffuserLed(2, 5); // 침실1 LED 디밍 5
// 풍량 VSP (환기2단 SA/EA)
_api.SetVsp(group:0, index:2, sa:63, ea:61);
// 히스테리시스
_api.SetHystPreset(HystPreset.Normal);
_api.SetHystDeadband(preset:1, pm25:2, pm10:5, voc:5, co2:50);
_api.SetHystThreshold(preset:1, pollutant:0 /*CO2*/, l1:700, l2:1000, l3:1300, l4:1600);
```
### 2.4 수신 처리
`StatusReceived``StatusMapper.Apply(rec, state)``DashboardState`(전원/모드/풍량/각실 센서·
댐퍼·LED·부하점수·온습도/VSP/히스테리시스/임계표) 전체가 갱신된다.
각실 일부 항목만 즉시 조회할 때는 `GetRoomStatus` 사용(최근 수신 STATUS 기준) :
```csharp
if (_api.GetRoomStatus(1, out bool sa, out bool ea, out AirQuality aq, out int led))
Console.WriteLine($"거실: 급기={(sa ? "" : "")} 배기={(ea ? "" : "")} 공기질={aq} LED={led}");
```
---
## 3. 프로토콜 상세
### 3.1 물리계층
- RS-485 (또는 USB-Serial), **115200 bps, 8 Data, None Parity, 1 Stop (N81)**
### 3.2 공통 프레임 (Rev2.0 — 244byte 고정)
```
+------+------+----------------+--------+--------+
| STX | CMD | DATA[240] | CRC_L | CRC_H |
+------+------+----------------+--------+--------+
0xAA 1B 240B 고정 16-bit CRC(LE)
```
| 필드 | 크기 | 설명 |
|---|---|---|
| STX | 1 | 고정 `0xAA` |
| CMD | 1 | 명령/응답 코드 |
| DATA | 240 | **고정 240byte.** 제어는 앞쪽 인자 + 나머지 `0` 패딩, ERV→PC 는 STATUS/ACK 데이터 |
| CRC | 2 | **CRC-16/MODBUS**(poly 0xA001, init 0xFFFF), **CMD~DATA(241byte)** 범위, **리틀엔디안** |
- **LEN 필드 폐기.** 모든 프레임은 항상 `1+1+240+2 = 244byte` 고정. 파서는 정해진 바이트 수만 읽고 CRC 검증.
- 멀티바이트 수치는 **빅엔디안**(CRC만 리틀엔디안)
- 프레임 동기 : STX(0xAA) 탐색 + 고정길이 수신 + CRC 검증. 60ms 이상 바이트 공백 시 파서 리셋.
### 3.3 명령 코드
**PC → ERV (제어)** : 1.3 표 참조 (0x01~0x0E)
**ERV → PC (상태/응답)**
| CMD | 이름 | PAYLOAD | 설명 |
|---|---|---|---|
| 0x81 | STATUS | DATA 240 byte (3.5) | 전체 상태 스냅샷 (주기 송신 + REQ_STATUS 응답) |
| 0x82 | ACK | DATA `[echoCmd][result]` + 0패딩 | 제어 수신 응답 result 0=OK / 1=ERR |
### 3.4 값 정의
- 운전모드 : 0 OFF / 1 환기 / 2 자동 / 3 공청 / 4 바이패스
- 부가모드 type : 1 스마트수면 / 2 쾌적조리 / 3 안심회복 (STATUS subMode 는 비트맵 bit0/1/2)
- 공기질 : 1 매우나쁨(빨강) / 2 나쁨(주황) / 3 보통(초록) / 4 좋음(파랑)
- 자동상태 : 0 분산 / 1 집중
- 히스 프리셋 : 0 ECO / 1 NORMAL / 2 TURBO
### 3.5 STATUS(0x81) PAYLOAD 레이아웃 — **총 240 byte**
| 블록 | offset | 크기 | 내용 |
|---|---|---|---|
| 글로벌 | 0~16 | 17 | power, runMode, autoState, fanMode, subMode, hood, hystPreset, hystPM25(7,2), hystPM10(9,2), hystVOC(11,2), hystCO2(13,2), errorCode(15,2) |
| 각실 ×4 | 17~72 | 14×4=56 | 거실→침실1→2→3, 아래 표 |
| 리셋 | 73 | 1 | reset 토글 0/1 |
| VSP | 74~109 | 4×9=36 | 환기1~4, 바이패스, 공청1~4 의 SA(2)+EA(2) |
| 히스 프리셋표 | 110~133 | 8×3=24 | ECO/NORMAL/TURBO 의 PM2.5(2)/PM10(2)/VOC(2)/CO2(2) |
| 오염단계 임계표 | 134~229 | 32×3=96 | 프리셋×[CO2,PM2.5,PM10,VOC] 각 L1~L4 u16 |
| 각실 온습도 ×4 | 230~237 | 2×4=8 | 실별 Temp(1)+Humi(1) |
| (꺼짐)예약 | 238~239 | 2 | 잔여 초 u16 (0=예약없음) |
**각실 블록(14 byte) 상세** (상대 offset)
| +off | 크기 | 필드 |
|---|---|---|
| +0 | 1 | damper 비트맵 (bit0 급기 열림 / bit1 배기 열림) |
| +1 | 2 | pm25 |
| +3 | 2 | pm10 |
| +5 | 2 | voc |
| +7 | 2 | co2 |
| +9 | 1 | airQuality (3.4) |
| +10 | 1 | ledDim (0~9) |
| +11 | 2 | loadScore (부하점수) |
| +13 | 1 | finalVolume (최종풍량) |
**오염단계 임계표(프리셋당 32 byte)** : `CO2[L1..L4]` `PM2.5[L1..L4]` `PM10[L1..L4]` `VOC[L1..L4]` 순, 각 u16(빅엔디안).
> 계산식 : 17 + 56 + 1 + 36 + 24 + 96 + 8 + 2 = **240**
### 3.6 동작 시나리오
1. 연결 후 `RequestStatus()(0x0A)` 송신 → ERV 가 `STATUS(0x81)` 응답.
2. ERV 는 약 500ms~1s 주기로 `STATUS` 자동 송신 → 대시보드 실시간 갱신.
3. PC 제어 시 해당 `CTRL_*` 송신 → ERV 가 `ACK(0x82)` + 다음 STATUS 에 반영.
4. PC 는 STATUS 수신 시마다 로그(시각 + 전체 상태) 적재.
---
## 4. 비고
- 본 문서의 API(IErvApi) 도입은 **전송 방식(485 프로토콜)을 바꾸지 않는다.** 호출부를 함수로 캡슐화한 것.
- `IErvApi` 는 인터페이스이므로, 향후 다른 전송(예: HTTP) 구현(`HttpErvApi`)을 추가해 설정으로 교체 가능.
- 펌웨어(UART1/HOMENET_485) 세부 필드는 상호 합의하여 조정한다. (원본 초안: `TestProgram/PC_ERV_Protocol.md`)
+207
View File
@@ -0,0 +1,207 @@
# HuevenEco DL 각실제어 대시보드 ↔ ERV 메인보드 통신 프로토콜 (Rev2.0 고정패킷)
- 물리계층 : RS-485 (또는 USB-Serial), **115200 bps, 8 Data, None Parity, 1 Stop (N81)**
- 역할 : PC 대시보드(Host) ↔ ERV 메인보드(Main Board)
- **Rev2.0 변경점** : 가변 길이(`LEN` 필드) 프레임을 폐기하고 **모든 프레임을 244byte 고정**으로 통일.
파서는 "STX 탐색 → 정해진 바이트 수만 읽기 → CRC 검증"으로 단순화된다. CMD 의미·STATUS 레이아웃·CRC 방식은 종전과 동일.
---
## 1. 공통 프레임 (244byte 고정)
```
+------+------+------------------+--------+--------+
| STX | CMD | DATA[240] | CRC_L | CRC_H |
+------+------+------------------+--------+--------+
0xAA 1B 240B 고정 16-bit CRC
```
| 필드 | 크기 | 설명 |
|----------|------|-------------------------------------------------------------|
| STX | 1 | 고정 `0xAA` |
| CMD | 1 | 명령/응답 코드 (2장) |
| DATA | 240 | **고정 240byte.** PC→ERV 제어는 앞쪽에 인자 + 나머지 `0` 패딩, ERV→PC 는 STATUS/ACK 데이터 |
| CRC | 2 | **CRC-16/MODBUS** (poly 0xA001, init 0xFFFF), **CMD~DATA(241byte)**, **리틀엔디안** |
- **LEN 필드 없음.** 모든 프레임은 정확히 `1+1+240+2 = 244byte`.
- 멀티바이트 수치는 모두 **빅엔디안(상위 바이트 먼저)** 으로 표기한다. (CRC만 리틀엔디안)
- 프레임 동기 : STX(0xAA) 탐색 후 고정 길이로 수신, CRC 로 검증. 바이트 공백(예 60ms) 발생 시 파서를 STX 탐색으로 리셋해 재동기.
---
## 2. 명령 코드 (CMD)
DATA 앞쪽에 아래 인자를 싣고 나머지는 `0` 으로 패딩한다.
### 2.1 PC → ERV (제어)
| CMD | 이름 | DATA 앞쪽 인자 | 설명 |
|------|-----------------|-------------------------------------------|-----------------------------------|
| 0x01 | CTRL_POWER | `[onoff]` | 전원 0=OFF / 1=ON |
| 0x02 | CTRL_RUNMODE | `[mode]` | 운전모드 (3.1 참조) |
| 0x03 | CTRL_FAN | `[speed]` | 풍량 0~4 (자동모드에서는 무시) |
| 0x04 | CTRL_SUBMODE | `[type][onoff]` | 부가모드 토글 (3.2 참조) |
| 0x05 | CTRL_HOOD | `[onoff]` | 연동후드 0=OFF / 1=ON |
| 0x06 | CTRL_HYST_PRESET| `[preset]` | 히스테리시스 프리셋 0=ECO/1=NORMAL/2=TURBO |
| 0x07 | CTRL_HYST_VALUE | `[preset][pm25(2)][pm10(2)][voc(2)][co2(2)]` | 프리셋별 히스(하강) 데드밴드 설정 (값 BE) |
| 0x08 | CTRL_DAMPER | `[room][type][onoff]` | 각실 댐퍼 type 0=급기(SA)/1=배기(EA), 0=닫힘 / 1=열림 |
| 0x09 | CTRL_LED | `[room][dim]` | 각실 LED 디밍 0~9 |
| 0x0A | REQ_STATUS | (없음, 전부 0) | 상태 1회 즉시 요청 |
| 0x0B | CTRL_RESET | `[onoff]` | ERV 리셋 토글 0/1 |
| 0x0C | CTRL_VSP | `[group][index][sa(2)][ea(2)]` | 풍량 VSP 값 설정 (3.5 참조, sa/ea BE) |
| 0x0D | CTRL_HYST_THR | `[preset][pollutant][L1(2)][L2(2)][L3(2)][L4(2)]` | 오염단계 임계 설정 (pollutant 0=CO2/1=PM2.5/2=PM10/3=VOC, 값 BE) |
| 0x0E | CTRL_RESERVE | `[hours]` | (꺼짐)예약 0~8시간(0=해제) |
- `room` : 1=거실, 2=침실1, 3=침실2, 4=침실3
### 2.2 ERV → PC (상태/응답)
| CMD | 이름 | DATA | 설명 |
|------|-----------|--------------------|---------------------------------------------|
| 0x81 | STATUS | 240byte (4장 참조) | 전체 상태 스냅샷 (주기 송신 + REQ_STATUS 응답) |
| 0x82 | ACK | `[echoCmd][result]` + 0패딩 | 제어 명령 수신 응답 result 0=OK / 1=ERR |
---
## 3. 값 정의
### 3.1 운전모드 (RunMode)
| 코드 | 의미 | 펌웨어 매핑 |
|------|--------|----------------------------|
| 0x00 | OFF | Power_On = 0 |
| 0x01 | 환기 | MODE_VENTILATION (0) |
| 0x02 | 자동 | MODE_AUTO (1) |
| 0x03 | 공청 | MODE_AIRCLEAN (2) |
| 0x04 | 바이패스 | MODE_BYPASS (3) |
### 3.2 부가모드 (SubMode)
`CTRL_SUBMODE``type` :
| type | 의미 | 펌웨어 매핑 |
|------|------------|----------------------|
| 0x01 | 스마트수면 | Ext_Run_Mode = 4 |
| 0x02 | 쾌적조리 | Hood_YeunDong_Enable |
| 0x03 | 안심회복 | Ext_Run_Mode = 1 |
STATUS 의 `subMode` 는 비트맵 : bit0=스마트수면, bit1=쾌적조리, bit2=안심회복
### 3.3 공기질 상태 (AirQuality)
| 코드 | 등급 | 색상 |
|------|-----------|--------|
| 0x01 | 매우나쁨 | 빨강 |
| 0x02 | 나쁨 | 주황 |
| 0x03 | 보통 | 초록 |
| 0x04 | 좋음 | 파랑 |
### 3.4 자동운전 상태 (AutoState)
| 코드 | 의미 |
|------|--------|
| 0x00 | 분산 |
| 0x01 | 집중 |
### 3.5 풍량 VSP (CTRL_VSP 0x0C / STATUS VSP 블록)
급기(SA)/배기(EA) 풍량 설정값. `CTRL_VSP` 로 한 엔트리씩 설정, STATUS 로 전체 표시.
- `group` : `0`=환기(Vent), `1`=바이패스(Bypass), `2`=공청(AirClean)
- `index` : 환기/공청 `1~4`, 바이패스 `1`
- `sa`,`ea` : 각 **u16 빅엔디안**
**STATUS VSP 9 엔트리 순서** (각 SA,EA): `환기1, 환기2, 환기3, 환기4, 바이패스, 공청1, 공청2, 공청3, 공청4`
---
## 4. STATUS(0x81) DATA 레이아웃 (240 byte)
| 블록 | offset | 크기 | 내용 |
|---|---|---|---|
| 글로벌 | 0~16 | 17 | power, runMode, autoState, fanMode, subMode, hood, hystPreset, hystPM25(7,2), hystPM10(9,2), hystVOC(11,2), hystCO2(13,2), errorCode(15,2) |
| 각실 ×4 | 17~72 | 14×4=56 | 거실→침실1→2→3, 4.2 표 |
| 리셋 | 73 | 1 | reset 토글 0/1 |
| VSP | 74~109 | 4×9=36 | 환기1~4, 바이패스, 공청1~4 의 SA(2)+EA(2) |
| 히스 프리셋표 | 110~133 | 8×3=24 | ECO/NORMAL/TURBO 의 PM2.5(2)/PM10(2)/VOC(2)/CO2(2) |
| 오염단계 임계표 | 134~229 | 32×3=96 | 프리셋×[CO2,PM2.5,PM10,VOC] 각 L1~L4 u16 |
| 각실 온습도 ×4 | 230~237 | 2×4=8 | 실별 Temp(1)+Humi(1) |
| (꺼짐)예약 | 238~239 | 2 | 잔여 초 u16 (0=예약없음) |
> 계산식 : 17 + 56 + 1 + 36 + 24 + 96 + 8 + 2 = **240 byte**
### 4.1 글로벌 (offset 0~16, 17 byte)
| off | 크기 | 필드 | 비고 |
|-----|------|---------------|----------------------------------------|
| 0 | 1 | power | Power_On |
| 1 | 1 | runMode | 3.1 |
| 2 | 1 | autoState | 3.4 (분산/집중) |
| 3 | 1 | fanMode | 0~4 (Fan_Mode) |
| 4 | 1 | subMode | 비트맵 (3.2) |
| 5 | 1 | hood | bit0 Hood_YeunDong_Enable / bit1 Hood_Status |
| 6 | 1 | hystPreset | 0 ECO / 1 NORMAL / 2 TURBO |
| 7 | 2 | hystPM25 | 활성 프리셋 데드밴드 PM2.5 |
| 9 | 2 | hystPM10 | 활성 프리셋 데드밴드 PM10 |
| 11 | 2 | hystVOC | 활성 프리셋 데드밴드 VOC |
| 13 | 2 | hystCO2 | 활성 프리셋 데드밴드 CO2 |
| 15 | 2 | errorCode | 비트맵 (Err_Code) |
### 4.2 각실 블록 (offset 17~, 14 byte × 4실 = 56 byte)
순서: 거실 → 침실1 → 침실2 → 침실3
| off(상대) | 크기 | 필드 | 비고 |
|-----------|------|-------------|-----------------------------------|
| +0 | 1 | damper | 비트맵 bit0=급기(SA) 열림 / bit1=배기(EA) 열림 |
| +1 | 2 | pm25 | SEN66_pm2p5 |
| +3 | 2 | pm10 | SEN66_pm10p0 |
| +5 | 2 | voc | SEN66_VOC_value |
| +7 | 2 | co2 | SEN66_CO2_value |
| +9 | 1 | airQuality | 3.3 |
| +10 | 1 | ledDim | 0~9 (Light_Bright) |
| +11 | 2 | loadScore | 각실 부하점수 (Room_Level) |
| +13 | 1 | finalVolume | 최종 풍량 (Fan_Mode) |
### 4.3 VSP 블록 (offset 74~109, 9엔트리 × SA(2)·EA(2) = 36 byte)
순서(3.5): 환기1~4 → 바이패스 → 공청1~4. 각 엔트리 SA(2) + EA(2), 빅엔디안.
### 4.4 히스 데드밴드 프리셋표 (offset 110~133, 3프리셋 × PM2.5/PM10/VOC/CO2 u16 = 24 byte)
프리셋(ECO/NORMAL/TURBO)별 하강 데드밴드. 현재 적용값은 글로벌 `hystPM25~hystCO2`(off 7~14) = 본 표의 `[hystPreset]` 행.
### 4.5 오염단계 임계표 (offset 134~229, 3프리셋 × 32byte = 96 byte)
프리셋당 `CO2[L1..L4]` `PM2.5[L1..L4]` `PM10[L1..L4]` `VOC[L1..L4]` 순, 각 u16(빅엔디안).
### 4.6 각실 온습도 (offset 230~237, 4실 × Temp(1)+Humi(1) = 8 byte)
순서: 거실 → 침실1 → 침실2 → 침실3. 디퓨저 SEN66 값, 0~255 클램프.
### 4.7 (꺼짐)예약 잔여초 (offset 238~239, u16 BE)
전원 자동 OFF 까지 잔여 초. 0 = 예약 없음.
---
## 5. 동작 시나리오
1. PC 연결 후 `REQ_STATUS(0x0A)` 송신 → ERV 가 `STATUS(0x81)` 응답.
2. ERV 는 약 500ms~1s 주기로 `STATUS(0x81)` 를 자동 송신 (대시보드 실시간 갱신).
3. PC 가 토글/슬라이드/선택 시 해당 `CTRL_*` 송신 → ERV 가 `ACK(0x82)` + 다음 STATUS 에 반영.
4. PC 는 STATUS 수신 시마다 로그(날짜·시간 + 전체 상태)에 적재/저장.
---
## 6. 구현 매핑
| 계층 | 파일 | 역할 |
|---|---|---|
| 펌웨어 | `program/User/My_Homenet.c` | 244B 고정 프레임 수신/송신, CMD 적용, STATUS 빌드 |
| C# 공용 | `TestProgram/ErvProtocol/CtrlFrame.cs` | 244B 제어 프레임 빌더 |
| C# 공용 | `TestProgram/ErvProtocol/FrameParser.cs` | 고정 길이 프레임 분리 + CRC 검증 |
| C# 공용 | `TestProgram/ErvProtocol/StatusDecoder.cs` / `StatusEncoder.cs` | STATUS 240B 디코드/인코드 |
| C# 대시보드 | `TestProgram/PCDashBoard/Api/IErvApi.cs` / `SerialErvApi.cs` | API 파사드(함수 호출 → 프레임) |
> API 함수 목록·사용법은 `260607_PCDashBoard_API_및_프로토콜.md` 1·2장 참조. 본 문서가 와이어 프로토콜 정본이다.