# =================================================================== # services/weather/precipitation.py # 강수량 데이터 서비스 모듈 # =================================================================== # 시간별 강수량 예보 데이터를 조회하고 요약 정보를 생성합니다. # HTML 테이블 생성 및 SQLite/MySQL 저장을 지원합니다. # =================================================================== """ 강수량 데이터 서비스 모듈 시간별 강수량 예보 데이터를 조회하고 요약 정보를 생성합니다. 다양한 출력 형식(HTML, JSON, 텍스트)을 지원합니다. 사용 예시: from services.weather.precipitation import PrecipitationService service = PrecipitationService(service_key) summary = service.get_daily_summary() html = service.generate_html_table() """ import os import sqlite3 from datetime import datetime from typing import Dict, List, Optional, Tuple, Any from core.logging_utils import get_logger from core.config import get_config try: # 상대 import (패키지 내에서) from .forecast import parse_precip, get_ultra_forecast, get_vilage_forecast except ImportError: # 절대 import (직접 실행 시) from services.weather.forecast import parse_precip, get_ultra_forecast, get_vilage_forecast logger = get_logger(__name__) class PrecipitationService: """ 강수량 데이터 서비스 클래스 초단기예보와 단기예보를 조합하여 시간별 강수량 예보를 제공합니다. Attributes: service_key: 기상청 API 서비스 키 start_hour: 집계 시작 시간 (기본: 10) end_hour: 집계 종료 시간 (기본: 22) """ def __init__( self, service_key: Optional[str] = None, start_hour: int = 10, end_hour: int = 22 ): """ Args: service_key: API 키 (None이면 설정에서 로드) start_hour: 집계 시작 시간 end_hour: 집계 종료 시간 """ if service_key is None: config = get_config() service_key = config.weather_service.get('service_key') or config.data_api.get('service_key', '') self.service_key = service_key self.start_hour = start_hour self.end_hour = end_hour def get_hourly_ultra_data(self, target_date: Optional[str] = None) -> Dict[int, float]: """ 초단기예보에서 시간별 강수량 추출 Args: target_date: 대상 날짜 (YYYYMMDD). None이면 오늘 Returns: 시간별 강수량 딕셔너리 {시간: 강수량(mm)} """ if target_date is None: target_date = datetime.now().strftime('%Y%m%d') items = get_ultra_forecast(self.service_key) result = {} for item in items: if item.get('category') != 'RN1': continue if item.get('fcstDate') != target_date: continue try: hour = int(item['fcstTime'][:2]) if self.start_hour <= hour <= self.end_hour: result[hour] = parse_precip(item['fcstValue']) except (ValueError, KeyError): continue return result def get_hourly_vilage_data(self, target_date: Optional[str] = None) -> Dict[int, float]: """ 단기예보에서 시간별 강수량 추출 Args: target_date: 대상 날짜 (YYYYMMDD). None이면 오늘 Returns: 시간별 강수량 딕셔너리 {시간: 강수량(mm)} """ if target_date is None: target_date = datetime.now().strftime('%Y%m%d') items = get_vilage_forecast(self.service_key, base_date=target_date) result = {} for item in items: if item.get('category') != 'PCP': continue if item.get('fcstDate') != target_date: continue try: hour = int(item['fcstTime'][:2]) if self.start_hour <= hour <= self.end_hour: result[hour] = parse_precip(item['fcstValue']) except (ValueError, KeyError): continue return result def get_daily_summary( self, target_date: Optional[str] = None ) -> Tuple[List[Tuple[str, float]], float]: """ 일별 강수량 요약 조회 초단기예보를 우선으로 하고, 없는 시간대는 단기예보로 보완합니다. Args: target_date: 대상 날짜 (YYYYMMDD). None이면 오늘 Returns: (시간별 강수량 리스트, 총 강수량) 튜플 시간별: [('10:00', 0.5), ('11:00', 0.0), ...] """ if target_date is None: target_date = datetime.now().strftime('%Y%m%d') # 초단기예보 데이터 (우선) ultra_data = self.get_hourly_ultra_data(target_date) # 단기예보 데이터 (보완용) vilage_data = self.get_hourly_vilage_data(target_date) time_precip_list = [] total_rainfall = 0.0 for hour in range(self.start_hour, self.end_hour + 1): # 초단기예보 우선, 없으면 단기예보 사용 rainfall = ultra_data.get(hour, vilage_data.get(hour, 0.0)) time_str = f"{hour:02d}:00" time_precip_list.append((time_str, rainfall)) total_rainfall += rainfall return time_precip_list, round(total_rainfall, 1) def generate_html_table( self, target_date: Optional[str] = None, title: Optional[str] = None ) -> str: """ 강수량 요약 HTML 테이블 생성 Args: target_date: 대상 날짜 (YYYYMMDD). None이면 오늘 title: 테이블 제목 (None이면 기본 제목) Returns: HTML 문자열 """ if target_date is None: target_date = datetime.now().strftime('%Y%m%d') time_precip_list, total_rainfall = self.get_daily_summary(target_date) if title is None: title = f"[{self.start_hour}:00 ~ {self.end_hour}:00 예상 강수량]" lines = [ '
| 시간 | ', '강수량 | ', '
|---|---|
| {time_str} | ' f'{rainfall}mm |
| ' f'총 예상 강수량: {total_rainfall:.1f}mm | |
초단기 + 단기 예보 기준
') lines.append('