## 퍼스트가든용 기상청 API를 활용해 공지사항 자동 등록 시스템 기상정보에 따른 이벤트 진행에 대한 정확한 기준 부여를 위해 기상청 API를 사용하여, 영업시간 내 강수정보를 파악하고 자동으로 공지를 올리기 위한 프로젝트. --- ## 📁 폴더 구조 ``` project-root/ ├── logs/ # 크론 실행 로그 저장 경로 │ └── cron.log # Crontab 실행 로그 │ ├── data/ # SQLite DB, 캡처 이미지 저장 경로 (공용 볼륨) │ ├── weather.sqlite # 날씨 DB (precipitation, summary 테이블) │ └── weather_capture_YYYYMMDD.png # 일자별 날씨 캡처 이미지 │ ├── app/ # gnu-autouploader + API 서버 (통합) │ ├── gnu_autoupload.py # 메인 실행 스크립트 (Selenium → FTP → DB) │ ├── weather_capture.py # Selenium 기반 날씨 이미지 캡처 + 강우량 추출 │ ├── weather.py # 기상청 API 데이터 처리 및 sqlite 저장 │ ├── send_message.py # Mattermost 알림 발송 │ ├── selenium_manager.py # Selenium 브라우저 관리 │ ├── api_server.py # Flask 기반 카카오 챗봇 웹훅 서버 ⭐ │ ├── config.py # 설정값 로드 (DB, FTP, API KEY 등) │ ├── requirements.txt # Python 의존성 │ └── run.sh # 수동 실행용 셸 스크립트 (개발 시 사용) │ ├── webhook/ # (더 이상 사용 안 함 - app/api_server.py로 통합) │ └── webhook.py # (참고용 아카이브) │ ├── build/ │ ├── app/ │ │ ├── Dockerfile # gnu-autouploader + Flask 통합 이미지 │ │ ├── entrypoint.sh # Flask + Cron 동시 실행 스크립트 ⭐ │ │ └── run.sh # (위의 app/run.sh와 동일) │ └── webhook/ │ └── Dockerfile # (더 이상 사용 안 함) │ ├── .env.example # 환경 변수 템플릿 (.env로 복사하여 수정) ├── docker-compose.yml # Docker Compose 서비스 정의 (gnu-autouploader만) └── README.md # 프로젝트 문서 ``` --- ## 📋 주요 스크립트 설명 ### `app/gnu_autoupload.py` (메인) - **역할**: 날씨 캡처 → FTP 업로드 → 그누보드 DB에 게시글 등록 - **실행 방식**: - 매일 09:00 Crontab 자동 실행 - `docker exec` 또는 `run.sh`로 수동 실행 가능 - **오류 발생 시**: Mattermost으로 알림 발송 ### `app/weather_capture.py` ⭐ (개선) - **이전**: Selenium으로 웹페이지 캡처만 수행 - **현재**: - Selenium으로 기상청 웹페이지 접근 - **페이지에서 강우량 데이터 자동 추출** (10시~21시) - '-'는 0mm, '~1'은 0.5mm로 자동 계산 - **추출된 강우량을 SQLite에 저장** (`rainfall_capture`, `rainfall_summary` 테이블) - 웹페이지 이미지 캡처 저장 ### `app/weather.py` - 기상청 API에서 시간별 강수량 데이터 수집 - 10:00 ~ 22:00 영업시간 강수 데이터 HTML 테이블 생성 - SQLite DB에 저장 ### `webhook/webhook.py` ⭐ (개선) - **Flask 기반 카카오 챇봇 응답 서버** - **주요 기능**: - **당일 조회**: 09:00 캡처된 **실제 강우량 데이터** 응답 - **미래 날짜 조회**: 기상청 API 기반 **예보 강우량** 응답 - 예보 시 "변동될 수 있음" 경고 문구 표시 - 10mm 초과 시 이벤트 적용 안내 - 날씨 캡처 이미지 함께 전송 - **통합**: 현재 `app/api_server.py`로 통합되어 동일 컨테이너에서 실행 ### `app/config.py` - 환경 변수 로드 (`.env` 또는 컨테이너 환경 변수) - 필수 변수 부재 시 즉시 오류 출력 후 종료 --- ## 🚀 설치 & 실행 ### 1. 환경 설정 ```bash # .env 파일 생성 cp .env.example .env # 필수 정보 입력 vim .env ``` ### 필수 환경 변수 ```env # 게시판 정보 BOARD_ID=news BOARD_CA_NAME=카테고리명 BOARD_CONTENT=글 내용 BOARD_MB_ID=user_id BOARD_NICKNAME=닉네임 # MySQL 연결 (로컬: localhost, Docker: db 서비스명, Synology: 실제 호스트 IP/도메인) DB_HOST=localhost DB_USER=db_user DB_PASSWORD=db_password DB_NAME=database_name # FTP 업로드 FTP_HOST=ftp.example.com FTP_USER=ftp_user FTP_PASSWORD=ftp_password FTP_UPLOAD_DIR=/data/file/news/ # 기상청 API SERVICE_KEY=your_api_key_here # Mattermost 알림 (선택사항) MATTERMOST_URL=https://mattermost.example.com MATTERMOST_TOKEN=token MATTERMOST_CHANNEL_ID=channel_id ``` ### 2. Docker Compose 실행 ```bash # 빌드 및 실행 docker-compose up -d # 로그 확인 docker-compose logs -f gnu-autouploader # 크론 실행 로그 확인 docker exec gnu-autouploader tail -f /logs/cron.log ``` ### 3. 수동 실행 ```bash # 컨테이너에서 직접 실행 docker exec -it gnu-autouploader /usr/bin/python /app/gnu_autoupload.py # 또는 run.sh 사용 docker exec -it gnu-autouploader /app/run.sh ``` --- --- ## 🎯 시스템 동작 플로우 ### 아키텍처 (통합 구조) ``` [gnu-autouploader 컨테이너] (포트 5151:5000 노출) ├─ Crontab 데몬 (포그라운드) │ └─ 매일 09:00 크론 작업 실행 │ └─ Flask 웹서버 (백그라운드) └─ 포트 5000에서 지속 실행 ``` ### 일일 작업 플로우 ``` 매일 09:00 ↓ [Crontab 작업 시작] ├─ 1. weather_capture.py 실행 │ ├─ Selenium으로 기상청 웹페이지 접근 │ ├─ 강우량 데이터 추출 (10시~21시) ⭐ │ ├─ SQLite 저장 │ └─ 웹페이지 이미지 캡처 저장 ├─ 2. weather.py 실행 (선택적) │ └─ API 기반 시간별 강수 데이터 저장 └─ 3. gnu_autoupload.py 실행 ├─ 캡처된 이미지 FTP 업로드 └─ 그누보드 게시글 자동 등록 동시에 실행 중: Flask 웹서버 ↓ (사용자 요청 시) [Flask 웹훅 엔드포인트] ├─ "오늘의 강우량은?" → SQLite에서 실제 데이터 응답 ✓ ├─ "내일 강우량은?" → API 예보 데이터 + 경고 문구 응답 ⚠️ └─ "강우량 10mm 초과?" → 이벤트 적용 여부 자동 판단 ``` --- ## 🗄️ SQLite 데이터베이스 스키마 ### `rainfall_capture` (웹페이지 캡처 데이터) ```sql CREATE TABLE rainfall_capture ( id INTEGER PRIMARY KEY, date TEXT, -- 'YYYYMMDD' hour INTEGER, -- 10~21 (10시~21시) rainfall REAL -- mm 단위 ); ``` ### `rainfall_summary` (일일 합계) ```sql CREATE TABLE rainfall_summary ( id INTEGER PRIMARY KEY, date TEXT UNIQUE, -- 'YYYYMMDD' total_rainfall REAL, -- mm 단위 capture_time TEXT -- '2025-12-19 09:00:00' ); ``` --- ## 💬 카카오 챗봇 응답 예시 ### 당일 조회 (실제 데이터) ``` 📅 12월 19일(금) 📊 실제 강수량 (09:00 캡처 기준) 10:00 → ☀️ 강수 없음 11:00 → ☀️ 강수 없음 12:00 → 0.5mm ... 21:00 → 2.3mm 💧 총 강수량: 5.2mm ❌ 이벤트 기준(10mm 초과)을 충족하지 않음 [날씨 캡처 이미지] ``` ### 미래 날짜 조회 (API 예보) ``` 📅 12월 20일(토) 📊 예보 강수량 (08:00 발표 기준) 10:00 → 1.2mm 11:00 → 2.1mm ... 21:00 → 0.8mm 💧 총 강수량: 12.5mm ✅ 식음료 2만원 이상 결제 시 무료입장권 제공 ⚠️ 이는 기상청 08:00 발표 예보입니다. 실제 이벤트 적용 기준은 당일 09:00 캡처 데이터입니다. ``` --- ## ⚙️ 크론탭 설정 Docker 컨테이너 내부에서 매일 **09:00**에 자동 실행됩니다. ``` 0 9 * * * /usr/bin/python /app/gnu_autoupload.py >> /logs/cron.log 2>&1 ``` **로그 확인:** ```bash docker exec gnu-autouploader tail -f /logs/cron.log ``` --- ## 🔍 문제 해결 ### MySQL 연결 오류 - **오류**: `Can't connect to MySQL server on 'localhost'` - **원인**: Docker 컨테이너에서 localhost는 컨테이너 자신을 가리킴 - **해결**: - Docker 환경: `DB_HOST=db` (docker-compose 서비스명) - Synology: `DB_HOST=192.168.x.x` (호스트 IP) ### Mattermost 알림 실패 - **오류**: `Invalid URL '/api/v4/posts': No scheme supplied` - **원인**: URL에 `http://` 또는 `https://`가 없음 - **해결**: `MATTERMOST_URL=https://mattermost.example.com` 명시 ### 크론탭에서 환경 변수 미로드 - **원인**: 기존 버전에서 crontab이 `.env` 파일 접근 불가 - **해결**: 현재는 `docker-compose.yml`에서 `.env`를 volume mount + env_file로 처리 --- ## 📝 설정 변경 후 재배포 ```bash # 컨테이너 재시작 docker-compose restart gnu-autouploader # 또는 재빌드 docker-compose up -d --build ``` --- ## 🛠️ 개발 & 디버깅 ### 로컬 테스트 (가상환경) ```bash # 가상환경 생성 python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 의존성 설치 pip install -r app/requirements.txt # .env 파일 생성 후 직접 실행 python app/gnu_autoupload.py ``` ### Docker 내 수동 실행 ```bash # 날씨 캡처 + 강우량 추출 docker exec gnu-autouploader /usr/bin/python /app/weather_capture.py # 메인 작업 (게시글 등록) docker exec gnu-autouploader /usr/bin/python /app/gnu_autoupload.py # 기상청 API 데이터 (선택사항) docker exec gnu-autouploader /usr/bin/python /app/weather.py ``` ### 로그 확인 ```bash # Crontab + Flask 통합 로그 docker-compose logs -f gnu-autouploader # Crontab 실행 로그만 docker exec gnu-autouploader tail -f /logs/cron.log # Flask 웹서버 로그 docker exec gnu-autouploader tail -f /logs/flask.log ```