fix: 크롤링 오류 시 daily_stats 0으로 덮어쓰기 방지
- save_to_supabase()에서 status에 '오류' 포함 시 daily_stats 갱신 금지 - today_kwh == 0인 경우도 daily_stats 갱신 금지 (새벽/야간 보호) - solar_logs는 이상 이력 추적을 위해 오류 데이터도 계속 기록 - 재현 사례: 2026-05-14 15:40 nrems-03 NREMS 응답 오류로 0kW 오보
This commit is contained in:
parent
c736b2982f
commit
c885bab007
36
database.py
36
database.py
|
|
@ -73,11 +73,16 @@ def save_to_supabase(data_list):
|
||||||
kst = timezone(timedelta(hours=9))
|
kst = timezone(timedelta(hours=9))
|
||||||
kst_now = datetime.now(kst).isoformat()
|
kst_now = datetime.now(kst).isoformat()
|
||||||
|
|
||||||
|
status = item.get('status', '')
|
||||||
|
is_error = '오류' in status # '🔴 오류' 상태 감지
|
||||||
|
|
||||||
|
# [보호] 오류 상태 데이터는 solar_logs에는 기록하되 daily_stats는 건드리지 않음
|
||||||
|
# 단, solar_logs 기록 자체는 이상 이력 추적을 위해 유지
|
||||||
record = {
|
record = {
|
||||||
'plant_id': plant_id,
|
'plant_id': plant_id,
|
||||||
'current_kw': float(item.get('kw', 0)),
|
'current_kw': float(item.get('kw', 0)),
|
||||||
'today_kwh': float(item.get('today', 0)),
|
'today_kwh': float(item.get('today', 0)),
|
||||||
'status': item.get('status', ''),
|
'status': status,
|
||||||
'created_at': kst_now # 한국 시간으로 저장
|
'created_at': kst_now # 한국 시간으로 저장
|
||||||
}
|
}
|
||||||
records.append(record)
|
records.append(record)
|
||||||
|
|
@ -86,28 +91,34 @@ def save_to_supabase(data_list):
|
||||||
print("[DB] 저장할 유효한 레코드가 없습니다.")
|
print("[DB] 저장할 유효한 레코드가 없습니다.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Supabase에 일괄 삽입 (solar_logs)
|
# Supabase에 일괄 삽입 (solar_logs) - 오류 상태 포함 전체 기록
|
||||||
result = client.table("solar_logs").insert(records).execute()
|
result = client.table("solar_logs").insert(records).execute()
|
||||||
|
|
||||||
print(f"✅ [DB] Supabase 저장 완료: {len(records)}건 (solar_logs)")
|
print(f"✅ [DB] Supabase 저장 완료: {len(records)}건 (solar_logs)")
|
||||||
|
|
||||||
# daily_stats 테이블 업데이트 (Upsert)
|
# daily_stats 테이블 업데이트 (Upsert)
|
||||||
# 오늘 날짜(KST) 기준, 현재 수집된 today_kwh가 기존 값보다 크거나 같으면 업데이트
|
# [보호 로직]
|
||||||
# 하지만 보통 today_kwh는 누적값이므로 간단하게 upsert 처리
|
# 1. 오류 상태(크롤링 실패)인 경우 daily_stats 갱신 금지
|
||||||
|
# 2. today_kwh == 0인 경우 daily_stats 갱신 금지 (새벽 0 값으로 하루치 덮어쓰기 방지)
|
||||||
daily_records = []
|
daily_records = []
|
||||||
kst_date_str = datetime.now(timezone(timedelta(hours=9))).strftime("%Y-%m-%d")
|
kst_date_str = datetime.now(timezone(timedelta(hours=9))).strftime("%Y-%m-%d")
|
||||||
|
|
||||||
for item in data_list:
|
for item in data_list:
|
||||||
plant_id = item.get('id', '')
|
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))
|
today_val = float(item.get('today', 0))
|
||||||
|
|
||||||
# 0인 경우는 저장하지 않거나(새벽), 기존 값을 덮어쓰지 않도록 주의해야 함
|
# 오류 상태이거나 today_kwh가 0이면 daily_stats 갱신 건너뜀
|
||||||
# 하지만 발전소 데이터 보정을 위해 0이어도 일단 기록하거나,
|
if is_error:
|
||||||
# 아니면 max 값을 유지하는 로직이 필요할 수 있음.
|
print(f" ⚠️ [{plant_id}] 오류 상태 → daily_stats 갱신 건너뜀")
|
||||||
# 여기서는 Upsert로 덮어쓰되, DB 트리거가 없다면 마지막 값이 저장됨.
|
continue
|
||||||
# 보통 크롤링은 누적값이므로 마지막 값이 그날의 최종값에 가까움.
|
if today_val == 0:
|
||||||
|
print(f" ⚠️ [{plant_id}] today_kwh=0 → daily_stats 갱신 건너뜀 (새벽/야간 추정)")
|
||||||
|
continue
|
||||||
|
|
||||||
daily_records.append({
|
daily_records.append({
|
||||||
"plant_id": plant_id,
|
"plant_id": plant_id,
|
||||||
|
|
@ -118,10 +129,7 @@ def save_to_supabase(data_list):
|
||||||
})
|
})
|
||||||
|
|
||||||
if daily_records:
|
if daily_records:
|
||||||
# upsert: plant_id, date가 unique constraint여야 함
|
|
||||||
try:
|
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()
|
stats_result = client.table("daily_stats").upsert(daily_records, on_conflict="plant_id, date").execute()
|
||||||
print(f"✅ [DB] daily_stats 업데이트 완료: {len(daily_records)}건")
|
print(f"✅ [DB] daily_stats 업데이트 완료: {len(daily_records)}건")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user