# ========================================== # crawlers/cmsolar.py - CMSolar 크롤러 (10호기) # ========================================== import requests from .base import create_session def fetch_data(plant_info): """ CMSolar 발전소 데이터 수집 """ plant_id = plant_info.get('id', 'cmsolar-10') auth = plant_info.get('auth', {}) system = plant_info.get('system', {}) company_name = plant_info.get('company_name', '태양과바람') plant_name = plant_info.get('name', '10호기') login_id = auth.get('login_id', '') login_pw = auth.get('login_pw', '') site_no = auth.get('site_no', '') base_url = system.get('base_url', '') session = create_session() headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/143.0.0.0 Safari/537.36', 'Referer': f'{base_url}/plant/index.php' } # 1. 로그인 try: login_data = {'id': login_id, 'pw': login_pw, 'commit': 'Login'} session.post(f"{base_url}/login_ok.php", data=login_data, headers=headers) except: return [] # 2. 사이트 선택 try: session.get(f"{base_url}/change.php?site={site_no}", headers=headers) except: return [] # 3. 데이터 요청 target_url = f"{base_url}/plant/sub/idx_ok.php?mode=getPlant" try: res = session.get(target_url, headers=headers) res.encoding = 'utf-8' data = res.json() plant_data = data[0]['plant'] # 단위 변환 (W -> kW, Wh -> kWh) curr_kw = float(plant_data.get('now', 0)) / 1000 today_kwh = float(plant_data.get('today', 0)) / 1000 is_error = int(plant_data.get('inv_error', 0)) status = "🟢 정상" if is_error == 0 else "🔴 점검/고장" print(f" [CMSolar] {plant_name} 수집 완료: {round(curr_kw, 2)} kW") return [{ 'id': plant_id, 'name': f'{company_name} {plant_name}', 'kw': round(curr_kw, 2), 'today': round(today_kwh, 2), 'status': status }] except Exception as e: print(f"❌ {plant_name} 에러: {e}") return [] def fetch_history_daily(plant_info, start_date, end_date): """ CMSolar 발전소의 일별 과거 데이터 수집 """ from datetime import datetime, timedelta from .base import safe_float results = [] plant_id = plant_info.get('id', 'cmsolar-10') auth = plant_info.get('auth', {}) system = plant_info.get('system', {}) plant_name = plant_info.get('name', '10호기') login_id = auth.get('login_id', '') login_pw = auth.get('login_pw', '') site_no = auth.get('site_no', '') base_url = system.get('base_url', '') session = create_session() print(f"\n{'='*60}") print(f"[CMSolar Daily] {plant_name} ({start_date} ~ {end_date})") print(f"{'='*60}") headers = { 'User-Agent': 'Mozilla/5.0', 'Referer': f'{base_url}/plant/index.php' } try: login_data = {'id': login_id, 'pw': login_pw, 'commit': 'Login'} session.post(f"{base_url}/login_ok.php", data=login_data, headers=headers) session.get(f"{base_url}/change.php?site={site_no}", headers=headers) print(" ✓ Login successful") except Exception as e: print(f" ✗ Login failed: {e}") return results current_date = datetime.strptime(start_date, '%Y-%m-%d') end_dt = datetime.strptime(end_date, '%Y-%m-%d') while current_date <= end_dt: date_str = current_date.strftime('%Y-%m-%d') # 일별 데이터 엔드포인트 (추정) daily_url = f"{base_url}/plant/sub/daily_data.php?date={date_str}" try: res = session.get(daily_url, headers=headers, timeout=10) res.encoding = 'utf-8' if res.status_code == 200: data = res.json() daily_kwh = safe_float(data.get('today', data.get('daily', 0))) / 1000.0 results.append({ 'plant_id': plant_id, 'date': date_str, 'generation_kwh': daily_kwh }) print(f" ✓ {date_str}: {daily_kwh}kWh") except Exception as e: print(f" ✗ {date_str}: {e}") current_date += timedelta(days=1) print(f"[Total] Collected {len(results)} daily records\n") return results def fetch_history_monthly(plant_info, start_month, end_month): """ CMSolar 발전소의 월별 과거 데이터 수집 """ from datetime import datetime from dateutil.relativedelta import relativedelta from .base import safe_float results = [] plant_id = plant_info.get('id', 'cmsolar-10') auth = plant_info.get('auth', {}) system = plant_info.get('system', {}) plant_name = plant_info.get('name', '10호기') login_id = auth.get('login_id', '') login_pw = auth.get('login_pw', '') site_no = auth.get('site_no', '') base_url = system.get('base_url', '') session = create_session() print(f"\n{'='*60}") print(f"[CMSolar Monthly] {plant_name} ({start_month} ~ {end_month})") print(f"{'='*60}") headers = { 'User-Agent': 'Mozilla/5.0', 'Referer': f'{base_url}/plant/index.php' } try: login_data = {'id': login_id, 'pw': login_pw, 'commit': 'Login'} session.post(f"{base_url}/login_ok.php", data=login_data, headers=headers) session.get(f"{base_url}/change.php?site={site_no}", headers=headers) print(" ✓ Login successful") except Exception as e: print(f" ✗ Login failed: {e}") return results current_month = datetime.strptime(start_month, '%Y-%m') end_month_dt = datetime.strptime(end_month, '%Y-%m') while current_month <= end_month_dt: month_str = current_month.strftime('%Y-%m') # 월별 데이터 엔드포인트 (추정) monthly_url = f"{base_url}/plant/sub/monthly_data.php?month={month_str}" try: res = session.get(monthly_url, headers=headers, timeout=10) res.encoding = 'utf-8' if res.status_code == 200: data = res.json() monthly_kwh = safe_float(data.get('month', data.get('monthly', 0))) / 1000.0 results.append({ 'plant_id': plant_id, 'month': month_str, 'generation_kwh': monthly_kwh }) print(f" ✓ {month_str}: {monthly_kwh}kWh") except Exception as e: print(f" ✗ {month_str}: {e}") current_month += relativedelta(months=1) print(f"[Total] Collected {len(results)} monthly records\n") return results def fetch_history_hourly(plant_info, start_date, end_date): """ CMSolar 발전소의 시간대별 과거 데이터 수집 Args: plant_info: dict, 발전소 정보 start_date: str, 시작일 (YYYY-MM-DD) end_date: str, 종료일 (YYYY-MM-DD) Returns: list: 시간대별 데이터 레코드 """ from datetime import datetime, timedelta from .base import safe_float results = [] # 설정 추출 plant_id = plant_info.get('id', 'cmsolar-10') auth = plant_info.get('auth', {}) system = plant_info.get('system', {}) plant_name = plant_info.get('name', '10호기') login_id = auth.get('login_id', '') login_pw = auth.get('login_pw', '') site_no = auth.get('site_no', '') base_url = system.get('base_url', '') session = create_session() print(f"\n{'='*60}") print(f"[CMSolar History] {plant_name} ({start_date} ~ {end_date})") print(f"{'='*60}") # 로그인 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/143.0.0.0 Safari/537.36', 'Referer': f'{base_url}/plant/index.php' } try: login_data = {'id': login_id, 'pw': login_pw, 'commit': 'Login'} session.post(f"{base_url}/login_ok.php", data=login_data, headers=headers) # 사이트 선택 session.get(f"{base_url}/change.php?site={site_no}", headers=headers) print(f" ✓ Login successful") except Exception as e: print(f" ✗ Login failed: {e}") return results # 날짜 범위 반복 current_date = datetime.strptime(start_date, '%Y-%m-%d') end_dt = datetime.strptime(end_date, '%Y-%m-%d') while current_date <= end_dt: date_str = current_date.strftime('%Y-%m-%d') print(f"\n[Processing Date] {date_str}") # 시간대별 데이터 엔드포인트 (추정) hourly_url = f"{base_url}/plant/sub/hourly_data.php?site={site_no}&date={date_str}" try: res = session.get(hourly_url, headers=headers, timeout=10) res.encoding = 'utf-8' if res.status_code == 200: data = res.json() hourly_data = data if isinstance(data, list) else data.get('hourly', []) if hourly_data and len(hourly_data) > 0: print(f" ✓ Found {len(hourly_data)} hourly records") for item in hourly_data: hour = str(item.get('hour', item.get('time', '00'))).zfill(2) generation_wh = safe_float(item.get('energy', item.get('now', 0))) generation_kwh = generation_wh / 1000.0 if generation_wh > 1000 else generation_wh current_kw = safe_float(item.get('power', 0)) / 1000.0 timestamp = f"{date_str} {hour}:00:00" results.append({ 'plant_id': plant_id, 'timestamp': timestamp, 'generation_kwh': generation_kwh, 'current_kw': current_kw }) else: print(f" ⚠ No hourly data for {date_str}") else: print(f" ✗ HTTP {res.status_code}") except Exception as e: print(f" ✗ Error: {e}") # 다음 날짜로 current_date += timedelta(days=1) print(f"\n{'='*60}") print(f"[Total] Collected {len(results)} hourly records") print(f"{'='*60}\n") return results