846	    else if((Ext_Run_Mode == 2)&&(Pre_Ext_Run_Mode != 2)) //쾌적조리 En
847	    {
848	        Hood_YeunDong_Enable = 1;
849	        Pre_Ext_Run_Mode = Ext_Run_Mode ;
850	        Pre_Ext_Select_Room = Ext_Select_Room;
851	    }
852	    else if((Ext_Run_Mode == 3)&&(Pre_Ext_Run_Mode != 3)) //집중청정 모드
853	    {
854	        Memory_Diffuser_Dmp_Ang_SA[6] = 0;
855	        Memory_Diffuser_Dmp_Ang_SA[5] = 0;
856	        Memory_Diffuser_Dmp_Ang_SA[4] = 0;
857	        Memory_Diffuser_Dmp_Ang_SA[3] = 0;
858	        Memory_Diffuser_Dmp_Ang_SA[2] = 0;
859	        Memory_Diffuser_Dmp_Ang_SA[1] = 0;
860
861	        Memory_Diffuser_Dmp_Ang_RA[6] = 0;
862	        Memory_Diffuser_Dmp_Ang_RA[5] = 0;
863	        Memory_Diffuser_Dmp_Ang_RA[4] = 0;
864	        Memory_Diffuser_Dmp_Ang_RA[3] = 0;
865	        Memory_Diffuser_Dmp_Ang_RA[2] = 0;
866	        Memory_Diffuser_Dmp_Ang_RA[1] = 0;
867
868	        Memory_Diffuser_Dmp_Ang_SA[Ext_Select_Room] = 110;
869	        Memory_Diffuser_Dmp_Ang_RA[Ext_Select_Room] = 110;
870
871	        Diffuser_Air_quality[6] = 0;//OFF
872	        Diffuser_Air_quality[5] = 0;//OFF
873	        Diffuser_Air_quality[4] = 0;//OFF
874	        Diffuser_Air_quality[3] = 0;//OFF
875	        Diffuser_Air_quality[2] = 0;//OFF
876	        Diffuser_Air_quality[1] = 0;//OFF
877	        Diffuser_Air_quality[Ext_Select_Room] = 5;//ON
878
879	        Tmp_Air_Volume = 2;
880
881	        Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
882
883	        My_Memory_Run_Mode = Run_Mode;
884	        My_Memory_Fan_Mode = Fan_Mode;
885
886	        Set_Run_Mode =  MODE_VENTILATION;
887	        Set_Fan_Mode =  2;
888
889	        Pre_Ext_Run_Mode = Ext_Run_Mode ;
890	        Pre_Ext_Select_Room = Ext_Select_Room;
891	        goto PASS_VOLUME;
892	    }
893	    else if(Ext_Run_Mode == 4) //스마트 수면 모드 (사양서 8p) : 환기 수동·1단 고정, 실별 CO2 기준 댐퍼 개폐
894	    {
895	        if(Pre_Ext_Run_Mode != 4)   /* 진입 1회 : 모드/풍량 + 초기상태(거실 CLOSE, 침실1~3 OPEN) */
896	        {
897	            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
898
899	            My_Memory_Run_Mode = Run_Mode;
900	            My_Memory_Fan_Mode = Fan_Mode;
901
902	            Set_Run_Mode = MODE_VENTILATION;
903	            Set_Fan_Mode = 1;
904
905	            Memory_Diffuser_Dmp_Ang_SA[1] = 0;   Memory_Diffuser_Dmp_Ang_RA[1] = 0;   /* 거실 CLOSE */
906	            for(Room_Num = 2; Room_Num < 5; Room_Num++)                                /* 침실1~3 OPEN */
907	            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
908	            Memory_Diffuser_Dmp_Ang_SA[5] = 0; Memory_Diffuser_Dmp_Ang_RA[5] = 0;
909	            Memory_Diffuser_Dmp_Ang_SA[6] = 0; Memory_Diffuser_Dmp_Ang_RA[6] = 0;
910
911	            Pre_Ext_Run_Mode = Ext_Run_Mode;
912	            Pre_Ext_Select_Room = Ext_Select_Room;
913	        }
914
915	        /* 거실(room1)은 사양상 CO2 무관하게 항상 CLOSE → 매 틱 강제 닫음 */
916	        Memory_Diffuser_Dmp_Ang_SA[1] = 0; Memory_Diffuser_Dmp_Ang_RA[1] = 0;
917	        Diffuser_Air_quality[1] = 0;//OFF
918
919	        /* 매 틱 : 침실1~3(room2~4) 만 CO2 히스테리시스. CO2 >= 1000 OPEN, <= 800 CLOSE, 그 사이(데드존)는 현재 상태 유지 */
920	        for(Room_Num = 2; Room_Num < 5; Room_Num++)
921	        {
922	            if(SEN66_CO2_value[Room_Num] >= 1000)
923	            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
924	            else if(SEN66_CO2_value[Room_Num] <= 800)
925	            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;   Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0; }
926
927	            if((Memory_Diffuser_Dmp_Ang_SA[Room_Num] != 0)||(Memory_Diffuser_Dmp_Ang_RA[Room_Num] != 0))
928	                Diffuser_Air_quality[Room_Num] = 5;//ON
929	            else
930	                Diffuser_Air_quality[Room_Num] = 0;//OFF
931	        }
932
933	        Tmp_Air_Volume = 1;   /* 1단 고정 */
934	        Ext_Run_Mode_Off_Delay = 0;
935
936	        goto PASS_VOLUME;
937	    }
938	    else if((Ext_Run_Mode == 0)&&((Pre_Ext_Run_Mode == 1)||(Pre_Ext_Run_Mode == 3)||(Pre_Ext_Run_Mode == 4)))
939	    {
940	        if(Power_On == 1)
941	        {
942	            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
943
944	            Set_Run_Mode = My_Memory_Run_Mode;
945	            Set_Fan_Mode = My_Memory_Fan_Mode;
946
947	            Pre_Ext_Run_Mode = Ext_Run_Mode ;
948	            Pre_Ext_Select_Room = Ext_Select_Room;
949	        }
950	        Ext_Run_Mode_Off_Delay = 0;
951	    }
952	    else if((Ext_Run_Mode == 0)&&(Pre_Ext_Run_Mode == 2))// 쾌적조리(후드연동) 토글 OFF -> 연동 없음(사양 260613 9p 3.1)
953	    {
954	        Hood_YeunDong_Enable = 0;
955	        /* 메이크업 에어 동작중(후드 가동/롤백 유지)이었으면 본래 운전모드/풍량으로 즉시 복귀(롤백 딜레이 없음) */
956	        if((Power_On == 1)&&((Hood_Status != 0)||(Hood_Yeundong_flag != 0)||(Hood_Warming_up_Timer != 0)))
957	        {
958	            Set_Run_Mode = My_Memory_Run_Mode;
959	            Set_Fan_Mode = My_Memory_Fan_Mode;
960	            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
961	        }
962	        Hood_Yeundong_flag = 0;
963	        Hood_Warming_up_Timer = 0;
964	        Pre_Ext_Run_Mode = Ext_Run_Mode ;
965	        Pre_Ext_Select_Room = Ext_Select_Room;
966	        goto PASS_VOLUME;
967	    }
968	    else if((Ext_Run_Mode != 0)&&(Ext_Run_Mode != 2))
969	    {
970	        Pre_Ext_Run_Mode = Ext_Run_Mode ;
971	        Pre_Ext_Select_Room = Ext_Select_Room;
972	        if(Run_Mode != MODE_AUTO)goto PASS_VOLUME;
973	    }
974
975	    Total_CV_Mode_Factot = 0;

    else if((Ext_Run_Mode == 2)&&(Pre_Ext_Run_Mode != 2)) //쾌적조리 En
    {
        Hood_YeunDong_Enable = 1;
        Pre_Ext_Run_Mode = Ext_Run_Mode ;
        Pre_Ext_Select_Room = Ext_Select_Room;
    }
    else if((Ext_Run_Mode == 3)&&(Pre_Ext_Run_Mode != 3)) //집중청정 모드
    {
        Memory_Diffuser_Dmp_Ang_SA[6] = 0;
        Memory_Diffuser_Dmp_Ang_SA[5] = 0;
        Memory_Diffuser_Dmp_Ang_SA[4] = 0;
        Memory_Diffuser_Dmp_Ang_SA[3] = 0;
        Memory_Diffuser_Dmp_Ang_SA[2] = 0;
        Memory_Diffuser_Dmp_Ang_SA[1] = 0;

        Memory_Diffuser_Dmp_Ang_RA[6] = 0;
        Memory_Diffuser_Dmp_Ang_RA[5] = 0;
        Memory_Diffuser_Dmp_Ang_RA[4] = 0;
        Memory_Diffuser_Dmp_Ang_RA[3] = 0;
        Memory_Diffuser_Dmp_Ang_RA[2] = 0;
        Memory_Diffuser_Dmp_Ang_RA[1] = 0;

        Memory_Diffuser_Dmp_Ang_SA[Ext_Select_Room] = 110;
        Memory_Diffuser_Dmp_Ang_RA[Ext_Select_Room] = 110;

        Diffuser_Air_quality[6] = 0;//OFF
        Diffuser_Air_quality[5] = 0;//OFF
        Diffuser_Air_quality[4] = 0;//OFF
        Diffuser_Air_quality[3] = 0;//OFF
        Diffuser_Air_quality[2] = 0;//OFF
        Diffuser_Air_quality[1] = 0;//OFF
        Diffuser_Air_quality[Ext_Select_Room] = 5;//ON

        Tmp_Air_Volume = 2;

        Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);

        My_Memory_Run_Mode = Run_Mode;
        My_Memory_Fan_Mode = Fan_Mode;

        Set_Run_Mode =  MODE_VENTILATION;
        Set_Fan_Mode =  2;

        Pre_Ext_Run_Mode = Ext_Run_Mode ;
        Pre_Ext_Select_Room = Ext_Select_Room;
        goto PASS_VOLUME;
    }
    else if(Ext_Run_Mode == 4) //스마트 수면 모드 (사양서 8p) : 환기 수동·1단 고정, 실별 CO2 기준 댐퍼 개폐
    {
        if(Pre_Ext_Run_Mode != 4)   /* 진입 1회 : 모드/풍량 + 초기상태(거실 CLOSE, 침실1~3 OPEN) */
        {
            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);

            My_Memory_Run_Mode = Run_Mode;
            My_Memory_Fan_Mode = Fan_Mode;

            Set_Run_Mode = MODE_VENTILATION;
            Set_Fan_Mode = 1;

            Memory_Diffuser_Dmp_Ang_SA[1] = 0;   Memory_Diffuser_Dmp_Ang_RA[1] = 0;   /* 거실 CLOSE */
            for(Room_Num = 2; Room_Num < 5; Room_Num++)                                /* 침실1~3 OPEN */
            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
            Memory_Diffuser_Dmp_Ang_SA[5] = 0; Memory_Diffuser_Dmp_Ang_RA[5] = 0;
            Memory_Diffuser_Dmp_Ang_SA[6] = 0; Memory_Diffuser_Dmp_Ang_RA[6] = 0;

            Pre_Ext_Run_Mode = Ext_Run_Mode;
            Pre_Ext_Select_Room = Ext_Select_Room;
        }

        /* 거실(room1)은 사양상 CO2 무관하게 항상 CLOSE → 매 틱 강제 닫음 */
        Memory_Diffuser_Dmp_Ang_SA[1] = 0; Memory_Diffuser_Dmp_Ang_RA[1] = 0;
        Diffuser_Air_quality[1] = 0;//OFF

        /* 매 틱 : 침실1~3(room2~4) 만 CO2 히스테리시스. CO2 >= 1000 OPEN, <= 800 CLOSE, 그 사이(데드존)는 현재 상태 유지 */
        for(Room_Num = 2; Room_Num < 5; Room_Num++)
        {
            if(SEN66_CO2_value[Room_Num] >= 1000)
            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 110; Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 110; }
            else if(SEN66_CO2_value[Room_Num] <= 800)
            { Memory_Diffuser_Dmp_Ang_SA[Room_Num] = 0;   Memory_Diffuser_Dmp_Ang_RA[Room_Num] = 0; }

            if((Memory_Diffuser_Dmp_Ang_SA[Room_Num] != 0)||(Memory_Diffuser_Dmp_Ang_RA[Room_Num] != 0))
                Diffuser_Air_quality[Room_Num] = 5;//ON
            else
                Diffuser_Air_quality[Room_Num] = 0;//OFF
        }

        Tmp_Air_Volume = 1;   /* 1단 고정 */
        Ext_Run_Mode_Off_Delay = 0;

        goto PASS_VOLUME;
    }
    else if((Ext_Run_Mode == 0)&&((Pre_Ext_Run_Mode == 1)||(Pre_Ext_Run_Mode == 3)||(Pre_Ext_Run_Mode == 4)))
    {
        if(Power_On == 1)
        {
            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);

            Set_Run_Mode = My_Memory_Run_Mode;
            Set_Fan_Mode = My_Memory_Fan_Mode;

            Pre_Ext_Run_Mode = Ext_Run_Mode ;
            Pre_Ext_Select_Room = Ext_Select_Room;
        }
        Ext_Run_Mode_Off_Delay = 0;
    }
    else if((Ext_Run_Mode == 0)&&(Pre_Ext_Run_Mode == 2))// 쾌적조리(후드연동) 토글 OFF -> 연동 없음(사양 260613 9p 3.1)
    {
        Hood_YeunDong_Enable = 0;
        /* 메이크업 에어 동작중(후드 가동/롤백 유지)이었으면 본래 운전모드/풍량으로 즉시 복귀(롤백 딜레이 없음) */
        if((Power_On == 1)&&((Hood_Status != 0)||(Hood_Yeundong_flag != 0)||(Hood_Warming_up_Timer != 0)))
        {
            Set_Run_Mode = My_Memory_Run_Mode;
            Set_Fan_Mode = My_Memory_Fan_Mode;
            Command_request_type |= (TYPE_MODE|TYPE_FAN_SPEED);
        }
        Hood_Yeundong_flag = 0;
        Hood_Warming_up_Timer = 0;
        Pre_Ext_Run_Mode = Ext_Run_Mode ;
        Pre_Ext_Select_Room = Ext_Select_Room;
        goto PASS_VOLUME;
    }
    else if((Ext_Run_Mode != 0)&&(Ext_Run_Mode != 2))
    {
        Pre_Ext_Run_Mode = Ext_Run_Mode ;
        Pre_Ext_Select_Room = Ext_Select_Room;
        if(Run_Mode != MODE_AUTO)goto PASS_VOLUME;
    }

    Total_CV_Mode_Factot = 0;


개발사양서 연동매트릭스와 조금 다르게 동작해. 쾌적조리 선택 > 후드 on 후드 동작 > 후드 off > 쾌적조리 버튼 토글, 이전 모드 동작 후드 off 후 쾌적조리 버튼이 토글이 안돼.


HECO2 댐퍼 동작 문제 분석 및 비교


중요한 걸 찾았습니다. 정리하면 문제가 **두 겹**입니다.

## 1) 대시보드 (이미 수정함 — 재배포 필요)
앞서 고친 버튼 강조(`HoodRunning`→`ComfortCook`)가 "버튼이 토글 안 되는 것처럼 보임"의 직접 원인이었습니다. **publish 다시 해서(`dotnet publish ... ErvDashboard.csproj`) 새 exe로 테스트**해야 반영됩니다. 이전 빌드로 보고 계신 거면 그대로 안 바뀝니다.

## 2) 펌웨어 — 쾌적조리가 설계와 다르게 배선됨 (사양 매트릭스 불일치의 근원)
펌웨어를 보니 **쾌적조리 상태머신이 죽은 코드(dead code)** 입니다:

- `My_system.c`에 쾌적조리 **진입(846, `Ext_Run_Mode==2`)** 과 **해제(952, "사양 9p 3.1")** 상태머신이 작성돼 있는데,
- 정작 `Ext_Run_Mode`를 **2로 설정하는 곳이 펌웨어 어디에도 없습니다.** (안심회복=1, 스마트수면=4만 설정됨)
- 대시보드 쾌적조리(CTRL_SUBMODE type=2)는 [My_Homenet.c:318](Source/HECO2/User/My_Homenet.c#L318)에서 `Hood_YeunDong_Enable`을 **직접** 세팅 → 846/952 상태머신을 **건너뜀**.

즉 안심회복·스마트수면은 `Ext_Run_Mode` 상태머신으로 진입/해제·복귀가 일관되게 관리되는데, **쾌적조리만 그 틀을 벗어나** `Hood_YeunDong_Enable` 직접 제어 + My_Hood만으로 돌아갑니다. 그래서 952의 토글 OFF→연동해제·롤백 로직(사양 3.1 그대로 구현된 코드)이 **한 번도 실행되지 않습니다.**

## 권장 펌웨어 수정 (스펙·다른 시나리오와 일관)
CTRL_SUBMODE type=2를 다른 시나리오처럼 `Ext_Run_Mode`로 배선:
```c
// My_Homenet.c CTRL_SUBMODE
else if(pl[0] == 2) Ext_Run_Mode = pl[1] ? 2 : 0;   // was: Hood_YeunDong_Enable = pl[1] ? 1 : 0;
```
그러면 진입은 846(`Hood_YeunDong_Enable=1`), 해제는 952(`Hood_YeunDong_Enable=0` + 롤백)가 **설계대로** 돌아 토글·복귀가 사양 매트릭스와 일치합니다.

다만 확인할 점: 별도 **"연동후드" 버튼**([Hood_Click](TestProgram/PCDashBoard/MainWindow.xaml.cs#L444) → CTRL_HOOD)도 같은 `Hood_YeunDong_Enable`을 직접 건드립니다. 쾌적조리와 연동후드가 **같은 변수**라 중복/충돌 소지가 있습니다.

---

**진행 방향을 정해주세요:**
1. 먼저 **대시보드 재배포 후 재테스트** — 토글 표시가 정상인지 확인 (1번만으로 해결될 수도 있음).
2. 그래도 동작이 매트릭스와 다르면 **위 펌웨어 수정(type=2 → Ext_Run_Mode=2)** 적용.

어느 것부터 할까요? 아니면 2번(펌웨어)까지 한 번에 적용할까요? (연동후드 버튼 중복 처리도 같이 정리할지 알려주시면 반영하겠습니다.)


1. 재배포 후 테스트


대시보드를 재배포하겠습니다. CLAUDE.md의 publish 명령으로 단일 exe를 생성합니다.


Bash

cd /d/Project/nuvoton/HECO2/TestProgram/PCDashBoard && dotnet publish ErvDashboard.csproj -c Release -nologo 2>&1 | grep -iE "error|게시함|publish|\.exe|Release" | grep -ivE "NU1701" | tail -15; echo "---done---"

Publish PC dashboard release single exe


  ErvProtocol -> D:\Project\nuvoton\HECO2\TestProgram\ErvProtocol\bin\Release\net10.0\ErvProtocol.dll
  ErvDashboard -> D:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\ErvDashboard.dll
  ErvDashboard -> D:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish\
---done---


재배포 완료했습니다. 결과물을 확인합니다.


Confirm published exe exists


-rwxr-xr-x 1 전경선 197121 163266207 Jun 18 15:50 /d/Project/nuvoton/HECO2/TestProgram/PCDashBoard/bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe


재배포 완료했습니다 (오류 0). 방금 빌드된 새 exe:

`TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish\ErvDashboard.exe` (15:50 생성, 강조 수정 반영됨)

이 exe로 실행해서 테스트해 주세요:
- **쾌적조리 ON → 후드 ON(메이크업) → 후드 OFF(이전 모드 복귀) → 쾌적조리 버튼 다시 누름** 순서로,
- 누를 때마다 버튼 강조가 **즉시 ON/OFF로 토글되는지**, 그리고 OFF 누르면 연동 해제되는지 확인해 주세요.

확인 결과 알려주시면:
- 정상이면 → 대시보드 수정 마무리(원하시면 커밋).
- 여전히 매트릭스와 다르면 → 2번 펌웨어 수정(`type=2 → Ext_Run_Mode=2`)으로 넘어가겠습니다.


쾌적조리 버튼 디폴트는 비활성화인데 ..전원 on 하면 토글이 돼.아마 후드 연결이 되니 그런가 본데..
후드 연결하고..쾌적조리 버튼하고는 상관없어.
개발사양서 9페이지 연동 매트릭스도 그렇게 되어 있어.


쾌적조리 버튼의 활성/비활성이 전원·후드연결에 엮여 있는지 확인하겠습니다. UI 갱신부에서 전원/연결 기반으로 컨트롤을 막는 부분과 버튼 enable 로직을 봅니다.


505
506	        void SendLed(Slider s)
507	        {
508	            if (s.Tag is not int roomId) return;
509	            if (_suppressLed) return;   // STATUS 동기 적용 중 echo 차단
510	            int dim = (int)s.Value;
511	            // 직전 송신/수신값과 같으면 전송 안 함 — STATUS 역갱신이 유발한 ValueChanged(에코) 차단.
512	            // 사용자가 값을 실제로 바꾸면 dim 이 달라지므로 정상 전송됨.
513	            if (_lastLed.TryGetValue(roomId, out var last) && last == dim) return;
514	            if (_demoTimer.IsEnabled) return;
515	            if (!CanSend()) return;
516	            _api.SetDiffuserLed(roomId, dim);
517	            _lastLed[roomId] = dim;
518	            Log($"[제어] {_state.Room(roomId).Name} LED 디밍 → {dim}");
519	        }
520
521	        // ================= (꺼짐)예약 =================
522	        bool _suppressReserve;   // 상태→콤보 동기화 중 Reserve_Changed 재진입 차단
523	        void Reserve_Changed(object sender, SelectionChangedEventArgs e)
524	        {
525	            if (!IsLoaded || _suppressReserve) return;
526	            if (ReserveCombo.SelectedIndex < 0) return;
527	            int hours = ReserveCombo.SelectedIndex;   // 0=해제, 1~8시간
528	            if (_demoTimer.IsEnabled) { _state.ReserveRemainSec = hours * 3600; return; }
529	            if (!CanSend()) return;
530	            _api.SetReserve(hours);
531	            Log(hours == 0 ? "[제어] 예약 해제" : $"[제어] {hours}시간 후 꺼짐 예약");
532	        }
533
534	        // ================= 데모 모드 (버튼 제거됨 — 내부 합성 STATUS 경로는 비활성 상태로 유지) =================
535	        void DemoTick()
536	        {
537	            _api.InjectDemoStatus(_demoTick++);
538	        }
539
540	        // ================= UI 갱신 =================
541	        void RefreshControls()
542	        {
543	            // 전원
544	            SetToggle(PowerBtn, _state.PowerOn, "ON", "OFF");
545	            // ERV 리셋
546	            SetToggle(ResetBtn, _state.Reset, "ON", "OFF");
547	            // 연동후드 + 통신연결 상태 텍스트
548	            SetToggle(HoodBtn, _state.Hood, "ON", "OFF");
549	            if (_state.Hood)
550	            {
551	                HoodConnText.Text = _state.HoodConnected ? "후드 연결" : "후드 연결 안됨";
552	                HoodConnText.Foreground = _state.HoodConnected ? GoodBr : BadBr;
553	            }
554	            else
555	            {
556	                HoodConnText.Text = "";
557	            }
558
559	            // 운전모드 강조
560	            for (int i = 0; i < _modeButtons.Count; i++)
561	                SetActive(_modeButtons[i], ModeDefs[i].mode == _state.RunMode);
562
563	            // 풍량 : 현재 단수는 모드와 무관하게 항상 강조(자동은 ERV가 결정한 단수 표시).
564	            //   - 자동 : 수동 조절 불가(전 단 비활성)
565	            //   - 바이패스 : 최대 1단(2~4단 비활성)
566	            //   - 환기/공청 : 0~4단
567	            // 시나리오모드 활성 시: 운전모드·풍량·선택 안 된 시나리오모드 비활성화
568	            // 쾌적조리는 '연동운전중(HoodRunning=후드 가동중)' 기준으로 시나리오 활성 판단.
569	            // 후드 OFF(대기 상태)면 ERV는 본래 운전모드로 복귀하므로 운전모드를 다시 활성화해야 함(사양 3.1).
570	            bool subActive = _state.SmartSleep || _state.HoodRunning || _state.ReliefRecover;
571	            int fanMax = _state.RunMode == RunMode.Bypass ? 1 : 4;
572	            foreach (var fb in _fanButtons)
573	            {
574	                int sp = (int)fb.Tag!;
575	                fb.IsEnabled = !subActive && !_state.IsAuto && sp <= fanMax;
576	                SetActive(fb, sp == _state.FanMode);
577	            }
578
579	            // 시나리오모드
580	            SetActive(SmartSleepBtn,    _state.SmartSleep);
581	            // 쾌적조리는 사양 9p 3.1 의 'UI 토글(연동 스위치)' — 후드 가동중이 아니라 토글 ON/OFF(=Hood_YeunDong_Enable)를 강조.
582	            // (HoodRunning 으로 강조하면 대기/Roll-back 상태에서 버튼이 꺼져 보여 재선택 시 토글이 반대로 먹던 문제 수정)
583	            SetActive(ComfortCookBtn,   _state.ComfortCook);
584	            SetActive(ReliefRecoverBtn, _state.ReliefRecover);
585	            //   (활성 모드 버튼은 OFF 토글 가능해야 하므로 자기 자신은 유지)
586	            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
587	            ComfortCookBtn.IsEnabled   = !subActive || _state.ComfortCook;
588	            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;
589	            // 스마트수면 시간설정 버튼 : 스마트수면 ON 일 때만 활성

        void SendLed(Slider s)
        {
            if (s.Tag is not int roomId) return;
            if (_suppressLed) return;   // STATUS 동기 적용 중 echo 차단
            int dim = (int)s.Value;
            // 직전 송신/수신값과 같으면 전송 안 함 — STATUS 역갱신이 유발한 ValueChanged(에코) 차단.
            // 사용자가 값을 실제로 바꾸면 dim 이 달라지므로 정상 전송됨.
            if (_lastLed.TryGetValue(roomId, out var last) && last == dim) return;
            if (_demoTimer.IsEnabled) return;
            if (!CanSend()) return;
            _api.SetDiffuserLed(roomId, dim);
            _lastLed[roomId] = dim;
            Log($"[제어] {_state.Room(roomId).Name} LED 디밍 → {dim}");
        }

        // ================= (꺼짐)예약 =================
        bool _suppressReserve;   // 상태→콤보 동기화 중 Reserve_Changed 재진입 차단
        void Reserve_Changed(object sender, SelectionChangedEventArgs e)
        {
            if (!IsLoaded || _suppressReserve) return;
            if (ReserveCombo.SelectedIndex < 0) return;
            int hours = ReserveCombo.SelectedIndex;   // 0=해제, 1~8시간
            if (_demoTimer.IsEnabled) { _state.ReserveRemainSec = hours * 3600; return; }
            if (!CanSend()) return;
            _api.SetReserve(hours);
            Log(hours == 0 ? "[제어] 예약 해제" : $"[제어] {hours}시간 후 꺼짐 예약");
        }

        // ================= 데모 모드 (버튼 제거됨 — 내부 합성 STATUS 경로는 비활성 상태로 유지) =================
        void DemoTick()
        {
            _api.InjectDemoStatus(_demoTick++);
        }

        // ================= UI 갱신 =================
        void RefreshControls()
        {
            // 전원
            SetToggle(PowerBtn, _state.PowerOn, "ON", "OFF");
            // ERV 리셋
            SetToggle(ResetBtn, _state.Reset, "ON", "OFF");
            // 연동후드 + 통신연결 상태 텍스트
            SetToggle(HoodBtn, _state.Hood, "ON", "OFF");
            if (_state.Hood)
            {
                HoodConnText.Text = _state.HoodConnected ? "후드 연결" : "후드 연결 안됨";
                HoodConnText.Foreground = _state.HoodConnected ? GoodBr : BadBr;
            }
            else
            {
                HoodConnText.Text = "";
            }

            // 운전모드 강조
            for (int i = 0; i < _modeButtons.Count; i++)
                SetActive(_modeButtons[i], ModeDefs[i].mode == _state.RunMode);

            // 풍량 : 현재 단수는 모드와 무관하게 항상 강조(자동은 ERV가 결정한 단수 표시).
            //   - 자동 : 수동 조절 불가(전 단 비활성)
            //   - 바이패스 : 최대 1단(2~4단 비활성)
            //   - 환기/공청 : 0~4단
            // 시나리오모드 활성 시: 운전모드·풍량·선택 안 된 시나리오모드 비활성화
            // 쾌적조리는 '연동운전중(HoodRunning=후드 가동중)' 기준으로 시나리오 활성 판단.
            // 후드 OFF(대기 상태)면 ERV는 본래 운전모드로 복귀하므로 운전모드를 다시 활성화해야 함(사양 3.1).
            bool subActive = _state.SmartSleep || _state.HoodRunning || _state.ReliefRecover;
            int fanMax = _state.RunMode == RunMode.Bypass ? 1 : 4;
            foreach (var fb in _fanButtons)
            {
                int sp = (int)fb.Tag!;
                fb.IsEnabled = !subActive && !_state.IsAuto && sp <= fanMax;
                SetActive(fb, sp == _state.FanMode);
            }

            // 시나리오모드
            SetActive(SmartSleepBtn,    _state.SmartSleep);
            // 쾌적조리는 사양 9p 3.1 의 'UI 토글(연동 스위치)' — 후드 가동중이 아니라 토글 ON/OFF(=Hood_YeunDong_Enable)를 강조.
            // (HoodRunning 으로 강조하면 대기/Roll-back 상태에서 버튼이 꺼져 보여 재선택 시 토글이 반대로 먹던 문제 수정)
            SetActive(ComfortCookBtn,   _state.ComfortCook);
            SetActive(ReliefRecoverBtn, _state.ReliefRecover);
            //   (활성 모드 버튼은 OFF 토글 가능해야 하므로 자기 자신은 유지)
            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
            ComfortCookBtn.IsEnabled   = !subActive || _state.ComfortCook;
            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;
            // 스마트수면 시간설정 버튼 : 스마트수면 ON 일 때만 활성


쾌적조리 버튼 디폴트는 비활성화인데 ..전원 on 하면 토글이 돼.아마 후드 연결이 되니 그런가 본데.. 후드 연결하고..쾌적조리 버튼하고는 상관없어. 개발사양서 9페이지 연동 매트릭스도 그렇게 되어 있어.


전원/연결 기반으로 컨트롤을 막는 상위 게이트가 있는지 RefreshControls 나머지와 연결 처리부를 봅니다.


589	            // 스마트수면 시간설정 버튼 : 스마트수면 ON 일 때만 활성
590	            SmartSleepSetBtn.IsEnabled = _state.SmartSleep;
591	            foreach (var mb in _modeButtons) mb.IsEnabled = !subActive;
592
593	            // 자동모드 프리셋(ECO/NORMAL/TURBO) : 자동모드에서만 활성, 활성 프리셋 강조.
594	            // 선택 프리셋이 곧 공기질 판정 임계(=히스테리시스 임계). 기본값은 표준(NORMAL, 상태 초기값).
595	            // (HystWindow 팝업의 프리셋 버튼과 _state.HystPreset 으로 동기화)
596	            bool presetEnabled = _state.IsAuto && !subActive;
597	            var presets = new[] { HystPreset.Eco, HystPreset.Normal, HystPreset.Turbo };
598	            for (int i = 0; i < _presetButtons.Count; i++)
599	            {
600	                _presetButtons[i].IsEnabled = presetEnabled;
601	                SetActive(_presetButtons[i], presetEnabled && presets[i] == _state.HystPreset);
602	            }
603
604	            // (꺼짐)예약 : 만료(전원OFF)/해제 시 콤보를 '해제'로 되돌림
605	            if (_state.ReserveRemainSec == 0 && ReserveCombo.SelectedIndex != 0)
606	            {
607	                _suppressReserve = true;
608	                ReserveCombo.SelectedIndex = 0;
609	                _suppressReserve = false;
610	            }
611	        }
612
613	        void SetToggle(Button b, bool on, string onText, string offText)
614	        {
615	            b.Content = on ? onText : offText;
616	            b.Background = on ? Accent : CardBgBr;
617	            b.Foreground = on ? Brushes.White : TextPrimaryBr;
618	            b.BorderBrush = on ? Accent : CardBorderBr;
619	        }
620
621	        void SetActive(Button b, bool active)
622	        {
623	            b.Background = active ? Accent : CardBgBr;
624	            b.Foreground = active ? Brushes.White : TextPrimaryBr;
625	            b.BorderBrush = active ? Accent : CardBorderBr;
626	        }
627
628	        // ================= 로그 =================
629	        void LogStatusSnapshot()
630	        {
631	            // 사양서 로그 항목: 운전모드/풍량/연동, 자동상태(분산/집중), 각실 부하점수·풍량, 프리셋, 히스테리시스값, 각실 댐퍼/센서/공기질/LED
632	            var sb = new StringBuilder();
633	            sb.Append($"STATUS pwr={(_state.PowerOn ? "ON" : "OFF")} mode={_state.RunMode} fan={_state.FanMode} ");
634	            sb.Append($"hood={(_state.Hood ? 1 : 0)} sub=0x{_state.SubModeBitmap:X2} auto={_state.AutoStateText} ");
635	            sb.Append($"preset={_state.HystPreset} hyst[PM2.5={_state.HystPm25},PM10={_state.HystPm10},VOC={_state.HystVoc},CO2={_state.HystCo2}] ");
636	            sb.Append($"err={_state.ErrorCodeHex}");
637	            Log(sb.ToString());
638	            foreach (var r in _state.Rooms)
639	                Log($"  {r.Name}: 급기={(r.DamperSaOpen ? "O" : "X")} 배기={(r.DamperEaOpen ? "O" : "X")} PM2.5={r.Pm25} PM10={r.Pm10} VOC={r.Voc} CO2={r.Co2} " +
640	                    $"AQ={r.AirQualityText} LED={r.LedDim} load={r.LoadScore} vol={r.FinalVolume}");
641	        }
642
643	        void Log(string msg)
644	        {
645	            var line = $"[{DateTime.Now:HH:mm:ss.fff}] {msg}";
646	            Dispatcher.BeginInvoke(() =>
647	            {
648	                LogList.AppendText(line + Environment.NewLine);
649	                if (LogList.LineCount > 1000)   // 오래된 줄 정리(최근 600줄 유지)
650	                {
651	                    var lines = LogList.Text.Split(Environment.NewLine);
652	                    LogList.Text = string.Join(Environment.NewLine, lines[^600..]);
653	                }
654	                if (AutoScrollChk.IsChecked == true) LogList.ScrollToEnd();
655	            });
656	        }
657
658	        void ClearLog_Click(object sender, RoutedEventArgs e) => LogList.Clear();

            // 스마트수면 시간설정 버튼 : 스마트수면 ON 일 때만 활성
            SmartSleepSetBtn.IsEnabled = _state.SmartSleep;
            foreach (var mb in _modeButtons) mb.IsEnabled = !subActive;

            // 자동모드 프리셋(ECO/NORMAL/TURBO) : 자동모드에서만 활성, 활성 프리셋 강조.
            // 선택 프리셋이 곧 공기질 판정 임계(=히스테리시스 임계). 기본값은 표준(NORMAL, 상태 초기값).
            // (HystWindow 팝업의 프리셋 버튼과 _state.HystPreset 으로 동기화)
            bool presetEnabled = _state.IsAuto && !subActive;
            var presets = new[] { HystPreset.Eco, HystPreset.Normal, HystPreset.Turbo };
            for (int i = 0; i < _presetButtons.Count; i++)
            {
                _presetButtons[i].IsEnabled = presetEnabled;
                SetActive(_presetButtons[i], presetEnabled && presets[i] == _state.HystPreset);
            }

            // (꺼짐)예약 : 만료(전원OFF)/해제 시 콤보를 '해제'로 되돌림
            if (_state.ReserveRemainSec == 0 && ReserveCombo.SelectedIndex != 0)
            {
                _suppressReserve = true;
                ReserveCombo.SelectedIndex = 0;
                _suppressReserve = false;
            }
        }

        void SetToggle(Button b, bool on, string onText, string offText)
        {
            b.Content = on ? onText : offText;
            b.Background = on ? Accent : CardBgBr;
            b.Foreground = on ? Brushes.White : TextPrimaryBr;
            b.BorderBrush = on ? Accent : CardBorderBr;
        }

        void SetActive(Button b, bool active)
        {
            b.Background = active ? Accent : CardBgBr;
            b.Foreground = active ? Brushes.White : TextPrimaryBr;
            b.BorderBrush = active ? Accent : CardBorderBr;
        }

        // ================= 로그 =================
        void LogStatusSnapshot()
        {
            // 사양서 로그 항목: 운전모드/풍량/연동, 자동상태(분산/집중), 각실 부하점수·풍량, 프리셋, 히스테리시스값, 각실 댐퍼/센서/공기질/LED
            var sb = new StringBuilder();
            sb.Append($"STATUS pwr={(_state.PowerOn ? "ON" : "OFF")} mode={_state.RunMode} fan={_state.FanMode} ");
            sb.Append($"hood={(_state.Hood ? 1 : 0)} sub=0x{_state.SubModeBitmap:X2} auto={_state.AutoStateText} ");
            sb.Append($"preset={_state.HystPreset} hyst[PM2.5={_state.HystPm25},PM10={_state.HystPm10},VOC={_state.HystVoc},CO2={_state.HystCo2}] ");
            sb.Append($"err={_state.ErrorCodeHex}");
            Log(sb.ToString());
            foreach (var r in _state.Rooms)
                Log($"  {r.Name}: 급기={(r.DamperSaOpen ? "O" : "X")} 배기={(r.DamperEaOpen ? "O" : "X")} PM2.5={r.Pm25} PM10={r.Pm10} VOC={r.Voc} CO2={r.Co2} " +
                    $"AQ={r.AirQualityText} LED={r.LedDim} load={r.LoadScore} vol={r.FinalVolume}");
        }

        void Log(string msg)
        {
            var line = $"[{DateTime.Now:HH:mm:ss.fff}] {msg}";
            Dispatcher.BeginInvoke(() =>
            {
                LogList.AppendText(line + Environment.NewLine);
                if (LogList.LineCount > 1000)   // 오래된 줄 정리(최근 600줄 유지)
                {
                    var lines = LogList.Text.Split(Environment.NewLine);
                    LogList.Text = string.Join(Environment.NewLine, lines[^600..]);
                }
                if (AutoScrollChk.IsChecked == true) LogList.ScrollToEnd();
            });
        }

        void ClearLog_Click(object sender, RoutedEventArgs e) => LogList.Clear();


원인을 찾았습니다. 쾌적조리 버튼의 **활성/비활성**이 [MainWindow.xaml.cs:587](TestProgram/PCDashBoard/MainWindow.xaml.cs#L587)에서 `!subActive || _state.ComfortCook`로 묶여 있고, `subActive`에 **`HoodRunning`(후드 가동)** 이 포함됩니다. 그래서 후드 상태/연결에 따라 쾌적조리 버튼이 막힙니다.

사양 9p 3.1대로 쾌적조리는 **독립 토글 스위치**(후드 연결·가동, 다른 시나리오와 무관)여야 하므로, 이 버튼의 enable을 분리합니다:


Edit

            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
            ComfortCookBtn.IsEnabled   = !subActive || _state.ComfortCook;
            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;

            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
            // 쾌적조리는 사양 9p 3.1 의 '독립 토글(연동 스위치)' — 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능.
            ComfortCookBtn.IsEnabled   = true;
            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;


The file d:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\MainWindow.xaml.cs has been updated successfully. (file state is current in your context — no need to Read it back)

            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
            ComfortCookBtn.IsEnabled   = !subActive || _state.ComfortCook;
            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;

            SmartSleepBtn.IsEnabled    = !subActive || _state.SmartSleep;
            // 쾌적조리는 사양 9p 3.1 의 '독립 토글(연동 스위치)' — 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능.
            ComfortCookBtn.IsEnabled   = true;
            ReliefRecoverBtn.IsEnabled = !subActive || _state.ReliefRecover;

//   (활성 모드 버튼은 OFF 토글 가능해야 하므로 자기 자신은 유지)

-            ComfortCookBtn.IsEnabled   = !subActive || _state.ComfortCook;

+            // 쾌적조리는 사양 9p 3.1 의 '독립 토글(연동 스위치)' — 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능.

+            ComfortCookBtn.IsEnabled   = true;

// 스마트수면 시간설정 버튼 : 스마트수면 ON 일 때만 활성


이제 빌드 후 재배포합니다.


Bash

cd /d/Project/nuvoton/HECO2/TestProgram/PCDashBoard && dotnet publish ErvDashboard.csproj -c Release -nologo 2>&1 | grep -iE "error|publish\\\\$|->.*publish" | grep -ivE "NU1701"; echo "exit=$?"; ls -la "bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe"

Build and publish dashboard, verify exe


  ErvDashboard -> D:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish\
exit=0
-rwxr-xr-x 1 전경선 197121 163262111 Jun 18 15:55 bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe


수정 + 재배포 완료했습니다 (오류 0, exe 15:55 갱신).

## 원인 / 수정
쾌적조리 버튼의 활성 조건이 `!subActive || ComfortCook`였고, 여기서 `subActive`에 **`HoodRunning`(후드 가동중)** 이 포함돼 있어 후드 상태에 따라 버튼이 막혔습니다.

사양 9p 3.1대로 쾌적조리는 **독립 토글 스위치**이므로 [MainWindow.xaml.cs:587](TestProgram/PCDashBoard/MainWindow.xaml.cs#L587)을 항상 활성으로 변경:
```csharp
ComfortCookBtn.IsEnabled = true;   // 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능
```
(모드/풍량 버튼은 기존대로 `subActive`로 잠금 — 후드 가동중엔 ERV 제어를 무시하므로 사양 3.1에 맞음. 쾌적조리 버튼 자신만 분리.)

새 exe:
`TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish\ErvDashboard.exe`

이걸로 테스트해 주세요 — 후드 연결/전원 상태와 무관하게 쾌적조리 버튼이 항상 눌리고 토글되는지 확인 부탁드립니다.

## 참고 (관련, 아직 안 건드림)
`SubMode_Click`의 상호배타 로직([L401~406](TestProgram/PCDashBoard/MainWindow.xaml.cs#L401))은 여전히 쾌적조리를 스마트수면/안심회복과 배타 처리합니다(하나 켜면 쾌적조리 OFF). 사양상 쾌적조리는 독립이라 이것도 분리해야 완전히 맞습니다. 이 부분도 정리할까요?


대시보드 폴더 위치가 어디야..실행파일.


실행파일(단일 exe) 위치:

```
D:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish\ErvDashboard.exe
```

- 방금(15:55) 재배포된 최신 빌드입니다.
- SelfContained 단일 exe라 **이 `ErvDashboard.exe` 하나만** 복사해서 다른 PC에서 실행해도 됩니다(.NET 런타임 설치 불필요).

폴더 열기:


explorer.exe "D:\Project\nuvoton\HECO2\TestProgram\PCDashBoard\bin\Release\net10.0-windows\win-x64\publish" 2>/dev/null; echo opened

Open publish folder in Explorer


opened


탐색기로 publish 폴더를 열었습니다. `ErvDashboard.exe`를 실행하시면 됩니다.


지금까지 수정한 내용 server에 올려줘.
작업 컴퓨터를 변경하려고 해.


변경 내용을 서버(Gitea)에 올리겠습니다. 먼저 현재 상태와 무엇이 바뀌었는지 확인합니다.


cd /d/Project/nuvoton/HECO2
echo "=== branch & remote ==="; git branch --show-current; git remote -v
echo ""; echo "=== status (short) ==="; git status --short
echo ""; echo "=== 변경 통계(추적파일) ==="; git diff --stat

Check git status, remote, and changed files


=== branch & remote ===
main
origin	https://gitea.himpelai.com/jeon/HECO2.git (fetch)
origin	https://gitea.himpelai.com/jeon/HECO2.git (push)

=== status (short) ===
 M Source/HECO2/User/MyMotor.c
 M Source/HECO2/User/My_Homenet.c
 M Source/HECO2/User/My_Hood.c
 M Source/HECO2/User/My_system.c
 M TestProgram/PCDashBoard/MainWindow.xaml.cs
 M "\352\260\234\353\260\234\354\202\254\354\226\221\354\204\234/\352\260\201\354\213\244\354\240\234\354\226\264\354\213\234\354\212\244\355\205\234_\352\260\234\353\260\234\354\202\254\354\226\221\354\204\234_DL_\353\217\231\354\236\221\353\241\234\354\247\201_260613.pptx"
?? "doc/260618_\353\202\264\353\266\200\353\214\220\355\215\274_\353\252\250\353\223\234\353\263\200\352\262\275\354\213\234_\353\257\270\353\217\231\354\236\221_\354\210\230\354\240\225.md"

=== 변경 통계(추적파일) ===
 Source/HECO2/User/MyMotor.c                        |   9 +++++++++
 Source/HECO2/User/My_Homenet.c                     |  12 ++++++++----
 Source/HECO2/User/My_Hood.c                        |   8 ++++++--
 Source/HECO2/User/My_system.c                      |   8 ++++++--
 TestProgram/PCDashBoard/MainWindow.xaml.cs         |   7 +++++--
 ...54\236\221\353\241\234\354\247\201_260613.pptx" | Bin 2593047 -> 2484058 bytes
 6 files changed, 34 insertions(+), 10 deletions(-)


지금까지 수정한 내용 server에 올려줘. 작업 컴퓨터를 변경하려고 해.


HECO2 댐퍼 동작 문제 분석 및 비교


`main` 브랜치, 원격은 Gitea(`gitea.himpelai.com/jeon/HECO2`)입니다. 이 저장소는 그동안 main에 직접 커밋해온 흐름이고, 다른 PC에서 이어받으시려는 목적이라 **main에 커밋·푸시**하겠습니다.

오늘(260618) 수정 전체 + 새 작업기록 문서를 스테이징하고, 개발사양서 pptx도 변경돼 있어 함께 포함합니다(제가 만든 변경은 아니지만 작업 연속성을 위해).


cd /d/Project/nuvoton/HECO2
git add -A
echo "=== staged ==="; git status --short
echo ""; echo "=== 빌드산출물 포함 안됨 확인(아래 비어야 정상) ==="; git status --short | grep -iE "bin/|obj/|publish/" || echo "(없음 - OK)"

Stage all changes and verify no build artifacts


warning: in the working copy of 'doc/260618_내부댐퍼_모드변경시_미동작_수정.md', LF will be replaced by CRLF the next time Git touches it
=== staged ===
M  Source/HECO2/User/MyMotor.c
M  Source/HECO2/User/My_Homenet.c
M  Source/HECO2/User/My_Hood.c
M  Source/HECO2/User/My_system.c
M  TestProgram/PCDashBoard/MainWindow.xaml.cs
A  "doc/260618_\353\202\264\353\266\200\353\214\220\355\215\274_\353\252\250\353\223\234\353\263\200\352\262\275\354\213\234_\353\257\270\353\217\231\354\236\221_\354\210\230\354\240\225.md"
M  "\352\260\234\353\260\234\354\202\254\354\226\221\354\204\234/\352\260\201\354\213\244\354\240\234\354\226\264\354\213\234\354\212\244\355\205\234_\352\260\234\353\260\234\354\202\254\354\226\221\354\204\234_DL_\353\217\231\354\236\221\353\241\234\354\247\201_260613.pptx"

=== 빌드산출물 포함 안됨 확인(아래 비어야 정상) ===
(없음 - OK)


아..그리고..수정내용도 문서로 정리해 줘.


먼저 수정내용을 문서로 정리하겠습니다(다른 PC 핸드오프용 요약 + 최신 쾌적조리 항목 추가). 문서 끝부분을 확인합니다.


tail -20 "doc/260618_내부댐퍼_모드변경시_미동작_수정.md"

Read tail of the doc to append cleanly


- 쾌적조리 = 운전모드가 아닌 **'후드 연동 UI 토글 스위치'**. 사용자가 켤 때까지 ON 유지.
- 3.1 매트릭스: 토글 ON + 후드꺼짐 = 대기(본래 모드 가동), 토글 ON + 후드켜짐 = 메이크업 강제연동.
- 3.3 Roll-back: 후드 OFF 후 20분 환기 약 후 이전 모드 복귀 — 이는 메이크업 복귀 타이밍이지 토글 OFF가 아님.
- → 토글은 **계속 armed**가 정상. 펌웨어 `Hood_YeunDong_Enable`(토글)은 정상.

## 원인 (순수 대시보드 버그)
- `_state.ComfortCook` = status byte4 bit1 = 펌웨어 `Hood_YeunDong_Enable`(토글 Enable).
- 대시보드가 **토글 판단은 `_state.ComfortCook`(L386), 버튼 강조는 `_state.HoodRunning`(L581, 후드 실제 가동중)** 으로 서로 다른 변수 사용.
- 대기/Roll-back 상태(HoodRunning=0, ComfortCook=1)에서 버튼이 꺼져 보이고, 다시 누르면 `next=!ComfortCook=false` → OFF 전송 → "선택 안됨".

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L581:
  - `SetActive(ComfortCookBtn, _state.HoodRunning);` → `SetActive(ComfortCookBtn, _state.ComfortCook);`
  - 토글 상태(=Enable)를 강조하도록 일치. (모드/풍량 잠금 `subActive`는 사양 3.1대로 HoodRunning 유지 — 대기 중 본래 모드 조작 허용.)

## 빌드 결과
- `dotnet build ErvDashboard.csproj` → 오류 0 (NU1701 경고 9개는 기존 패키지 호환 경고, 무관).

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.


Now I'll add the latest 쾌적조리 enable fix (5) and a clean handoff summary at the top.


Edit

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.

---

# 260618 (5) 쾌적조리 버튼 활성(Enable)이 후드 상태에 묶임 — 독립 토글로 수정

## 증상
- 쾌적조리 버튼이 디폴트 비활성, 전원 ON/후드 연결 시에야 토글됨. 사양 9p 3.1상 쾌적조리는 후드 연결과 무관한 독립 토글.

## 원인
- `MainWindow.xaml.cs` L587 `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;`
- `subActive = SmartSleep || HoodRunning || ReliefRecover` 에 **HoodRunning(후드 가동중)** 포함 → 후드 상태가 쾌적조리 버튼 활성을 좌우.

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L587:
  - `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;` → `ComfortCookBtn.IsEnabled = true;`
  - 쾌적조리는 독립 토글 → 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능. (모드/풍량 버튼은 기존대로 subActive 잠금 유지.)

## 빌드/배포
- `dotnet publish ErvDashboard.csproj -c Release` → 오류 0. publish 단일 exe 갱신.


The file d:\Project\nuvoton\HECO2\doc\260618_내부댐퍼_모드변경시_미동작_수정.md has been updated successfully. (file state is current in your context — no need to Read it back)

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.

---

# 260618 (5) 쾌적조리 버튼 활성(Enable)이 후드 상태에 묶임 — 독립 토글로 수정

## 증상
- 쾌적조리 버튼이 디폴트 비활성, 전원 ON/후드 연결 시에야 토글됨. 사양 9p 3.1상 쾌적조리는 후드 연결과 무관한 독립 토글.

## 원인
- `MainWindow.xaml.cs` L587 `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;`
- `subActive = SmartSleep || HoodRunning || ReliefRecover` 에 **HoodRunning(후드 가동중)** 포함 → 후드 상태가 쾌적조리 버튼 활성을 좌우.

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L587:
  - `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;` → `ComfortCookBtn.IsEnabled = true;`
  - 쾌적조리는 독립 토글 → 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능. (모드/풍량 버튼은 기존대로 subActive 잠금 유지.)

## 빌드/배포
- `dotnet publish ErvDashboard.csproj -c Release` → 오류 0. publish 단일 exe 갱신.

# 260618 내부댐퍼 — 운전모드 변경 시 미동작 수정 (1차: 명령경로 즉시 팬설정 제거)

## 증상
- 환기 → 공청 전환 시 **팬은 정상 동작하는데 내부댐퍼(본체 6개)가 안 움직임.**

## 원인 (마스터 `D:\Project\nuvoton\HERV_DL_MH_2nd\Program` 비교로 확정)
- 내부댐퍼 이동 트리거(`Fan_Speed_process`가 모드변경 시 `Damper_Mode()` 호출)는 HECO2/마스터 **동일하게 존재**. 빠진 게 아님.
- 그 트리거는 **"팬이 0까지 감속"되어야 발동**하도록 게이팅됨(공기 흐름 중 댐퍼 미동작 의도):
  `모드변경 → 팬타깃0 → 팬=0 도달 → Damper_Mode 호출(댐퍼 이동) → 정렬(Step_Status==0x3F) → 팬 복원`
- **마스터:** 명령 핸들러가 팬 타깃을 안 건드림 → 팬이 0 도달 → 댐퍼 이동.
- **HECO2:** 명령 핸들러가 모드변경 즉시 `Fan_Speed_Setting()` 직접 호출 → 팬 타깃이 곧바로 운전속도로 올라감 → **팬이 0에 도달 못 함 → `if(Fan!=0) if(wait==5) goto PASS1` 게이트가 `Damper_Mode` 영원히 스킵 → 댐퍼 미동작, 팬만 정상.**
- 마스터엔 없고 HECO2에만 추가된 명령경로 `Fan_Speed_Setting` 호출이 게이트를 막은 것.

## 변경 파일/내용 (1차 = 모드 변경 시 호출만 제거, 풍량단수 변경 호출은 유지)
주석 처리(삭제 아님, 복원 용이). 마커: `[모드변경댐퍼테스트]`
- `Source/HECO2/User/My_Homenet.c`
  - L259 CTRL_POWER(전원ON→환기) `Fan_Speed_Setting` 주석
  - L293 CTRL_RUNMODE(운전모드 변경) `Fan_Speed_Setting` 주석  ← 보고 증상(대시보드 환기→공청)의 직접 경로
  - **L306 CTRL_FAN(풍량단수만 변경)은 유지** (댐퍼 무관, 팬 단수 반응 필요)
- `Source/HECO2/User/My_Hood.c`
  - L192 후드ON(→환기) `Fan_Speed_Setting` 주석
  - L207 후드OFF(모드 복귀) `Fan_Speed_Setting` 주석
  - **L219 후드 단수변경(풍량만)은 유지**

## 핵심 결정
- 모드 변경 후 팬 복원은 `Fan_Speed_process`의 wait==1 호출(MyMotor.c 1018/1056/1090/1124, ③)이 담당 → 팬이 꺼진 채 남지 않음.
- RJ2(`My_RJ2.c`)·분배기(`My_bunbaegi.c`)는 두 소스 동일 → 미수정.
- 이번엔 "동작모드 변경 트리거 복원(①, 디퓨저 시퀀스 명령트리거)"은 보류 — ②(땜빵) 제거만으로 댐퍼가 움직이는지 먼저 검증.

## 빌드 결과
- `cd SOURCE/HECO2 && bash build.sh all` → 성공, 경고/오류 0.
- text 43920 / data 1940 / bss 3388 (HERV.elf). (이전 44008 → 코드 제거로 감소)

## 미해결 / 후속
- 실장비/시뮬레이터에서 **환기→공청 시 내부댐퍼 이동** 확인 필요(특히 고풍량 전환 시 팬 감속 대기시간 체감).
- 검증 후: 필요하면 ①(동작모드 변경 트리거 = MyMotor.c 디퓨저/팬복원 타이밍의 명령 트리거)도 마스터 정렬 검토.
- 풍량단수만 바꿀 때(L306/L219) 팬 즉시 반응 정상인지 확인.

---

# 260618 (2) 스마트수면 모드 — 거실 댐퍼 미닫힘 수정

## 증상
- 스마트수면 동작 중 **거실 댐퍼가 열려 있음**. 사양(개발사양서 8p)상 거실은 항상 CLOSE여야 함.

## 사양 (개발사양서 8p, 스마트수면)
- 환기 수동·풍량 1단 고정.
- 초기상태: **거실 CLOSE, 침실1~3 OPEN**.
- 거실 급기(SA)/배기(RA) 모두 **X(항상 닫힘)** — CO2 무관.
- 침실1~3: CO2 >= 1000 PPM → 해당 침실 OPEN, CO2 <= 800 PPM → CLOSE.

## 원인
- `My_system.c` `Air_Quality_damper_process()` `Ext_Run_Mode == 4` 블록.
- 진입 1회(L905)는 거실(room1)을 올바르게 CLOSE 하지만, **매 틱 CO2 루프가 `Room_Num = 1`부터 돌아(L916) 거실까지 CO2 기준으로 다시 OPEN** 시킴.
- 룸 인덱스: room1=거실, room2~4=침실1~3.

## 변경 파일/내용
- `Source/HECO2/User/My_system.c` (스마트수면 매 틱 처리)
  - 거실(room1) 매 틱 강제 CLOSE + LED off 추가.
  - CO2 히스테리시스 루프 시작을 `Room_Num = 1` → **`Room_Num = 2`** (침실1~3만 개폐).

## 빌드 결과
- `bash build.sh all` → 성공, 경고/오류 0. text 43940 / data 1940 / bss 3388.

## 후속
- 실장비에서 스마트수면 진입 시 거실 닫힘 + 침실 CO2 개폐 확인.

---

# 260618 (3) 내부댐퍼 미동작 — 진짜 원인(타이밍 레이스) 수정

## 추가 진단 (사용자 확인)
- 테스트 경로 = **PC 대시보드**(My_Homenet 경로).
- 팬 거동 = **0까지 안 내려감**, 그리고 **간헐적**(어쩌다 정상 댐퍼 동작).
- → 전형적 **타이밍 레이스**. (1)차 수정으로 CTRL_RUNMODE(293)는 막았지만, 대시보드가 모드변경과 함께 보내는 **CTRL_FAN(306, 유지됨)** 이 모드전환 감속창(팬→0 구간)에 끼어드는 타이밍이면 팬 타깃을 다시 켜서 팬이 0 도달 못 함 → Damper_Mode 게이트 안 열림.
- 끼어드는 타이밍이 아니면 정상 → 간헐성 설명됨.

## 수정 (2차 = 게이트 보호, 단일 지점)
- `Source/HECO2/User/MyMotor.c` `Fan_Speed_process()` PASS1 직후(정상운전 분기, VSP 제외):
  - `Damper_wait_time == 5`(=모드전환 진행중 전용 신호. 4개 모드 진입에서만 set, Step 정렬 전까지 5 유지)일 때
    `Target_Fan1_Speed = 0; Target_Fan2_Speed = 0;` **강제** → 명령경로(CTRL_FAN 등)가 감속창에 끼어들어도 무시하고 팬을 0으로 떨굼 → 댐퍼 이동 보장.
  - 전환 완료(Step_Status==0x3F) 후 wait가 5→1로 감소하며 wait==1에서 Fan_Speed_Setting(③)이 팬 복원.
- 풍량단수만 변경(같은 모드, wait==0)은 force-zero 미적용 → CTRL_FAN(306) 즉시 반응 유지.

## 동작 변화(주의)
- 이제 환기→공청 전환 시 **팬이 잠깐 0까지 멈췄다가**(댐퍼 이동) 다시 도는 게 정상(설계상 공기흐름 중 댐퍼 미동작). 기존 "안 멈추던" 거동에서 바뀜.

## 빌드 결과
- `bash build.sh all` → 성공, 경고/오류 0. text 43948.

## 후속
- 실장비에서 환기→공청 **반복 전환** 시 매번 댐퍼 이동(간헐성 사라짐) 확인.
- 같은 모드 풍량단수 변경 시 팬 즉시 반응 정상 확인.

---

# 260618 (4) 쾌적조리 재선택 안됨 — 대시보드 버튼 강조 버그

## 증상
- 쾌적조리 동작 마치고 이전 모드 복귀 후 다시 쾌적조리 버튼 누르면 선택(ON)이 안 됨. 눌러도 토글 반응이 안 보임.

## 사양 (개발사양서 9p)
- 쾌적조리 = 운전모드가 아닌 **'후드 연동 UI 토글 스위치'**. 사용자가 켤 때까지 ON 유지.
- 3.1 매트릭스: 토글 ON + 후드꺼짐 = 대기(본래 모드 가동), 토글 ON + 후드켜짐 = 메이크업 강제연동.
- 3.3 Roll-back: 후드 OFF 후 20분 환기 약 후 이전 모드 복귀 — 이는 메이크업 복귀 타이밍이지 토글 OFF가 아님.
- → 토글은 **계속 armed**가 정상. 펌웨어 `Hood_YeunDong_Enable`(토글)은 정상.

## 원인 (순수 대시보드 버그)
- `_state.ComfortCook` = status byte4 bit1 = 펌웨어 `Hood_YeunDong_Enable`(토글 Enable).
- 대시보드가 **토글 판단은 `_state.ComfortCook`(L386), 버튼 강조는 `_state.HoodRunning`(L581, 후드 실제 가동중)** 으로 서로 다른 변수 사용.
- 대기/Roll-back 상태(HoodRunning=0, ComfortCook=1)에서 버튼이 꺼져 보이고, 다시 누르면 `next=!ComfortCook=false` → OFF 전송 → "선택 안됨".

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L581:
  - `SetActive(ComfortCookBtn, _state.HoodRunning);` → `SetActive(ComfortCookBtn, _state.ComfortCook);`
  - 토글 상태(=Enable)를 강조하도록 일치. (모드/풍량 잠금 `subActive`는 사양 3.1대로 HoodRunning 유지 — 대기 중 본래 모드 조작 허용.)

## 빌드 결과
- `dotnet build ErvDashboard.csproj` → 오류 0 (NU1701 경고 9개는 기존 패키지 호환 경고, 무관).

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.

## 미해결 / 후속(선택)

+# 260618 (5) 쾌적조리 버튼 활성(Enable)이 후드 상태에 묶임 — 독립 토글로 수정

+- 쾌적조리 버튼이 디폴트 비활성, 전원 ON/후드 연결 시에야 토글됨. 사양 9p 3.1상 쾌적조리는 후드 연결과 무관한 독립 토글.

+- `MainWindow.xaml.cs` L587 `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;`

+- `subActive = SmartSleep || HoodRunning || ReliefRecover` 에 **HoodRunning(후드 가동중)** 포함 → 후드 상태가 쾌적조리 버튼 활성을 좌우.

+## 변경 파일/내용

+  - `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;` → `ComfortCookBtn.IsEnabled = true;`

+  - 쾌적조리는 독립 토글 → 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능. (모드/풍량 버튼은 기존대로 subActive 잠금 유지.)

+- `dotnet publish ErvDashboard.csproj -c Release` → 오류 0. publish 단일 exe 갱신.


# 260618 내부댐퍼 — 운전모드 변경 시 미동작 수정 (1차: 명령경로 즉시 팬설정 제거)

# 260618 수정 요약 (핸드오프용)

> 작업 PC 이전 시점 기준. 아래 상세 항목 (1)~(5) 의 최종 변경 정리.

## 변경 파일 (커밋 포함)
| 파일 | 변경 요지 | 관련 항목 |
|---|---|---|
| `Source/HECO2/User/MyMotor.c` | 모드전환 중(`Damper_wait_time==5`) 팬 강제 0 → 내부댐퍼 이동 게이트 보호 | (3) |
| `Source/HECO2/User/My_Homenet.c` | 모드변경 시 명령경로 즉시 `Fan_Speed_Setting` 호출 주석(L259/293) — 마스터 정렬 | (1) |
| `Source/HECO2/User/My_Hood.c` | 후드연동 모드변경 시 즉시 `Fan_Speed_Setting` 주석(L192/207) — 마스터 정렬 | (1) |
| `Source/HECO2/User/My_system.c` | 스마트수면 거실(room1) CO2 무관 항상 CLOSE | (2) |
| `TestProgram/PCDashBoard/MainWindow.xaml.cs` | 쾌적조리 버튼 강조=ComfortCook(L583), 활성=항상(L587) | (4)(5) |
| `개발사양서/...DL_동작로직_260613.pptx` | 사양서 갱신(바이너리) | - |

## 빌드 상태
- 펌웨어: `cd SOURCE/HECO2 && bash build.sh all` → 경고/오류 0.
- 대시보드: `dotnet publish ErvDashboard.csproj -c Release` → 오류 0 (NU1701 경고만).
- 대시보드 exe: `TestProgram/PCDashBoard/bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe`

## 실장비/대시보드 확인 필요(테스트 대기)
- 환기→공청 반복 전환 시 내부댐퍼 매번 이동(간헐성 해소). 전환 시 팬이 잠깐 0까지 멈췄다 복귀하는 것이 정상.
- 스마트수면 진입 시 거실 닫힘 + 침실 CO2 개폐.
- 쾌적조리 버튼이 후드 연결/전원 무관하게 항상 토글되는지.

## 미적용/보류
- (선택) 쾌적조리를 스마트수면/안심회복과의 **상호배타에서 분리**(사양상 독립 토글) — SubMode_Click L401~406.
- (보류) 펌웨어 쾌적조리를 `Ext_Run_Mode==2` 상태머신으로 배선(현재 My_system 846/952 dead code). 1차 대시보드 수정으로 충분한지 검증 후 결정.
- 1차 명령경로 주석(My_Homenet/My_Hood)은 (3) 게이트 보호로 중복이나 무해 — 정리 보류.

---

# 260618 내부댐퍼 — 운전모드 변경 시 미동작 수정 (1차: 명령경로 즉시 팬설정 제거)


# 260618 수정 요약 (핸드오프용)

> 작업 PC 이전 시점 기준. 아래 상세 항목 (1)~(5) 의 최종 변경 정리.

## 변경 파일 (커밋 포함)
| 파일 | 변경 요지 | 관련 항목 |
|---|---|---|
| `Source/HECO2/User/MyMotor.c` | 모드전환 중(`Damper_wait_time==5`) 팬 강제 0 → 내부댐퍼 이동 게이트 보호 | (3) |
| `Source/HECO2/User/My_Homenet.c` | 모드변경 시 명령경로 즉시 `Fan_Speed_Setting` 호출 주석(L259/293) — 마스터 정렬 | (1) |
| `Source/HECO2/User/My_Hood.c` | 후드연동 모드변경 시 즉시 `Fan_Speed_Setting` 주석(L192/207) — 마스터 정렬 | (1) |
| `Source/HECO2/User/My_system.c` | 스마트수면 거실(room1) CO2 무관 항상 CLOSE | (2) |
| `TestProgram/PCDashBoard/MainWindow.xaml.cs` | 쾌적조리 버튼 강조=ComfortCook(L583), 활성=항상(L587) | (4)(5) |
| `개발사양서/...DL_동작로직_260613.pptx` | 사양서 갱신(바이너리) | - |

## 빌드 상태
- 펌웨어: `cd SOURCE/HECO2 && bash build.sh all` → 경고/오류 0.
- 대시보드: `dotnet publish ErvDashboard.csproj -c Release` → 오류 0 (NU1701 경고만).
- 대시보드 exe: `TestProgram/PCDashBoard/bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe`

## 실장비/대시보드 확인 필요(테스트 대기)
- 환기→공청 반복 전환 시 내부댐퍼 매번 이동(간헐성 해소). 전환 시 팬이 잠깐 0까지 멈췄다 복귀하는 것이 정상.
- 스마트수면 진입 시 거실 닫힘 + 침실 CO2 개폐.
- 쾌적조리 버튼이 후드 연결/전원 무관하게 항상 토글되는지.

## 미적용/보류
- (선택) 쾌적조리를 스마트수면/안심회복과의 **상호배타에서 분리**(사양상 독립 토글) — SubMode_Click L401~406.
- (보류) 펌웨어 쾌적조리를 `Ext_Run_Mode==2` 상태머신으로 배선(현재 My_system 846/952 dead code). 1차 대시보드 수정으로 충분한지 검증 후 결정.
- 1차 명령경로 주석(My_Homenet/My_Hood)은 (3) 게이트 보호로 중복이나 무해 — 정리 보류.

---

# 260618 내부댐퍼 — 운전모드 변경 시 미동작 수정 (1차: 명령경로 즉시 팬설정 제거)

# 260618 내부댐퍼 — 운전모드 변경 시 미동작 수정 (1차: 명령경로 즉시 팬설정 제거)

## 증상
- 환기 → 공청 전환 시 **팬은 정상 동작하는데 내부댐퍼(본체 6개)가 안 움직임.**

## 원인 (마스터 `D:\Project\nuvoton\HERV_DL_MH_2nd\Program` 비교로 확정)
- 내부댐퍼 이동 트리거(`Fan_Speed_process`가 모드변경 시 `Damper_Mode()` 호출)는 HECO2/마스터 **동일하게 존재**. 빠진 게 아님.
- 그 트리거는 **"팬이 0까지 감속"되어야 발동**하도록 게이팅됨(공기 흐름 중 댐퍼 미동작 의도):
  `모드변경 → 팬타깃0 → 팬=0 도달 → Damper_Mode 호출(댐퍼 이동) → 정렬(Step_Status==0x3F) → 팬 복원`
- **마스터:** 명령 핸들러가 팬 타깃을 안 건드림 → 팬이 0 도달 → 댐퍼 이동.
- **HECO2:** 명령 핸들러가 모드변경 즉시 `Fan_Speed_Setting()` 직접 호출 → 팬 타깃이 곧바로 운전속도로 올라감 → **팬이 0에 도달 못 함 → `if(Fan!=0) if(wait==5) goto PASS1` 게이트가 `Damper_Mode` 영원히 스킵 → 댐퍼 미동작, 팬만 정상.**
- 마스터엔 없고 HECO2에만 추가된 명령경로 `Fan_Speed_Setting` 호출이 게이트를 막은 것.

## 변경 파일/내용 (1차 = 모드 변경 시 호출만 제거, 풍량단수 변경 호출은 유지)
주석 처리(삭제 아님, 복원 용이). 마커: `[모드변경댐퍼테스트]`
- `Source/HECO2/User/My_Homenet.c`
  - L259 CTRL_POWER(전원ON→환기) `Fan_Speed_Setting` 주석
  - L293 CTRL_RUNMODE(운전모드 변경) `Fan_Speed_Setting` 주석  ← 보고 증상(대시보드 환기→공청)의 직접 경로
  - **L306 CTRL_FAN(풍량단수만 변경)은 유지** (댐퍼 무관, 팬 단수 반응 필요)
- `Source/HECO2/User/My_Hood.c`
  - L192 후드ON(→환기) `Fan_Speed_Setting` 주석
  - L207 후드OFF(모드 복귀) `Fan_Speed_Setting` 주석
  - **L219 후드 단수변경(풍량만)은 유지**

## 핵심 결정
- 모드 변경 후 팬 복원은 `Fan_Speed_process`의 wait==1 호출(MyMotor.c 1018/1056/1090/1124, ③)이 담당 → 팬이 꺼진 채 남지 않음.
- RJ2(`My_RJ2.c`)·분배기(`My_bunbaegi.c`)는 두 소스 동일 → 미수정.
- 이번엔 "동작모드 변경 트리거 복원(①, 디퓨저 시퀀스 명령트리거)"은 보류 — ②(땜빵) 제거만으로 댐퍼가 움직이는지 먼저 검증.

## 빌드 결과
- `cd SOURCE/HECO2 && bash build.sh all` → 성공, 경고/오류 0.
- text 43920 / data 1940 / bss 3388 (HERV.elf). (이전 44008 → 코드 제거로 감소)

## 미해결 / 후속
- 실장비/시뮬레이터에서 **환기→공청 시 내부댐퍼 이동** 확인 필요(특히 고풍량 전환 시 팬 감속 대기시간 체감).
- 검증 후: 필요하면 ①(동작모드 변경 트리거 = MyMotor.c 디퓨저/팬복원 타이밍의 명령 트리거)도 마스터 정렬 검토.
- 풍량단수만 바꿀 때(L306/L219) 팬 즉시 반응 정상인지 확인.

---

# 260618 (2) 스마트수면 모드 — 거실 댐퍼 미닫힘 수정

## 증상
- 스마트수면 동작 중 **거실 댐퍼가 열려 있음**. 사양(개발사양서 8p)상 거실은 항상 CLOSE여야 함.

## 사양 (개발사양서 8p, 스마트수면)
- 환기 수동·풍량 1단 고정.
- 초기상태: **거실 CLOSE, 침실1~3 OPEN**.
- 거실 급기(SA)/배기(RA) 모두 **X(항상 닫힘)** — CO2 무관.
- 침실1~3: CO2 >= 1000 PPM → 해당 침실 OPEN, CO2 <= 800 PPM → CLOSE.

## 원인
- `My_system.c` `Air_Quality_damper_process()` `Ext_Run_Mode == 4` 블록.
- 진입 1회(L905)는 거실(room1)을 올바르게 CLOSE 하지만, **매 틱 CO2 루프가 `Room_Num = 1`부터 돌아(L916) 거실까지 CO2 기준으로 다시 OPEN** 시킴.
- 룸 인덱스: room1=거실, room2~4=침실1~3.

## 변경 파일/내용
- `Source/HECO2/User/My_system.c` (스마트수면 매 틱 처리)
  - 거실(room1) 매 틱 강제 CLOSE + LED off 추가.
  - CO2 히스테리시스 루프 시작을 `Room_Num = 1` → **`Room_Num = 2`** (침실1~3만 개폐).

## 빌드 결과
- `bash build.sh all` → 성공, 경고/오류 0. text 43940 / data 1940 / bss 3388.

## 후속
- 실장비에서 스마트수면 진입 시 거실 닫힘 + 침실 CO2 개폐 확인.

---

# 260618 (3) 내부댐퍼 미동작 — 진짜 원인(타이밍 레이스) 수정

## 추가 진단 (사용자 확인)
- 테스트 경로 = **PC 대시보드**(My_Homenet 경로).
- 팬 거동 = **0까지 안 내려감**, 그리고 **간헐적**(어쩌다 정상 댐퍼 동작).
- → 전형적 **타이밍 레이스**. (1)차 수정으로 CTRL_RUNMODE(293)는 막았지만, 대시보드가 모드변경과 함께 보내는 **CTRL_FAN(306, 유지됨)** 이 모드전환 감속창(팬→0 구간)에 끼어드는 타이밍이면 팬 타깃을 다시 켜서 팬이 0 도달 못 함 → Damper_Mode 게이트 안 열림.
- 끼어드는 타이밍이 아니면 정상 → 간헐성 설명됨.

## 수정 (2차 = 게이트 보호, 단일 지점)
- `Source/HECO2/User/MyMotor.c` `Fan_Speed_process()` PASS1 직후(정상운전 분기, VSP 제외):
  - `Damper_wait_time == 5`(=모드전환 진행중 전용 신호. 4개 모드 진입에서만 set, Step 정렬 전까지 5 유지)일 때
    `Target_Fan1_Speed = 0; Target_Fan2_Speed = 0;` **강제** → 명령경로(CTRL_FAN 등)가 감속창에 끼어들어도 무시하고 팬을 0으로 떨굼 → 댐퍼 이동 보장.
  - 전환 완료(Step_Status==0x3F) 후 wait가 5→1로 감소하며 wait==1에서 Fan_Speed_Setting(③)이 팬 복원.
- 풍량단수만 변경(같은 모드, wait==0)은 force-zero 미적용 → CTRL_FAN(306) 즉시 반응 유지.

## 동작 변화(주의)
- 이제 환기→공청 전환 시 **팬이 잠깐 0까지 멈췄다가**(댐퍼 이동) 다시 도는 게 정상(설계상 공기흐름 중 댐퍼 미동작). 기존 "안 멈추던" 거동에서 바뀜.

## 빌드 결과
- `bash build.sh all` → 성공, 경고/오류 0. text 43948.

## 후속
- 실장비에서 환기→공청 **반복 전환** 시 매번 댐퍼 이동(간헐성 사라짐) 확인.
- 같은 모드 풍량단수 변경 시 팬 즉시 반응 정상 확인.

---

# 260618 (4) 쾌적조리 재선택 안됨 — 대시보드 버튼 강조 버그

## 증상
- 쾌적조리 동작 마치고 이전 모드 복귀 후 다시 쾌적조리 버튼 누르면 선택(ON)이 안 됨. 눌러도 토글 반응이 안 보임.

## 사양 (개발사양서 9p)
- 쾌적조리 = 운전모드가 아닌 **'후드 연동 UI 토글 스위치'**. 사용자가 켤 때까지 ON 유지.
- 3.1 매트릭스: 토글 ON + 후드꺼짐 = 대기(본래 모드 가동), 토글 ON + 후드켜짐 = 메이크업 강제연동.
- 3.3 Roll-back: 후드 OFF 후 20분 환기 약 후 이전 모드 복귀 — 이는 메이크업 복귀 타이밍이지 토글 OFF가 아님.
- → 토글은 **계속 armed**가 정상. 펌웨어 `Hood_YeunDong_Enable`(토글)은 정상.

## 원인 (순수 대시보드 버그)
- `_state.ComfortCook` = status byte4 bit1 = 펌웨어 `Hood_YeunDong_Enable`(토글 Enable).
- 대시보드가 **토글 판단은 `_state.ComfortCook`(L386), 버튼 강조는 `_state.HoodRunning`(L581, 후드 실제 가동중)** 으로 서로 다른 변수 사용.
- 대기/Roll-back 상태(HoodRunning=0, ComfortCook=1)에서 버튼이 꺼져 보이고, 다시 누르면 `next=!ComfortCook=false` → OFF 전송 → "선택 안됨".

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L581:
  - `SetActive(ComfortCookBtn, _state.HoodRunning);` → `SetActive(ComfortCookBtn, _state.ComfortCook);`
  - 토글 상태(=Enable)를 강조하도록 일치. (모드/풍량 잠금 `subActive`는 사양 3.1대로 HoodRunning 유지 — 대기 중 본래 모드 조작 허용.)

## 빌드 결과
- `dotnet build ErvDashboard.csproj` → 오류 0 (NU1701 경고 9개는 기존 패키지 호환 경고, 무관).

## 미해결 / 후속(선택)
- 사양상 쾌적조리는 운전모드 시나리오(스마트수면/안심회복)와 **독립**인데, 대시보드는 셋을 상호배타 처리(SubMode_Click L401~406, ApplySubModeLocal). 스마트수면/안심회복 켤 때 쾌적조리가 강제 OFF됨 → 사양과 불일치 가능. 필요 시 분리 검토.

---

# 260618 (5) 쾌적조리 버튼 활성(Enable)이 후드 상태에 묶임 — 독립 토글로 수정

## 증상
- 쾌적조리 버튼이 디폴트 비활성, 전원 ON/후드 연결 시에야 토글됨. 사양 9p 3.1상 쾌적조리는 후드 연결과 무관한 독립 토글.

## 원인
- `MainWindow.xaml.cs` L587 `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;`
- `subActive = SmartSleep || HoodRunning || ReliefRecover` 에 **HoodRunning(후드 가동중)** 포함 → 후드 상태가 쾌적조리 버튼 활성을 좌우.

## 변경 파일/내용
- `TestProgram/PCDashBoard/MainWindow.xaml.cs` L587:
  - `ComfortCookBtn.IsEnabled = !subActive || _state.ComfortCook;` → `ComfortCookBtn.IsEnabled = true;`
  - 쾌적조리는 독립 토글 → 후드 연결/가동·다른 시나리오와 무관하게 항상 토글 가능. (모드/풍량 버튼은 기존대로 subActive 잠금 유지.)

## 빌드/배포
- `dotnet publish ErvDashboard.csproj -c Release` → 오류 0. publish 단일 exe 갱신.

+> 작업 PC 이전 시점 기준. 아래 상세 항목 (1)~(5) 의 최종 변경 정리.

+## 변경 파일 (커밋 포함)

+| 파일 | 변경 요지 | 관련 항목 |

+| `Source/HECO2/User/MyMotor.c` | 모드전환 중(`Damper_wait_time==5`) 팬 강제 0 → 내부댐퍼 이동 게이트 보호 | (3) |

+| `Source/HECO2/User/My_Homenet.c` | 모드변경 시 명령경로 즉시 `Fan_Speed_Setting` 호출 주석(L259/293) — 마스터 정렬 | (1) |

+| `Source/HECO2/User/My_Hood.c` | 후드연동 모드변경 시 즉시 `Fan_Speed_Setting` 주석(L192/207) — 마스터 정렬 | (1) |

+| `Source/HECO2/User/My_system.c` | 스마트수면 거실(room1) CO2 무관 항상 CLOSE | (2) |

+| `TestProgram/PCDashBoard/MainWindow.xaml.cs` | 쾌적조리 버튼 강조=ComfortCook(L583), 활성=항상(L587) | (4)(5) |

+| `개발사양서/...DL_동작로직_260613.pptx` | 사양서 갱신(바이너리) | - |

+- 펌웨어: `cd SOURCE/HECO2 && bash build.sh all` → 경고/오류 0.

+- 대시보드: `dotnet publish ErvDashboard.csproj -c Release` → 오류 0 (NU1701 경고만).

+- 대시보드 exe: `TestProgram/PCDashBoard/bin/Release/net10.0-windows/win-x64/publish/ErvDashboard.exe`

+## 실장비/대시보드 확인 필요(테스트 대기)

+- 환기→공청 반복 전환 시 내부댐퍼 매번 이동(간헐성 해소). 전환 시 팬이 잠깐 0까지 멈췄다 복귀하는 것이 정상.

+- 스마트수면 진입 시 거실 닫힘 + 침실 CO2 개폐.

+- 쾌적조리 버튼이 후드 연결/전원 무관하게 항상 토글되는지.

+- (선택) 쾌적조리를 스마트수면/안심회복과의 **상호배타에서 분리**(사양상 독립 토글) — SubMode_Click L401~406.

+- (보류) 펌웨어 쾌적조리를 `Ext_Run_Mode==2` 상태머신으로 배선(현재 My_system 846/952 dead code). 1차 대시보드 수정으로 충분한지 검증 후 결정.

+- 1차 명령경로 주석(My_Homenet/My_Hood)은 (3) 게이트 보호로 중복이나 무해 — 정리 보류.


Now stage the updated doc and commit + push to Gitea.


Bash

cd /d/Project/nuvoton/HECO2
git add -A
git commit -m "$(cat <<'EOF'
fix: 260618 내부댐퍼·스마트수면·쾌적조리 동작 수정

- 내부댐퍼: 모드전환 중 명령경로(CTRL_FAN)가 팬 감속에 끼어들어 댐퍼가
  간헐적으로 안 움직이던 문제 수정 (Fan_Speed_process 게이트 보호)
- 명령경로 즉시 팬설정(My_Homenet/My_Hood) 모드변경분 주석 — 마스터 정렬
- 스마트수면: 거실(room1) CO2 무관 항상 CLOSE (사양 8p)
- 대시보드: 쾌적조리 버튼 강조=ComfortCook(연동 Enable),
  활성=후드/시나리오 무관 항상 토글 (사양 9p 3.1 독립 토글)
- doc/260618 수정 정리 + 개발사양서 갱신

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
)"
echo "=== commit 결과 ==="; git log --oneline -1

Commit all 260618 changes


warning: in the working copy of 'doc/260618_내부댐퍼_모드변경시_미동작_수정.md', LF will be replaced by CRLF the next time Git touches it
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got '전경선@IdeapadSlim5.(none)')
=== commit 결과 ===
82caac3 docs: Gitea 접속·협업·작업환경 가이드 추가


Git 사용자 정보가 설정돼 있지 않네요. 기존 커밋 작성자와 맞추기 위해 확인 후 설정하겠습니다.


cd /d/Project/nuvoton/HECO2
echo "=== 기존 커밋 author ==="; git log -3 --format='%an <%ae>'
echo ""; echo "=== 현재 config(local/global) ==="; git config user.name; git config user.email

Check existing commit authors and git config


Error: Exit code 1
=== 기존 커밋 author ===
jeon <jeon@himpelai.com>
jeon <jeon@himpelai.com>
jeon <jeon@himpelai.com>

=== 현재 config(local/global) ===


기존 커밋 작성자(`jeon <jeon@himpelai.com>`)에 맞춰 이 저장소에 한정해 설정하고 커밋합니다.


cd /d/Project/nuvoton/HECO2
git config user.name "jeon"
git config user.email "jeon@himpelai.com"
git commit -m "$(cat <<'EOF'
fix: 260618 내부댐퍼·스마트수면·쾌적조리 동작 수정

- 내부댐퍼: 모드전환 중 명령경로(CTRL_FAN)가 팬 감속에 끼어들어 댐퍼가
  간헐적으로 안 움직이던 문제 수정 (Fan_Speed_process 게이트 보호)
- 명령경로 즉시 팬설정(My_Homenet/My_Hood) 모드변경분 주석 — 마스터 정렬
- 스마트수면: 거실(room1) CO2 무관 항상 CLOSE (사양 8p)
- 대시보드: 쾌적조리 버튼 강조=ComfortCook(연동 Enable),
  활성=후드/시나리오 무관 항상 토글 (사양 9p 3.1 독립 토글)
- doc/260618 수정 정리 + 개발사양서 갱신

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
)"
echo "=== commit 결과 ==="; git log --oneline -1

Set local git identity and commit


[main c5e4c48] fix: 260618 내부댐퍼·스마트수면·쾌적조리 동작 수정
 7 files changed, 206 insertions(+), 10 deletions(-)
 create mode 100644 "doc/260618_\353\202\264\353\266\200\353\214\220\355\215\274_\353\252\250\353\223\234\353\263\200\352\262\275\354\213\234_\353\257\270\353\217\231\354\236\221_\354\210\230\354\240\225.md"
=== commit 결과 ===
c5e4c48 fix: 260618 내부댐퍼·스마트수면·쾌적조리 동작 수정


커밋 완료. 이제 Gitea로 푸시합니다.


git push origin main 2>&1 | tail -15; echo "exit=${PIPESTATUS[0]}"

Push to Gitea origin main


remote: . Processing 1 references
remote: Processed 1 references in total
To https://gitea.himpelai.com/jeon/HECO2.git
   82caac3..c5e4c48  main -> main
exit=0


푸시 완료했습니다. 서버에 정상 반영됐습니다.

## 서버 반영 결과
- 커밋: `c5e4c48` → Gitea `main` 푸시 성공 (`82caac3..c5e4c48`)
- 원격: https://gitea.himpelai.com/jeon/HECO2.git
- 작성자: `jeon <jeon@himpelai.com>` (기존 이력과 동일하게 맞춤)

## 커밋에 포함된 변경 (7 files)
- **펌웨어**: MyMotor.c(댐퍼 게이트 보호), My_Homenet.c·My_Hood.c(명령경로 팬설정 주석), My_system.c(스마트수면 거실 CLOSE)
- **대시보드**: MainWindow.xaml.cs(쾌적조리 강조·활성)
- **문서**: doc/260618 수정 정리(핸드오프 요약 + 상세 (1)~(5))
- **개발사양서**: pptx 갱신

빌드 산출물(bin/obj/publish)은 .gitignore로 제외돼 깔끔하게 소스만 올라갔습니다.

## 수정내용 문서
[doc/260618_내부댐퍼_모드변경시_미동작_수정.md](doc/260618_내부댐퍼_모드변경시_미동작_수정.md) 상단에 **핸드오프 요약**(변경 파일 표 / 빌드 상태 / 테스트 대기 항목 / 보류 항목)을 추가했고, 그 아래 (1)~(5) 상세 경위를 정리해 뒀습니다.

## 새 작업 PC에서 이어받기
```
git clone https://gitea.himpelai.com/jeon/HECO2.git
# 또는 기존 클론이 있으면
git pull origin main
```

테스트 대기 중인 항목(내부댐퍼 반복 전환 / 스마트수면 거실 / 쾌적조리 토글)은 문서 "테스트 대기"에 적어뒀으니 새 PC에서 실장비 확인하시면 됩니다. 더 필요하신 것 있으면 말씀해 주세요.


클로드코드도 이어 받을수는 없어?


좋은 질문입니다. 결론부터: **코드/문서는 git으로 넘어가지만, Claude Code 자체의 "대화 이력 + 메모리"는 git에 안 들어갑니다.** 이건 이 PC의 사용자 프로필(`~/.claude`) 안에 로컬로 저장되거든요. 제가 새 PC에 직접 옮길 수는 없고, 파일 복사가 필요합니다.

무엇이 어디에 있는지 확인해 드리겠습니다.


cd "/c/Users/전경선/.claude/projects/d--Project-nuvoton-HECO2" 2>/dev/null && { echo "=== 이 프로젝트의 .claude 폴더 내용 ==="; ls -la; echo ""; echo "=== memory/ ==="; ls -la memory/ 2>/dev/null; echo ""; echo "=== .jsonl(대화 이력) 개수/용량 ==="; ls -1 *.jsonl 2>/dev/null | wc -l; du -sh . 2>/dev/null; } || echo "경로 접근 불가"

Inspect local Claude Code project folder (transcripts + memory)


HECO2 댐퍼 동작 문제 분석 및 비교


=== 이 프로젝트의 .claude 폴더 내용 ===
total 1536
drwxr-xr-x 1 전경선 197121       0 Jun 18 15:06 .
drwxr-xr-x 1 전경선 197121       0 Jun 18 11:06 ..
-rw-r--r-- 1 전경선 197121 1561049 Jun 18 18:51 5209cdb2-53ba-4f8b-9aa0-4a7911424cf1.jsonl
drwxr-xr-x 1 전경선 197121       0 Jun 18 15:06 memory

=== memory/ ===
total 13
drwxr-xr-x 1 전경선 197121    0 Jun 18 15:06 .
drwxr-xr-x 1 전경선 197121    0 Jun 18 15:06 ..
-rw-r--r-- 1 전경선 197121  329 Jun 18 15:06 MEMORY.md
-rw-r--r-- 1 전경선 197121 1022 Jun 18 15:06 herv-master-source.md
-rw-r--r-- 1 전경선 197121 1418 Jun 18 15:06 internal-damper-fan-gate.md

=== .jsonl(대화 이력) 개수/용량 ===
1
1.6M	.
Shell cwd was reset to d:\Project\nuvoton\HECO2


확인했습니다. Claude Code의 로컬 데이터는 이 두 가지입니다 (git 저장소 밖, 사용자 프로필 안):

```
C:\Users\전경선\.claude\projects\d--Project-nuvoton-HECO2\
├─ 5209cdb2-...jsonl   ← 이 대화 전체 이력 (1.5MB, `claude --resume` 용)
└─ memory\
   ├─ MEMORY.md                  ← 메모리 인덱스(매 세션 자동 로드)
   ├─ herv-master-source.md      ← 마스터 소스 위치
   └─ internal-damper-fan-gate.md ← 내부댐퍼 게이트 원리
```

## 무엇이 넘어가고 안 넘어가나
- **git으로 이미 넘어감**: 소스코드, `CLAUDE.md`, `doc/260618...md` → 새 PC에서 `git clone`/`pull`이면 끝.
- **git에 없음(로컬)**: 위 대화 이력 + 메모리. 제가 새 PC로 직접 못 옮깁니다. **파일 복사가 필요**합니다.

## 이어받는 방법

**A. 완전 이어받기 (이 대화까지 그대로)**
새 PC의 같은 위치로 폴더 통째 복사:
```
C:\Users\<새PC사용자>\.claude\projects\d--Project-nuvoton-HECO2\   ← 여기에 통째 복사
```
그 후 프로젝트 폴더에서 `claude --resume` (목록에서 이 대화 선택) 또는 `claude --continue`.
- **중요(같은 경로 조건)**: 폴더명 `d--Project-nuvoton-HECO2`는 프로젝트 경로 `d:\Project\nuvoton\HECO2`에서 생성됩니다. 새 PC에서도 **같은 경로 `d:\Project\nuvoton\HECO2`로 clone**해야 자동 연결됩니다(드라이브/경로 다르면 폴더명이 달라져 인식 안 됨).
- 복사 수단: USB / OneDrive / 네트워크 공유 등.

**B. 메모리만 가볍게**
`memory\` 폴더만 새 PC의 같은 위치(`...\d--Project-nuvoton-HECO2\memory\`)에 복사 → 대화 이력은 없지만, 새 세션이 마스터 소스·댐퍼 게이트 사실을 자동 recall.

**C. git으로 같이 동기화 (선택)**
원하시면 메모리 3개 파일을 저장소(`doc/claude-memory/` 등)에도 커밋해 둘 수 있습니다. 그러면 git으로 새 PC에 따라오고, 새 PC에서 그 파일을 `~/.claude\projects\...\memory\`로 떨어뜨리면 됩니다. (자동 recall은 결국 프로필 경로에 있어야 작동하므로 한 번은 복사 필요)

---

정리하면: **소스/문서는 이미 서버에 있어 새 PC에서 바로 작업 가능**하고, "이 대화 자체를 이어받기"는 위 A처럼 `.claude` 프로젝트 폴더를 복사하면 됩니다.

원하시면 **C(메모리를 저장소에 커밋)** 를 지금 해둘까요? 그러면 적어도 메모리는 git으로 자동으로 따라갑니다.


지금 해줘


메모리를 저장소에 포함시키겠습니다. `doc/claude-memory/`로 복사하고 사용법 안내도 함께 넣겠습니다.


cd /d/Project/nuvoton/HECO2
mkdir -p doc/claude-memory
cp "/c/Users/전경선/.claude/projects/d--Project-nuvoton-HECO2/memory/MEMORY.md" doc/claude-memory/
cp "/c/Users/전경선/.claude/projects/d--Project-nuvoton-HECO2/memory/herv-master-source.md" doc/claude-memory/
cp "/c/Users/전경선/.claude/projects/d--Project-nuvoton-HECO2/memory/internal-damper-fan-gate.md" doc/claude-memory/
echo "=== 복사 결과 ==="; ls -la doc/claude-memory/

Copy Claude memory files into repo doc folder


=== 복사 결과 ===
total 17
drwxr-xr-x 1 전경선 197121    0 Jun 18 18:52 .
drwxr-xr-x 1 전경선 197121    0 Jun 18 18:52 ..
-rw-r--r-- 1 전경선 197121  329 Jun 18 18:52 MEMORY.md
-rw-r--r-- 1 전경선 197121 1022 Jun 18 18:52 herv-master-source.md
-rw-r--r-- 1 전경선 197121 1418 Jun 18 18:52 internal-damper-fan-gate.md


Write

# Claude Code 메모리 백업 (git 동기화용)

이 폴더는 Claude Code 의 프로젝트 메모리 사본입니다. (원본은 사용자 프로필
`C:\Users\<사용자>\.claude\projects\d--Project-nuvoton-HECO2\memory\` 에 있고 git 밖이라,
PC 이전 시 동기화되도록 여기에 복사해 둠.)

## 새 PC에서 적용하는 법
1. 저장소를 **같은 경로** `d:\Project\nuvoton\HECO2` 로 clone (경로가 다르면 자동 연결 안 됨).
2. 이 폴더의 `*.md` 3개를 새 PC의
   `C:\Users\<새사용자>\.claude\projects\d--Project-nuvoton-HECO2\memory\` 로 복사.
   (폴더 없으면 생성)
3. 그 폴더의 `MEMORY.md` 가 매 세션 자동 로드되어 아래 사실을 recall.

> 대화 이력(`*.jsonl`, `claude --resume` 용)은 용량이 커서 여기 포함하지 않음.
> 이 대화 자체를 이어받으려면 프로필의 해당 `.jsonl` 도 같이 복사해야 함.

## 포함된 메모리
- `MEMORY.md` — 인덱스
- `herv-master-source.md` — 검증된 마스터 펌웨어 = `D:\Project\nuvoton\HERV_DL_MH_2nd\Program`
- `internal-damper-fan-gate.md` — 내부댐퍼는 팬이 0까지 내려가야 모드별 이동(게이팅) 원리


File created successfully at: d:\Project\nuvoton\HECO2\doc\claude-memory\README.md (file state is current in your context — no need to Read it back)

# Claude Code 메모리 백업 (git 동기화용)

이 폴더는 Claude Code 의 프로젝트 메모리 사본입니다. (원본은 사용자 프로필
`C:\Users\<사용자>\.claude\projects\d--Project-nuvoton-HECO2\memory\` 에 있고 git 밖이라,
PC 이전 시 동기화되도록 여기에 복사해 둠.)

## 새 PC에서 적용하는 법
1. 저장소를 **같은 경로** `d:\Project\nuvoton\HECO2` 로 clone (경로가 다르면 자동 연결 안 됨).
2. 이 폴더의 `*.md` 3개를 새 PC의
   `C:\Users\<새사용자>\.claude\projects\d--Project-nuvoton-HECO2\memory\` 로 복사.
   (폴더 없으면 생성)
3. 그 폴더의 `MEMORY.md` 가 매 세션 자동 로드되어 아래 사실을 recall.

> 대화 이력(`*.jsonl`, `claude --resume` 용)은 용량이 커서 여기 포함하지 않음.
> 이 대화 자체를 이어받으려면 프로필의 해당 `.jsonl` 도 같이 복사해야 함.

## 포함된 메모리
- `MEMORY.md` — 인덱스
- `herv-master-source.md` — 검증된 마스터 펌웨어 = `D:\Project\nuvoton\HERV_DL_MH_2nd\Program`
- `internal-damper-fan-gate.md` — 내부댐퍼는 팬이 0까지 내려가야 모드별 이동(게이팅) 원리


Bash

cd /d/Project/nuvoton/HECO2
git add doc/claude-memory
git commit -m "$(cat <<'EOF'
docs: Claude Code 프로젝트 메모리 백업(git 동기화용) 추가

PC 이전 시 메모리가 따라오도록 ~/.claude memory 사본을 doc/claude-memory 에 보관.
새 PC 적용법은 doc/claude-memory/README.md 참고.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
)"
echo "=== push ==="
git push origin main 2>&1 | tail -6; echo "exit=${PIPESTATUS[0]}"

Commit and push claude-memory backup


warning: in the working copy of 'doc/claude-memory/MEMORY.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'doc/claude-memory/README.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'doc/claude-memory/herv-master-source.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'doc/claude-memory/internal-damper-fan-gate.md', LF will be replaced by CRLF the next time Git touches it
[main ec13d42] docs: Claude Code 프로젝트 메모리 백업(git 동기화용) 추가
 4 files changed, 52 insertions(+)
 create mode 100644 doc/claude-memory/MEMORY.md
 create mode 100644 doc/claude-memory/README.md
 create mode 100644 doc/claude-memory/herv-master-source.md
 create mode 100644 doc/claude-memory/internal-damper-fan-gate.md
=== push ===
remote: . Processing 1 references
remote: Processed 1 references in total
To https://gitea.himpelai.com/jeon/HECO2.git
   c5e4c48..ec13d42  main -> main
exit=0


완료했습니다. 메모리가 이제 git으로 동기화됩니다.

## 반영 결과
- 커밋 `ec13d42` → Gitea `main` 푸시 성공 (`c5e4c48..ec13d42`)
- 추가된 것: [doc/claude-memory/](doc/claude-memory/)
  - `MEMORY.md`, `herv-master-source.md`, `internal-damper-fan-gate.md` (메모리 사본 3개)
  - `README.md` (새 PC 적용법 안내)

## 새 PC에서 할 일
1. `git clone` (같은 경로 `d:\Project\nuvoton\HECO2`)
2. `doc/claude-memory/`의 `*.md` 3개를 → `C:\Users\<새사용자>\.claude\projects\d--Project-nuvoton-HECO2\memory\` 로 복사 (폴더 없으면 생성)
3. 이후 Claude Code 세션이 `MEMORY.md`를 자동 로드 → 마스터 소스 위치·내부댐퍼 게이트 원리를 recall

자세한 절차는 [doc/claude-memory/README.md](doc/claude-memory/README.md)에 적어뒀습니다.

> 참고: 이 **대화 자체**(`--resume`)까지 그대로 이어받으려면 용량 큰 `5209cdb2-...jsonl`(1.5MB)을 별도로 복사해야 합니다(git엔 미포함). 메모리만으로도 핵심 맥락은 새 세션에서 recall되니, 대화 재개가 꼭 필요하지 않으면 위 3단계로 충분합니다.

새 PC 세팅 후 막히는 부분 있으면 말씀해 주세요.


대화도 이어받고 싶은데..


대화 이력(transcript)도 git에 포함시키겠습니다. `--resume`이 인식하려면 파일명(UUID)을 그대로 유지해야 하므로 동일 이름으로 복사합니다.


cd /d/Project/nuvoton/HECO2
mkdir -p doc/claude-memory/session
cp "/c/Users/전경선/.claude/projects/d--Project-nuvoton-HECO2/5209cdb2-53ba-4f8b-9aa0-4a7911424cf1.jsonl" doc/claude-memory/session/
echo "=== 복사 결과 ==="; ls -la doc/claude-memory/session/

Copy conversation transcript jsonl into repo