Files
jeon 5a96a696b1 chore: HERV 통합 저장소 초기 커밋
- 펌웨어(program), C# 대시보드(TestProgram), 시뮬레이터(Simulator),
  프로토콜/문서(Protocol, doc) 전체를 단일 저장소로 통합
- program 폴더의 별도 git 저장소를 제거하고 통합 저장소에 흡수
- 빌드 산출물(program/build, bin/obj, *.o/.elf/.bin/.hex 등) .gitignore 처리
- 사내 Synology NAS Git 원격 연결 예정

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:44:23 +09:00

56 lines
2.3 KiB
C#

using ErvProtocol;
namespace ErvCollector.Storage
{
// 저장 정책: "N초 주기 + 상태(이산값) 변화 시 즉시"
// - 연속값(센서 PM/VOC/CO2 등)은 주기 샘플
// - 이산값(전원/모드/팬/부가/후드/프리셋/에러 + 각실 댐퍼/공기질등급/LED)이 바뀌면 즉시 기록
public sealed class Sampler
{
readonly TimeSpan _interval;
string? _lastFingerprint;
DateTime _lastWriteUtc = DateTime.MinValue;
public Sampler(int intervalSeconds)
{
_interval = TimeSpan.FromSeconds(intervalSeconds <= 0 ? 10 : intervalSeconds);
}
// 기록해야 하면 true (그리고 내부 상태 갱신)
public bool ShouldWrite(StatusRecord s, DateTime nowUtc, out string reason)
{
string fp = Fingerprint(s);
bool changed = fp != _lastFingerprint;
bool periodic = (nowUtc - _lastWriteUtc) >= _interval;
if (changed || periodic)
{
reason = changed ? (_lastFingerprint == null ? "first" : "change") : "periodic";
_lastFingerprint = fp;
_lastWriteUtc = nowUtc;
return true;
}
reason = "skip";
return false;
}
static string Fingerprint(StatusRecord s)
{
// 이산 상태/제어값만 모아 변화 감지 (연속 센서값 제외)
var sb = new System.Text.StringBuilder(48);
sb.Append(s.Power).Append(s.RunMode).Append('.').Append(s.AutoState).Append('.')
.Append(s.FanMode).Append('.').Append(s.SubMode).Append('.').Append(s.Hood).Append('.')
.Append(s.HystPreset).Append('.').Append(s.ErrorCode).Append('.').Append(s.Reset);
foreach (var r in s.Rooms)
sb.Append('|').Append(r.Damper).Append(r.AirQuality).Append(r.LedDim);
// VSP(설정값) 변경도 즉시 기록
foreach (var v in s.Vsp)
sb.Append('#').Append(v.Sa).Append(',').Append(v.Ea);
// 히스테리시스 프리셋 테이블 변경도 즉시 기록
foreach (var h in s.HystTable)
sb.Append('@').Append(h.Pm25).Append(',').Append(h.Pm10).Append(',').Append(h.Voc).Append(',').Append(h.Co2);
return sb.ToString();
}
}
}