from __future__ import annotations from typing import Any from farm_data.models import SensorData from farm_data.services import build_ai_farm_snapshot from .services import get_forecast_for_location WMO_CONDITIONS = { 0: "صاف", 1: "عمدتاً صاف", 2: "نیمه‌ابری", 3: "ابری", 45: "مه", 48: "مه یخ‌زده", 51: "نم‌نم باران", 61: "بارش خفیف", 63: "بارش متوسط", 65: "بارش شدید", 71: "برف خفیف", 80: "رگبار", 95: "رعد و برق", } def _safe_number(value, default=0): return default if value is None else value def _average(values, default=0): clean_values = [value for value in values if value is not None] if not clean_values: return default return sum(clean_values) / len(clean_values) def _weather_condition(weather_code): return WMO_CONDITIONS.get(weather_code, "نامشخص") def _build_farm_weather_card(forecasts: list[Any], *, farm_uuid: str | None = None, ai_snapshot: dict[str, Any] | None = None) -> dict[str, Any]: if not forecasts: return { "condition": "نامشخص", "temperature": 0, "unit": "°C", "humidity": 0, "windSpeed": 0, "windUnit": "km/h", "chartData": {"labels": [], "series": [[]]}, "source_metadata": { "weather": {"source": "center_location_forecast", "policy": "center_location_latest_forecast"}, "agronomic_metrics": {"source": "build_ai_farm_snapshot", "policy": "cluster_block_farm_aggregated"}, }, } current_forecast = forecasts[0] labels = [str(forecast.forecast_date) for forecast in forecasts[:7]] series = [[round(_safe_number(forecast.temperature_mean, 0)) for forecast in forecasts[:7]]] return { "condition": _weather_condition(current_forecast.weather_code), "temperature": round(_safe_number(current_forecast.temperature_mean, current_forecast.temperature_max)), "unit": "°C", "humidity": round(_average([current_forecast.humidity_mean], default=0)), "windSpeed": round(_safe_number(current_forecast.wind_speed_max, 0)), "windUnit": "km/h", "chartData": { "labels": labels, "series": series, }, "source_metadata": { "weather": {"source": "center_location_forecast", "policy": "center_location_latest_forecast"}, "agronomic_metrics": { "source": "build_ai_farm_snapshot", "policy": "cluster_block_farm_aggregated", "available": bool(ai_snapshot), }, }, } class FarmWeatherService: def get_farm_weather_card(self, *, farm_uuid: str) -> dict[str, Any]: sensor = ( SensorData.objects.select_related("center_location") .filter(farm_uuid=farm_uuid) .first() ) if sensor is None: raise ValueError("Farm not found.") forecasts = get_forecast_for_location(sensor.center_location, days=7) ai_snapshot = build_ai_farm_snapshot(farm_uuid) return _build_farm_weather_card(forecasts, farm_uuid=farm_uuid, ai_snapshot=ai_snapshot)