From c885bab007959ca23966fb043353aaf1786ce8fa Mon Sep 17 00:00:00 2001 From: haneulai Date: Thu, 14 May 2026 17:56:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=81=AC=EB=A1=A4=EB=A7=81=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=8B=9C=20daily=5Fstats=200=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=8D=AE=EC=96=B4=EC=93=B0=EA=B8=B0=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - save_to_supabase()에서 status에 '오류' 포함 시 daily_stats 갱신 금지 - today_kwh == 0인 경우도 daily_stats 갱신 금지 (새벽/야간 보호) - solar_logs는 이상 이력 추적을 위해 오류 데이터도 계속 기록 - 재현 사례: 2026-05-14 15:40 nrems-03 NREMS 응답 오류로 0kW 오보 --- database.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/database.py b/database.py index d088354..62fbb2b 100644 --- a/database.py +++ b/database.py @@ -73,11 +73,16 @@ def save_to_supabase(data_list): kst = timezone(timedelta(hours=9)) kst_now = datetime.now(kst).isoformat() + status = item.get('status', '') + is_error = '오류' in status # '🔴 오류' 상태 감지 + + # [보호] 오류 상태 데이터는 solar_logs에는 기록하되 daily_stats는 건드리지 않음 + # 단, solar_logs 기록 자체는 이상 이력 추적을 위해 유지 record = { 'plant_id': plant_id, 'current_kw': float(item.get('kw', 0)), 'today_kwh': float(item.get('today', 0)), - 'status': item.get('status', ''), + 'status': status, 'created_at': kst_now # 한국 시간으로 저장 } records.append(record) @@ -86,28 +91,34 @@ def save_to_supabase(data_list): print("[DB] 저장할 유효한 레코드가 없습니다.") return False - # Supabase에 일괄 삽입 (solar_logs) + # Supabase에 일괄 삽입 (solar_logs) - 오류 상태 포함 전체 기록 result = client.table("solar_logs").insert(records).execute() print(f"✅ [DB] Supabase 저장 완료: {len(records)}건 (solar_logs)") # daily_stats 테이블 업데이트 (Upsert) - # 오늘 날짜(KST) 기준, 현재 수집된 today_kwh가 기존 값보다 크거나 같으면 업데이트 - # 하지만 보통 today_kwh는 누적값이므로 간단하게 upsert 처리 + # [보호 로직] + # 1. 오류 상태(크롤링 실패)인 경우 daily_stats 갱신 금지 + # 2. today_kwh == 0인 경우 daily_stats 갱신 금지 (새벽 0 값으로 하루치 덮어쓰기 방지) daily_records = [] kst_date_str = datetime.now(timezone(timedelta(hours=9))).strftime("%Y-%m-%d") for item in data_list: plant_id = item.get('id', '') - if not plant_id: continue + if not plant_id: + continue + status = item.get('status', '') + is_error = '오류' in status today_val = float(item.get('today', 0)) - - # 0인 경우는 저장하지 않거나(새벽), 기존 값을 덮어쓰지 않도록 주의해야 함 - # 하지만 발전소 데이터 보정을 위해 0이어도 일단 기록하거나, - # 아니면 max 값을 유지하는 로직이 필요할 수 있음. - # 여기서는 Upsert로 덮어쓰되, DB 트리거가 없다면 마지막 값이 저장됨. - # 보통 크롤링은 누적값이므로 마지막 값이 그날의 최종값에 가까움. + + # 오류 상태이거나 today_kwh가 0이면 daily_stats 갱신 건너뜀 + if is_error: + print(f" ⚠️ [{plant_id}] 오류 상태 → daily_stats 갱신 건너뜀") + continue + if today_val == 0: + print(f" ⚠️ [{plant_id}] today_kwh=0 → daily_stats 갱신 건너뜀 (새벽/야간 추정)") + continue daily_records.append({ "plant_id": plant_id, @@ -118,10 +129,7 @@ def save_to_supabase(data_list): }) if daily_records: - # upsert: plant_id, date가 unique constraint여야 함 try: - # ignore_duplicates=False -> 업데이트 - # on_conflict="plant_id, date" (Supabase/PG 설정에 따라 다름, 보통 PK나 UK 기준) stats_result = client.table("daily_stats").upsert(daily_records, on_conflict="plant_id, date").execute() print(f"✅ [DB] daily_stats 업데이트 완료: {len(daily_records)}건") except Exception as e: