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:
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ERVSimulator.Model
|
||||
{
|
||||
// 펌웨어 [MyMotor.c] Damper_Mode() + Diffuser_Damper_process() 시퀀스를 흉내
|
||||
// - Cmd 변경 시 18초 시퀀스 트리거 (slot 180 / 120 / 60, 100ms tick)
|
||||
// - 본체 댐퍼 6개: Run_Mode 에 따라 즉시 목표각 세팅
|
||||
// - 디퓨저 댐퍼: Memory → Current 슬롯별 복사
|
||||
// - 팬 PWM: 매 tick ±1 ramp
|
||||
public class DamperSequencer
|
||||
{
|
||||
public ErvState State { get; }
|
||||
private readonly DispatcherTimer _timer;
|
||||
private int _diffuserSlot; // 180..0 카운트다운
|
||||
private int _seqType; // 1=on, 2=off, 3=decrease, 4=increase
|
||||
private int _prevAirVolume;
|
||||
private bool _pendingSequence;
|
||||
|
||||
public DamperSequencer(ErvState state)
|
||||
{
|
||||
State = state;
|
||||
_timer = new DispatcherTimer(DispatcherPriority.Normal)
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(100)
|
||||
};
|
||||
_timer.Tick += OnTick;
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
// RoomCon/HomeNet 핸들러가 Run_Mode/Fan_Mode 갱신 후 호출
|
||||
public void NotifyCommandChanged()
|
||||
{
|
||||
_pendingSequence = true;
|
||||
}
|
||||
|
||||
void OnTick(object? sender, EventArgs e)
|
||||
{
|
||||
// ---- Fan_Speed_process() 시작부: VENT && Fan=0 → 정지 진입 ----
|
||||
int newAirVolume = (State.RunMode != RunMode.Off && State.FanMode != 0) ? State.FanMode : 0;
|
||||
|
||||
if (_pendingSequence)
|
||||
{
|
||||
_pendingSequence = false;
|
||||
_diffuserSlot = 180;
|
||||
_seqType = DetermineSeqType(_prevAirVolume, newAirVolume);
|
||||
_prevAirVolume = newAirVolume;
|
||||
}
|
||||
|
||||
// ---- Damper_Mode(Run_Mode) — 본체 댐퍼 즉시 목표각 ----
|
||||
ApplyBodyDamperMode(EffectiveBodyMode());
|
||||
|
||||
// ---- Diffuser_Damper_process() — 슬롯 기반 적용 ----
|
||||
if (_diffuserSlot == 180)
|
||||
{
|
||||
if (_seqType == 1 || _seqType == 4)
|
||||
CopyMemoryToCurrent(1, 2);
|
||||
else if (_seqType == 2 || _seqType == 3)
|
||||
SetFanTargets(); // 즉시 ramp 시작
|
||||
}
|
||||
else if (_diffuserSlot == 120)
|
||||
{
|
||||
if (_seqType == 1 || _seqType == 4 || _seqType == 2 || _seqType == 3)
|
||||
CopyMemoryToCurrent(3, 4);
|
||||
}
|
||||
else if (_diffuserSlot == 60)
|
||||
{
|
||||
if (_seqType == 1 || _seqType == 4)
|
||||
SetFanTargets();
|
||||
else if (_seqType == 2 || _seqType == 3)
|
||||
CopyMemoryToCurrent(1, 2);
|
||||
}
|
||||
|
||||
if (_diffuserSlot > 0) _diffuserSlot--;
|
||||
|
||||
// ---- 팬 ramp ±1 (펌웨어와 동일) ----
|
||||
if (State.Fan1Current < State.Fan1Target) State.Fan1Current++;
|
||||
else if (State.Fan1Current > State.Fan1Target) State.Fan1Current--;
|
||||
if (State.Fan2Current < State.Fan2Target) State.Fan2Current++;
|
||||
else if (State.Fan2Current > State.Fan2Target) State.Fan2Current--;
|
||||
}
|
||||
|
||||
int DetermineSeqType(int prev, int now)
|
||||
{
|
||||
if (prev == 0 && now != 0) return 4; // increase (power on)
|
||||
if (prev != 0 && now == 0) return 3; // decrease (power off)
|
||||
if (prev > now) return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
RunMode EffectiveBodyMode()
|
||||
{
|
||||
// VENT && Fan=0 → 본체 댐퍼는 MODE_OFF 로 진입 (펌웨어 Fan_Speed_process 분기)
|
||||
if (State.RunMode == RunMode.Off) return RunMode.Off;
|
||||
if (State.RunMode == RunMode.Ventilation && State.FanMode == 0 &&
|
||||
State.Fan1Current == 0 && State.Fan2Current == 0)
|
||||
return RunMode.Off;
|
||||
return State.RunMode;
|
||||
}
|
||||
|
||||
// 펌웨어 Damper_Mode() — MyMotor.c:472
|
||||
void ApplyBodyDamperMode(RunMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case RunMode.Ventilation:
|
||||
SetBody(DamperId.OA, 0); SetBody(DamperId.EA, 0); SetBody(DamperId.BYPASS, 100);
|
||||
SetBody(DamperId.SA, 0); SetBody(DamperId.RA, 70); SetBody(DamperId.AIR, 105);
|
||||
break;
|
||||
case RunMode.AirClean:
|
||||
SetBody(DamperId.OA, 100); SetBody(DamperId.EA, 100); SetBody(DamperId.BYPASS, 100);
|
||||
SetBody(DamperId.SA, 0); SetBody(DamperId.RA, 140); SetBody(DamperId.AIR, 0);
|
||||
break;
|
||||
case RunMode.Bypass:
|
||||
SetBody(DamperId.OA, 0); SetBody(DamperId.EA, 0); SetBody(DamperId.BYPASS, 0);
|
||||
SetBody(DamperId.SA, 0); SetBody(DamperId.RA, 140); SetBody(DamperId.AIR, 105);
|
||||
break;
|
||||
case RunMode.Auto:
|
||||
// 펌웨어는 자동 시 공기질에 따라 VENT/AIR 선택. 단순화: VENT 와 동일.
|
||||
SetBody(DamperId.OA, 0); SetBody(DamperId.EA, 0); SetBody(DamperId.BYPASS, 100);
|
||||
SetBody(DamperId.SA, 0); SetBody(DamperId.RA, 70); SetBody(DamperId.AIR, 105);
|
||||
break;
|
||||
case RunMode.Off:
|
||||
default:
|
||||
SetBody(DamperId.OA, 100); SetBody(DamperId.EA, 100); SetBody(DamperId.BYPASS, 100);
|
||||
SetBody(DamperId.SA, 100); SetBody(DamperId.RA, 0); SetBody(DamperId.AIR, 105);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBody(DamperId id, int angle) => State.GetDamper(id).TargetAngle = angle;
|
||||
|
||||
void CopyMemoryToCurrent(int fromRoom, int toRoom)
|
||||
{
|
||||
for (int r = fromRoom; r <= toRoom; r++)
|
||||
{
|
||||
var room = State.GetRoom(r);
|
||||
room.CurrentSA = room.MemorySA;
|
||||
room.CurrentRA = room.MemoryRA;
|
||||
}
|
||||
}
|
||||
|
||||
// 펌웨어 Fan_Speed_Setting(Run_Mode, Fan_Mode) — MyMotor.c:1233
|
||||
void SetFanTargets()
|
||||
{
|
||||
int idx = System.Math.Clamp(State.FanMode, (byte)0, (byte)4);
|
||||
switch (State.RunMode)
|
||||
{
|
||||
case RunMode.Ventilation:
|
||||
case RunMode.Auto:
|
||||
State.Fan1Target = State.FanSAPreset_Vent[idx];
|
||||
State.Fan2Target = State.FanEAPreset_Vent[idx];
|
||||
break;
|
||||
case RunMode.Bypass:
|
||||
State.Fan1Target = State.FanSAPreset_Bypass[idx];
|
||||
State.Fan2Target = State.FanEAPreset_Bypass[idx];
|
||||
break;
|
||||
case RunMode.AirClean:
|
||||
State.Fan1Target = State.FanSAPreset_Air[idx];
|
||||
State.Fan2Target = State.FanEAPreset_Air[idx];
|
||||
break;
|
||||
default:
|
||||
State.Fan1Target = 0;
|
||||
State.Fan2Target = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user