# ☀️ 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
- 대시보드 필드명 매핑 수정.