# 気象データ機能 マスタードキュメント > **最終更新**: 2026-02-28 > **状態**: 本番稼働中 --- ## 概要 Open-Meteo archive API から窪川の気象データを日次取得し、PostgreSQL に蓄積する。 農業における積算温度計算・類似年分析・作期の気象振り返りを目的とする。 - **観測地点**: 窪川 (lat=33.213, lon=133.133) - **データソース**: [Open-Meteo Archive API](https://archive-api.open-meteo.com/v1/archive)(無料) - **蓄積期間**: 2016-01-01 〜 前日(毎朝自動更新) - **Django アプリ**: `backend/apps/weather/` --- ## データモデル ### WeatherRecord (`apps/weather/models.py`) | フィールド | 型 | 説明 | |---|---|---| | date | DateField (unique) | 日付 | | temp_mean | FloatField nullable | 平均気温 (℃) | | temp_max | FloatField nullable | 最高気温 (℃) | | temp_min | FloatField nullable | 最低気温 (℃) | | sunshine_h | FloatField nullable | 日照時間 (h) | | precip_mm | FloatField nullable | 降水量 (mm) | | wind_max | FloatField nullable | 最大風速 (m/s) | | pressure_min | FloatField nullable | 最低気圧 (hPa) | **Crop.base_temp** (`apps/plans/models.py` に追加): - FloatField, default=0.0 - GDD(有効積算温度)計算の基準温度 --- ## API エンドポイント (`/api/weather/`) ### POST `/api/weather/sync/` - **認証**: X-API-Key(MAIL_API_KEY 設定値、Windmill と共用) - **用途**: Windmill から日次データを受け取り upsert - **リクエスト**: 単一オブジェクトまたはリスト - **レスポンス**: `{"saved": N}` or `{"saved": N, "errors": [...]}` ```json [ { "date": "2026-02-27", "temp_mean": 8.5, "temp_max": 14.2, "temp_min": 3.1, "sunshine_h": 6.3, "precip_mm": 0.0, "wind_max": 4.2, "pressure_min": 1008.0 } ] ``` --- ### GET `/api/weather/records/` - **認証**: JWT - **クエリパラメータ**: - `?year=2025` — 年指定 - `?start=2025-05-01&end=2025-09-30` — 日付範囲指定 - **レスポンス**: WeatherRecord の配列(date 昇順) --- ### GET `/api/weather/summary/?year=2025` - **認証**: JWT - **レスポンス**: ```json { "year": 2025, "monthly": [ { "month": 1, "temp_mean_avg": 5.2, "temp_max_avg": 10.1, "temp_min_avg": 0.8, "precip_total": 45.0, "sunshine_total": 98.3, "wind_max": 9.5, "hot_days": 0, "cold_days": 8, "rainy_days": 12 }, ... ], "annual": { "temp_mean_avg": 16.1, "precip_total": 2310.0, "sunshine_total": 1850.5, "hot_days": 12, "cold_days": 25 } } ``` - **hot_days**: 最高気温 ≥ 35℃ の日数 - **cold_days**: 最低気温 < 0℃ の日数 - **rainy_days**: 降水量 ≥ 1.0mm の日数 --- ### GET `/api/weather/gdd/` - **認証**: JWT - **用途**: 播種日〜現在の有効積算温度(Growing Degree Days)を計算 - **クエリパラメータ**: - `?start_date=2025-05-15` (必須) — 起算日 - `?base_temp=10` (省略時=0) — 基準温度 ℃ - `?end_date=2025-09-30` (省略時=昨日) - **レスポンス**: ```json { "start_date": "2025-05-15", "end_date": "2025-09-30", "base_temp": 10.0, "total_gdd": 1342.5, "records": [ {"date": "2025-05-15", "temp_mean": 18.2, "daily_gdd": 8.2, "cumulative_gdd": 8.2}, ... ] } ``` - **日積算温度** = max(0, 平均気温 - 基準温度) --- ### GET `/api/weather/similarity/?year=2026` - **認証**: JWT - **用途**: 今年 1/1〜昨日 の気象パターンと過去年を比較し、類似年 Top3 を返す - **アルゴリズム**: (平均気温, 総降水量, 総日照時間) の正規化ユークリッド距離 - **レスポンス**: ```json { "target_year": 2026, "comparison_period": "1/1〜2/27", "target_features": {"mean_temp": 7.3, "total_precip": 185.0, "total_sunshine": 240.5}, "similar_years": [ { "year": 2020, "distance": 0.312, "features": {...}, "monthly": [...] } ] } ``` --- ## 管理コマンド ```bash # 全期間取得(初回のみ) docker compose exec backend python manage.py fetch_weather --full # 差分取得(最終レコード翌日〜昨日) docker compose exec backend python manage.py fetch_weather # 任意期間 docker compose exec backend python manage.py fetch_weather --start-date 2025-01-01 --end-date 2025-12-31 ``` **仕様**: - 年単位で Open-Meteo API を呼び出し(API 制限回避のため分割) - upsert: 既存データを上書き更新 - `--full`: 2016-01-01 から昨日まで(初回投入用) --- ## Windmill フロー | 項目 | 値 | |---|---| | パス | `f/weather/weather_sync` | | スケジュール | `0 0 6 * * *`(毎朝 6:00 Asia/Tokyo) | | スクリプト | `windmill/u/admin/weather_sync.flow/a.inline_script.py` | | 状態 | ✅ 本番稼働中(windmill.keinafarm.net) | **使用 Windmill Variables**: | 変数名 | 内容 | |---|---| | `u/admin/KEINASYSTEM_API_KEY` | API キー(メール機能と共用) | | `u/admin/KEINASYSTEM_API_URL` | `https://keinafarm.net` | --- ## フロントエンド画面 (`/weather`) ### 年別集計モード(デフォルト) - 年セレクタ (2016〜現在) - **年間サマリーカード**: 平均気温 / 年間降水量 / 年間日照時間 / 猛暑日数・冬日数 - **グラフタブ**: 月別気温折れ線(最高・平均・最低)、月別降水量棒 + 日照時間折れ線(2軸) - **月別サマリータブ**: 12ヶ月のテーブル - **直近14日タブ**: 日次データテーブル(Windmill 同期確認用) ### 期間指定モード - 開始日・終了日の date input + 「表示」ボタン - **期間集計カード**: 期間の平均気温 / 総降水量 / 総日照時間 / 猛暑日・冬日 - **グラフタブ**: 日次気温折れ線 + 日次降水量棒+日照折れ線 - X軸ラベル自動間引き(30日以内→3日おき、3ヶ月→週1、半年→2週、1年超→月1) - 60日以内はドット表示あり - **一覧タブ**: 日次データテーブル(スクロール対応) **使用ライブラリ**: Recharts 3.7.x(`frontend/package.json` に登録済み) --- ## ファイル索引 | ファイル | 役割 | |---|---| | `backend/apps/weather/models.py` | WeatherRecord モデル | | `backend/apps/weather/views.py` | 5つのAPIビュー | | `backend/apps/weather/urls.py` | URL設定 | | `backend/apps/weather/serializers.py` | Serializer | | `backend/apps/weather/admin.py` | 管理画面登録 | | `backend/apps/weather/migrations/0001_initial.py` | 初回マイグレーション | | `backend/apps/weather/management/commands/fetch_weather.py` | 管理コマンド | | `backend/apps/plans/migrations/0004_crop_base_temp.py` | Crop.base_temp 追加 | | `frontend/src/app/weather/page.tsx` | 気象画面(400行) | | `windmill/u/admin/weather_sync.flow/a.inline_script.py` | Windmill Python スクリプト | | `windmill/u/admin/weather_sync.flow/flow.yaml` | Windmill フロー定義 | --- ## 将来計画(Phase 2 以降) 1. **GDD 到達日予測**: `Crop.base_temp` を使い、播種日から目標GDDに達する日を予測 2. **類似年ベースの収穫予測**: 類似年の収穫時期を参考に今年の予測を表示 3. **作付け計画との連携**: 作期ごとの気象サマリーを圃場詳細に表示 4. **気象アラート**: 猛暑・長雨・強風などの異常気象を検知して通知 --- ## 注意事項 - Open-Meteo archive API は**前日まで**のデータしか取得できない(リアルタイム不可) - `pressure_min` は `surface_pressure_min`(地表気圧)。海面更正気圧とは異なる - Open-Meteo の `sunshine_duration` は秒単位 → `sunshine_h` = 秒 ÷ 3600 で変換