From a7a83e87922e2a93713361a9805f9d242bf4f380 Mon Sep 17 00:00:00 2001 From: haneulai Date: Fri, 23 Jan 2026 16:45:37 +0900 Subject: [PATCH] feat: Update stats API to include real-time crawled data --- app/routers/stats.py | 139 +++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/app/routers/stats.py b/app/routers/stats.py index 069e84f..b87ec98 100644 --- a/app/routers/stats.py +++ b/app/routers/stats.py @@ -23,7 +23,10 @@ async def get_plant_stats( db: Client = Depends(get_db) ) -> dict: """ - 발전소 통계 조회 + 발전소 통계 조회 (Hybrid 방식) + 1. daily_stats: 과거 데이터 조회 + 2. solar_logs: 오늘 실시간 데이터 조회 + 3. 병합: 오늘 날짜 데이터는 실시간 데이터 우선 사용 Args: plant_id: 발전소 ID @@ -34,80 +37,100 @@ async def get_plant_stats( """ try: today = datetime.now().date() + today_str = today.isoformat() + + # 1. 과거 데이터 조회 (daily_stats) + if period == "day": + start_date = today - timedelta(days=30) + date_filter = start_date.isoformat() + elif period == "month": + start_date = today.replace(day=1) - timedelta(days=365) + date_filter = start_date.isoformat() + else: # year + start_date = datetime(today.year - 5, 1, 1).date() + date_filter = start_date.strftime("%Y-%m-%d") + + stats_query = db.table("daily_stats") \ + .select("date, total_generation") \ + .eq("plant_id", plant_id) \ + .gte("date", date_filter) \ + .lte("date", today_str) \ + .order("date", desc=False) + + stats_result = stats_query.execute() + + # 데이터 맵핑 {날짜: 발전량} + data_map = {row["date"]: row["total_generation"] or 0 for row in stats_result.data} + + # 2. 오늘 실시간 데이터 조회 (solar_logs) + # 오늘의 가장 마지막 기록 1건만 조회 (성능 최적화) + logs_result = db.table("solar_logs") \ + .select("today_kwh, created_at") \ + .eq("plant_id", plant_id) \ + .gte("created_at", f"{today_str}T00:00:00") \ + .order("created_at", desc=True) \ + .limit(1) \ + .execute() + + today_generation = 0.0 + if logs_result.data: + today_generation = logs_result.data[0].get("today_kwh", 0.0) + + # 3. 데이터 병합 (오늘 데이터 갱신/추가) + # solar_logs 값이 있으면 무조건 daily_stats 값보다 우선 (실시간성) + if today_generation > 0: + data_map[today_str] = today_generation + + # 4. 포맷팅 및 집계 + data = [] if period == "day": - # 최근 30일 - start_date = today - timedelta(days=30) - - result = db.table("daily_stats") \ - .select("date, total_generation") \ - .eq("plant_id", plant_id) \ - .gte("date", start_date.isoformat()) \ - .lte("date", today.isoformat()) \ - .order("date", desc=False) \ - .execute() - - data = [ - {"label": row["date"], "value": row["total_generation"] or 0} - for row in result.data - ] - + # 최근 30일 일별 데이터 생성 (누락된 날짜는 0으로 채움) + current = start_date + while current <= today: + d_str = current.isoformat() + data.append({ + "label": d_str, + "value": round(data_map.get(d_str, 0), 2) + }) + current += timedelta(days=1) + elif period == "month": - # 최근 12개월 - 월별 합계 - start_date = today.replace(day=1) - timedelta(days=365) - - result = db.table("daily_stats") \ - .select("date, total_generation") \ - .eq("plant_id", plant_id) \ - .gte("date", start_date.isoformat()) \ - .lte("date", today.isoformat()) \ - .execute() - # 월별 집계 monthly = {} - for row in result.data: - date_str = row["date"] - month_key = date_str[:7] # YYYY-MM - generation = row["total_generation"] or 0 - monthly[month_key] = monthly.get(month_key, 0) + generation - + # daily_stats + solar_logs(오늘) 데이터로 집계 + for date_str, val in data_map.items(): + month_key = date_str[:7] + monthly[month_key] = monthly.get(month_key, 0) + val + + sorted_keys = sorted(monthly.keys()) data = [ - {"label": month, "value": round(value, 2)} - for month, value in sorted(monthly.items()) - ][-12:] # 최근 12개월만 + {"label": k, "value": round(monthly[k], 2)} + for k in sorted_keys + if k >= start_date.strftime("%Y-%m") + ] elif period == "year": - # 최근 5년 - 연도별 합계 - start_year = today.year - 5 - - result = db.table("daily_stats") \ - .select("date, total_generation") \ - .eq("plant_id", plant_id) \ - .gte("date", f"{start_year}-01-01") \ - .lte("date", today.isoformat()) \ - .execute() - # 연도별 집계 yearly = {} - for row in result.data: - date_str = row["date"] - year_key = date_str[:4] # YYYY - generation = row["total_generation"] or 0 - yearly[year_key] = yearly.get(year_key, 0) + generation - + for date_str, val in data_map.items(): + year_key = date_str[:4] + yearly[year_key] = yearly.get(year_key, 0) + val + + sorted_keys = sorted(yearly.keys()) data = [ - {"label": year, "value": round(value, 2)} - for year, value in sorted(yearly.items()) + {"label": k, "value": round(yearly[k], 2)} + for k in sorted_keys + if k >= str(start_date.year) ] - else: - raise HTTPException(status_code=400, detail="Invalid period parameter") - + return { "status": "success", "plant_id": plant_id, "period": period, "data": data, - "count": len(data) + "count": len(data), + "today_realtime_kwh": today_generation # 디버깅용 } except HTTPException: