# ☀️ SolarPower 태양광 발전 통합 관제 시스템 태양광 발전소의 실시간 발전 데이터를 수집하고 모니터링하는 통합 관제 시스템입니다. --- ## 📋 목차 1. [시스템 개요](#시스템-개요) 2. [전체 아키텍처](#전체-아키텍처) 3. [인프라 구성](#인프라-구성) 4. [크롤러 (Synology NAS / PC)](#크롤러-synology-nas--pc) 5. [API 서버 (Oracle Cloud)](#api-서버-oracle-cloud) 6. [모바일 앱 (React Native/Expo)](#모바일-앱-react-nativeexpo) 7. [데이터베이스 (Supabase)](#데이터베이스-supabase) 8. [문제 해결 가이드](#문제-해결-가이드) --- ## 시스템 개요 ### 지원 발전소 | 호기 | 크롤러 타입 | 모니터링 시스템 | 비고 | |------|------------|----------------|------| | 1호기 | NREMS | nrems.co.kr | 1,2호기 통합 계정 | | 2호기 | NREMS | nrems.co.kr | 인버터별 분리 처리 | | 3호기 | NREMS | nrems.co.kr | | | 4호기 | NREMS | nrems.co.kr | | | 5호기 | KREMC | kremc.kr | JWT 인증, 월 단위 수집 | | 6호기 | Sun-WMS | sun-wms.com | 암호화된 페이로드, 월 단위 수집 | | 8호기 | Hyundai | hyundai-es.co.kr | 월별 통계 API 사용 (초고속) | | 9호기 | NREMS | nrems.co.kr | | | 10호기 | CMSolar | cmsolar2.kr | | --- ## 전체 아키텍처 ```mermaid flowchart TD subgraph 외부시스템["외부 모니터링 시스템"] NREMS["NREMS
(1,2,3,4,9호기)"] KREMC["KREMC
(5호기)"] SUNWMS["Sun-WMS
(6호기)"] HYUNDAI["Hyundai
(8호기)"] CMSOLAR["CMSolar
(10호기)"] end subgraph CLOUD["Oracle Cloud (CRAWLER & API)"] FASTAPI["FastAPI Server
(Port 8000)"] NGINX["Nginx Reverse Proxy
(Port 443)"] CRAWLER["Python Crawler
(Tailscale Routing)"] end subgraph NAS["Synology NAS (Exit Node)"] TAILSCALE["Tailscale Node
(Home IP Mapping)"] end subgraph SUPABASE["Supabase (PostgreSQL)"] DB_PLANTS["plants 테이블"] DB_LOGS["solar_logs 테이블"] DB_DAILY["daily_stats 테이블"] end subgraph CLIENT["클라이언트"] APP["React Native App"] WEB["Web Browser"] end NREMS --> CRAWLER KREMC --> CRAWLER SUNWMS --> CRAWLER HYUNDAI --> CRAWLER CMSOLAR --> CRAWLER CRAWLER -.->|Tailscale Tunnel| TAILSCALE TAILSCALE -.->|Proxy Request| 외부시스템 CRAWLER -->|INSERT| DB_LOGS CRAWLER -->|UPSERT| DB_DAILY FASTAPI -->|SELECT| DB_PLANTS FASTAPI -->|SELECT| DB_LOGS FASTAPI -->|SELECT| DB_DAILY NGINX --> FASTAPI APP -->|HTTPS| NGINX WEB -->|HTTPS| NGINX ``` --- ## 인프라 구성 ### 서버 접속 정보 | 서버 | 용도 | 접속 명령어 | |------|------|------------| | **Oracle Cloud** | API 서버 & 크롤러 | `ssh -i "~/.ssh/holdem_server.key" ubuntu@140.245.73.212` | | **Synology NAS** | 데이터 백업 & Tailscale Exit Node | `ssh -p2022 haneulai@192.168.45.151` | ### 도메인 | 도메인 | 용도 | |--------|------| | `https://solorpower.dadot.net` | API 서버 (Nginx 리버스 프록시) | --- ## 크롤러 (Oracle Cloud / PC) ### 위치 ``` d:\dev\etc\SolorPower\crawler\ (Local PC) /home/ubuntu/SolorPower/crawler/ (Oracle Cloud) ``` ### 네트워크 구성 (Tailscale) 일부 모니터링 사이트에서 Oracle Cloud IP가 차단되는 문제를 해결하기 위해 **Tailscale**을 사용하여 네트워크를 구성하였습니다. - **주 호스트**: Oracle Cloud (크롤러 실행) - **Exit Node**: Synology NAS (가정용 IP 제공) - **동작**: 크롤링 요청 시 Tailscale 터널을 통해 NAS의 IP를 사용하여 외부 시스템에 접근합니다. ### 디렉토리 구조 ``` crawler/ ├── main.py # 메인 실행 파일 (실시간 수집용) ├── crawler_gui.py # GUI 관리 도구 (과거 데이터 수집용) ← NEW! ├── config.py # 발전소/인증 설정 ├── database.py # Supabase 연동 ├── fetch_history.py # 과거 데이터 수집 로직 ├── .env # 환경 변수 (SUPABASE_URL, SUPABASE_KEY) └── crawlers/ ├── __init__.py # 크롤러 라우팅 ├── base.py # 공통 유틸리티 ├── nrems.py # NREMS 크롤러 ├── kremc.py # KREMC 크롤러 ├── sun_wms.py # Sun-WMS 크롤러 ├── hyundai.py # Hyundai 크롤러 └── cmsolar.py # CMSolar 크롤러 ``` ### GUI 관리 도구 (NEW) 과거 데이터를 편리하게 수집하고 복구하기 위한 GUI 도구가 추가되었습니다. 1. **실행**: ```bash python crawler_gui.py ``` 2. **기능**: - 발전소별 실시간 상태 확인 - **과거 데이터 수집**: 날짜 범위를 지정하여 일별/월별 데이터 일괄 수집 - **로그 정리**: 미래 날짜로 잘못 들어간 오염 데이터 삭제 기능 ### 자동 수집 (Cron) ```bash # 30분마다 실행 (Oracle Cloud 환경) */30 * * * * cd /home/ubuntu/SolorPower/crawler && /home/ubuntu/SolorPower/crawler/venv/bin/python main.py >> cron.log 2>&1 ``` ### 크롤러별 개선 사항 (2026.01) - **공통**: 미래 날짜 데이터(UTC/KST 혼동)가 저장되는 버그 수정 및 자동 청소 로직 추가. - **NREMS**: 일별 데이터 수집 시 월 단위로 분할 요청하여 끊김 방지. - **KREMC**: 5호기 인증 토큰 파싱 개선 및 월 단위 배치 수집 적용. - **Sun-WMS**: 6호기 세션 유지 및 월 단위 수집 안정화. - **Hyundai**: 8호기 `getSolraMonthWork` API를 활용하여 1년치 데이터를 수십 초 내에 수집하도록 최적화. --- ## API 서버 (Oracle Cloud) ### 위치 ``` /home/ubuntu/SolorPower/api_server/ ``` ### 환경 설정 (.env) ```env SUPABASE_URL=https://xxxx.supabase.co SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6... DEBUG=false ``` ### 서비스 관리 `sudo systemctl restart solar-api` ### API 엔드포인트 | Method | Endpoint | 설명 | |--------|----------|------| | GET | `/plants/{plant_id}/stats` | 발전소 통계 조회 (일/월/년) | | GET | `/plants/{plant_id}/stats/today` | 오늘(또는 특정일) 시간별 상세 조회 | | POST | `/plants/{plant_id}/upload` | 엑셀 데이터 업로드 (일간) | | POST | `/plants/{plant_id}/upload/monthly` | 엑셀 데이터 업로드 (월간) | **파라미터 설명**: - `period`: `day` (일별), `month` (월별), `year` (연도별) - `year`: (옵션) 조회 기준 연도 - `month`: (옵션) `period=day`시 조회할 월 - `date`: (옵션) `stats/today`시 조회할 날짜 (YYYY-MM-DD) --- ## 모바일 앱 & 웹 (React Native/Expo) ### 위치 ``` d:\dev\etc\SolorPower\app\ ``` ### 주요 기능 - **실시간/통계 통합**: 대시보드 및 상세 차트(일/월/년). - **날짜 네비게이션**: `◀ 2026년 1월 ▶` 등의 컨트롤로 자유로운 과거 데이터 탐색. - **엑셀 업로드**: - **일간**: `date`, `generation` 또는 `year, month, day, kwh` 포맷 지원. - **월간**: `year, month, kwh` 포맷 지원. - 별칭(`발전량`, `kwh` 등) 및 셀 병합 처리 지원. - **반응형 웹 지원**: PC/모바일 브라우저 최적화. --- ## 웹 앱 배포 가이드 (Web Deployment) React Native(Expo) 앱을 웹으로 빌드하고 Nginx 서버에 배포하는 과정입니다. ### 1. 웹 빌드 (Local PC) ```bash cd d:\dev\etc\SolorPower\app npm run export:web ``` - `dist` 폴더에 정적 웹 파일들이 생성됩니다. ### 2. 서버 업로드 (SCP) 빌드된 `dist` 폴더를 Oracle Cloud 서버의 웹 루트로 전송합니다. *(참고: `/var/www/html/` 권한 문제로 인해 임시 폴더로 전송 후 `sudo`로 이동해야 할 수 있습니다)* ```bash # 1. 홈 디렉토리로 전송 scp -i "~/.ssh/holdem_server.key" -r dist ubuntu@140.245.73.212:~/dist_temp # 2. 서버 접속 후 이동 ssh -i "~/.ssh/holdem_server.key" ubuntu@140.245.73.212 sudo rm -rf /var/www/html/dist sudo mv ~/dist_temp /var/www/html/dist ``` ### 3. Nginx 설정 (서버 분석 결과) 실제 운영 중인 Nginx 설정 (`/etc/nginx/sites-enabled/solorpower`)의 핵심 구조입니다. **라우팅 규칙**: - **Frontend**: `/var/www/html/dist` (React Static Files) - **Backend**: `http://127.0.0.1:8000` (FastAPI) - `/plants` (데이터/통계 API) - `/docs`, `/openapi.json` (API 문서) ```nginx server { listen 80; server_name solorpower.dadot.net; # HTTPS 리다이렉트 생략... listen 443 ssl; # SSL 인증서 설정 생략... # 1. React Frontend (정적 파일) location / { root /var/www/html/dist; index index.html; try_files $uri $uri/ /index.html; } # 2. FastAPI Backend (API 프록시) # plants(데이터), docs(문서) 경로만 백엔드로 토스 location ~ ^/(plants|docs|openapi.json) { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` ### 4. 적용 ```bash sudo systemctl reload nginx ``` 이제 `https://solorpower.dadot.net` 에서 배포된 웹 앱을 확인할 수 있습니다. --- ## 데이터베이스 (Supabase) ### 주요 테이블 1. **plants**: 발전소 기본 정보. 2. **solar_logs**: 실시간 발전 로그 (10분/30분 단위). `created_at` 기준. 3. **daily_stats**: 일별 발전량 통계. `date` 기준. (과거 데이터는 여기에 저장됨) 4. **monthly_stats**: 월별 발전량 통계. `month` 기준. --- ## 개발 히스토리 ### 2026-04-22 - **크롤러 인프라 이전**: 크롤러 실행 환경을 Synology NAS에서 Oracle Cloud로 이전. - **네트워크 우회 설정**: Oracle Cloud IP 차단 이슈 대응을 위해 Tailscale을 도입, Synology NAS를 Exit Node로 설정하여 가정용 IP로 크롤링 수행. - **안정성 강화**: 클라우드 환경 이전을 통해 NAS 리소스 부하 감소 및 수집 안전성 확보. ### 2026-01-30 - **데이터 복구 및 안정화**: 1월 28-29일 데이터 누락 복구 완료. - **자동 통계 집계 개선**: `daily_summary.py`가 날짜 파라미터 없이 실행될 경우 자동으로 '어제' 날짜를 기준으로 집계하도록 수정. (새벽 실행 안전성 확보) - **월간 통계 자동화**: 일일 집계 시 해당 월의 마지막 날인 경우, 자동으로 `monthly_stats`까지 집계/갱신하는 로직 추가. - **Git 저장소 분리**: - `crawler`: https://gitea.dadot.synology.me/haneulai/solorpower_crawler.git - `app`: https://gitea.dadot.synology.me/haneulai/solorpower_app.git ### 2026-01-28 - **Stats API 고도화**: 날짜/월 탐색을 위한 파라미터(`month`, `date`) 추가. - **연간 통계 개선**: 단일 연도 조회에서 '해당 연도 포함 최근 5년' 조회로 변경. - **엑셀 업로드 유연성**: `year, month, day` 컬럼이 분리된 파일도 자동 인식 및 처리. - **Frontend 개선**: 차트 상단 날짜 네비게이션(`◀ ▶`) 추가, 조회 기간 범위 표시 강화. ### 2026-01-27 - **Crawler 구조화**: `crawler_manager.py` 도입 (스마트 스케줄링, 학습/최적화 모드). - **GUI & Documentation**: 관리자 GUI 기능 확장 및 `crawler_structure.md` 문서화. - **과거 데이터 수집 최적화**: 모든 크롤러 월 단위 분할 수집 지원. ### 2026-01-23 - 통계 조회 API 추가 및 엑셀 업로드 API 구현. ### 2026-01-22 - 대시보드 필드명 매핑 수정.