from flask import Blueprint, jsonify import json import jsonify import os import csv import time import xml.etree.ElementTree as ET from datetime import datetime import requests import app.data_config as data_config """ ------------------------------------------------------------------------- File: weather.py Description: 고흥 날씨를 가져오는 기상청 API Author: 소지안 프로 Created: 2026-02-02 Last Modified: 2026-02-02 ------------------------------------------------------------------------- """ bp = Blueprint('kma', __name__, url_prefix='/api/kma') # 캐시 저장 경로 (app 루트 기준 data/kma_cache.json) CACHE_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data') CACHE_FILE = os.path.join(CACHE_DIR, 'kma_cache.json') def _ensure_cache_dir(): """캐시 디렉토리 생성""" os.makedirs(CACHE_DIR, exist_ok=True) def _fetch_weather_prediction_kma_api(): """ 기상청 API에서 육상예보 데이터 조회 """ url = 'https://apihub.kma.go.kr/api/typ02/openApi/VilageFcstMsgService/getLandFcst' params = { 'authKey': data_config.KMA_AUTH_KEY, 'dataType': 'JSON', 'regId': '11F20403', 'pageNo': '1', 'numOfRows': '30', } response = requests.get(url, params=params, timeout=15) response.raise_for_status() data = response.json() body = data.get('response', {}).get('body', {}) items = body.get('items', {}).get('item', []) if not isinstance(items, list): items = [items] if items else [] rows = [] for item in items: rows.append({ 'announceTime': item.get('announceTime', ''), 'numEf': item.get('numEf', ''), 'wf': item.get('wf', ''), 'rnSt': item.get('rnSt', ''), 'rnYn': item.get('rnYn', ''), 'ta': item.get('ta', ''), 'wfCd': item.get('wfCd', ''), 'wd1': item.get('wd1', ''), 'wd2': item.get('wd2', ''), 'wdTnd': item.get('wdTnd', ''), 'wsIt': item.get('wsIt', ''), }) return {'success': True, 'rows': rows, 'count': len(rows)} def load_cached_forecast(): """저장된 캐시에서 예보 데이터 로드""" if not os.path.exists(CACHE_FILE): return None try: with open(CACHE_FILE, 'r', encoding='utf-8') as f: return json.load(f) except (json.JSONDecodeError, IOError): return None def save_forecast_cache(data): """예보 데이터를 캐시 파일로 저장""" _ensure_cache_dir() payload = { 'cachedAt': datetime.now().isoformat(), 'data': data, } with open(CACHE_FILE, 'w', encoding='utf-8') as f: json.dump(payload, f, ensure_ascii=False, indent=2) def fetch_and_cache_forecast(): """ 기상청 API를 호출하여 예보를 가져와 서버에 캐시 저장. 매일 밤 12시 스케줄에서 호출됨. TODO : 스케줄링 일시 변경 가능 """ try: data = _fetch_weather_prediction_kma_api() if data.get('success'): save_forecast_cache(data) return True except Exception: pass return False @bp.route('/forecast', methods=['GET']) def get_forecast(): """ 기상청 육상예보 조회 - 캐시가 있으면 캐시 반환, 없으면 API 호출 """ cached = load_cached_forecast() if cached and cached.get('data'): return jsonify(cached['data']) try: data = _fetch_weather_prediction_kma_api() if data.get('success'): save_forecast_cache(data) return jsonify(data) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500