ドキュメント整備が全て完了しました。今回のセッションで行った作業のまとめ: 実装した機能 Windmill フロー f/weather/weather_sync(毎朝6時 Asia/Tokyo)の作成・本番稼働 /weather フロントエンドページ(年別集計 / 期間指定の2モード) Recharts 3.7.0 による月別・日次グラフ(気温折れ線、降水量棒+日照折れ線 2軸) 整備したドキュメント ドキュメント 内容 CLAUDE.md weather 画面追加・Windmill フロー・マスタードキュメントリンク document/12_マスタードキュメント_気象データ編.md 気象機能の完全リファレンス(新規作成) MEMORY.md Windmill API パターン・Recharts TypeScript パターン Trilium マスタードキュメント フロントエンド2モード・Recharts・document/12_ 参照追加
7.6 KiB
7.6 KiB
気象データ機能 マスタードキュメント
最終更新: 2026-02-28 状態: 本番稼働中
概要
Open-Meteo archive API から窪川の気象データを日次取得し、PostgreSQL に蓄積する。 農業における積算温度計算・類似年分析・作期の気象振り返りを目的とする。
- 観測地点: 窪川 (lat=33.213, lon=133.133)
- データソース: Open-Meteo Archive API(無料)
- 蓄積期間: 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": [...]}
[
{
"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
- レスポンス:
{
"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(省略時=昨日)
- レスポンス:
{
"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 を返す
- アルゴリズム: (平均気温, 総降水量, 総日照時間) の正規化ユークリッド距離
- レスポンス:
{
"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": [...]
}
]
}
管理コマンド
# 全期間取得(初回のみ)
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 以降)
- GDD 到達日予測:
Crop.base_tempを使い、播種日から目標GDDに達する日を予測 - 類似年ベースの収穫予測: 類似年の収穫時期を参考に今年の予測を表示
- 作付け計画との連携: 作期ごとの気象サマリーを圃場詳細に表示
- 気象アラート: 猛暑・長雨・強風などの異常気象を検知して通知
注意事項
- Open-Meteo archive API は前日までのデータしか取得できない(リアルタイム不可)
pressure_minはsurface_pressure_min(地表気圧)。海面更正気圧とは異なる- Open-Meteo の
sunshine_durationは秒単位 →sunshine_h= 秒 ÷ 3600 で変換