Files

244 lines
8.3 KiB
Python
Raw Permalink Normal View History

2026-04-06 23:50:24 +03:30
from rest_framework import serializers
2026-04-24 02:50:27 +03:30
from irrigation.models import IrrigationMethod
from irrigation.serializers import IrrigationMethodSerializer
2026-04-06 23:50:24 +03:30
from weather.models import WeatherForecast
2026-05-05 01:46:10 +03:30
from .models import (
DEFAULT_SENSOR_DATA_TYPE,
DEFAULT_SENSOR_KEY,
FarmPlantAssignment,
PlantCatalogSnapshot,
SensorData,
)
2026-04-06 23:50:24 +03:30
class SensorDataUpdateSerializer(serializers.Serializer):
"""ورودی آپدیت داده سنسور در ساختار JSON."""
farm_uuid = serializers.UUIDField(required=True)
farm_boundary = serializers.JSONField(required=True)
2026-05-09 16:55:06 +03:30
block_count = serializers.IntegerField(required=False, min_value=1, default=1)
2026-04-06 23:50:24 +03:30
sensor_key = serializers.CharField(required=False, default=DEFAULT_SENSOR_KEY)
sensor_payload = serializers.JSONField(required=False)
plant_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
2026-05-05 01:46:10 +03:30
help_text="لیست شناسه گیاهان canonical در Backend/plants",
2026-04-06 23:50:24 +03:30
)
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(
required=False,
allow_null=True,
help_text="شناسه روش آبیاری مرتبط",
)
2026-04-06 23:50:24 +03:30
def to_internal_value(self, data):
if not isinstance(data, dict):
raise serializers.ValidationError("بدنه درخواست باید JSON object باشد.")
payload = dict(data)
known_fields = {
"farm_uuid",
"farm_boundary",
2026-05-09 16:55:06 +03:30
"block_count",
2026-04-06 23:50:24 +03:30
"sensor_key",
"sensor_payload",
"plant_ids",
2026-04-24 02:50:27 +03:30
"irrigation_method_id",
2026-04-06 23:50:24 +03:30
}
flat_metrics = {
key: value
for key, value in payload.items()
if key not in known_fields
}
if flat_metrics:
sensor_key = payload.get("sensor_key", DEFAULT_SENSOR_KEY)
nested_payload = payload.get("sensor_payload") or {}
if nested_payload and not isinstance(nested_payload, dict):
raise serializers.ValidationError(
{"sensor_payload": "sensor_payload باید object باشد."}
)
merged_payload = dict(nested_payload)
current_sensor_payload = merged_payload.get(sensor_key, {})
if current_sensor_payload and not isinstance(current_sensor_payload, dict):
raise serializers.ValidationError(
{"sensor_payload": f"مقدار {sensor_key} باید object باشد."}
)
merged_sensor_payload = dict(current_sensor_payload)
merged_sensor_payload.update(flat_metrics)
merged_payload[sensor_key] = merged_sensor_payload
payload["sensor_payload"] = merged_payload
for key in flat_metrics:
payload.pop(key, None)
return super().to_internal_value(payload)
def validate_sensor_payload(self, value):
if not isinstance(value, dict):
raise serializers.ValidationError("sensor_payload باید object باشد.")
for sensor_key, sensor_values in value.items():
if not isinstance(sensor_values, dict):
raise serializers.ValidationError(
f"مقدار سنسور {sensor_key} باید object باشد."
)
return value
2026-04-24 02:50:27 +03:30
def validate_irrigation_method_id(self, value):
if value is None:
return value
if not IrrigationMethod.objects.filter(pk=value).exists():
raise serializers.ValidationError("روش آبیاری معتبر نیست.")
return value
2026-04-06 23:50:24 +03:30
def validate(self, attrs):
2026-04-24 02:50:27 +03:30
if (
"sensor_payload" not in attrs
and "plant_ids" not in attrs
and "irrigation_method_id" not in attrs
):
2026-04-06 23:50:24 +03:30
raise serializers.ValidationError(
2026-04-24 02:50:27 +03:30
"حداقل یکی از sensor_payload یا plant_ids یا irrigation_method_id باید ارسال شود."
2026-04-06 23:50:24 +03:30
)
return attrs
class SensorDataResponseSerializer(serializers.ModelSerializer):
"""سریالایزر خروجی برای SensorData."""
2026-05-05 01:46:10 +03:30
plant_ids = serializers.SerializerMethodField()
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(
source="irrigation_method.id",
read_only=True,
allow_null=True,
)
2026-04-06 23:50:24 +03:30
2026-05-05 01:46:10 +03:30
def get_plant_ids(self, obj):
return [plant.backend_plant_id for plant in obj.plant_snapshots]
2026-04-06 23:50:24 +03:30
class Meta:
model = SensorData
fields = [
"farm_uuid",
"center_location_id",
"weather_forecast_id",
"sensor_payload",
"plant_ids",
2026-04-24 02:50:27 +03:30
"irrigation_method_id",
2026-04-06 23:50:24 +03:30
"created_at",
"updated_at",
]
class SensorParameterSerializer(serializers.Serializer):
"""سریالایزر ورودی برای تعریف پارامترهای سنسورهای مختلف."""
sensor_key = serializers.CharField(max_length=64, required=False, default=DEFAULT_SENSOR_KEY)
code = serializers.CharField(max_length=64)
name_fa = serializers.CharField(max_length=128)
unit = serializers.CharField(max_length=32, required=False, allow_blank=True)
data_type = serializers.CharField(
max_length=32,
required=False,
default=DEFAULT_SENSOR_DATA_TYPE,
)
metadata = serializers.JSONField(required=False, default=dict)
class FarmCenterLocationSerializer(serializers.Serializer):
id = serializers.IntegerField()
lat = serializers.DecimalField(max_digits=9, decimal_places=6)
lon = serializers.DecimalField(max_digits=9, decimal_places=6)
farm_boundary = serializers.JSONField()
2026-05-09 16:55:06 +03:30
input_block_count = serializers.IntegerField()
block_layout = serializers.JSONField()
2026-04-06 23:50:24 +03:30
class WeatherForecastDetailSerializer(serializers.ModelSerializer):
class Meta:
model = WeatherForecast
fields = [
"id",
"forecast_date",
"temperature_min",
"temperature_max",
"temperature_mean",
"precipitation",
"precipitation_probability",
"humidity_mean",
"wind_speed_max",
"et0",
"weather_code",
]
class FarmSoilPayloadSerializer(serializers.Serializer):
resolved_metrics = serializers.JSONField()
metric_sources = serializers.JSONField()
2026-05-09 16:55:06 +03:30
satellite_snapshots = serializers.JSONField()
2026-04-06 23:50:24 +03:30
2026-05-05 01:46:10 +03:30
class PlantCatalogSnapshotSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(source="backend_plant_id", read_only=True)
class Meta:
model = PlantCatalogSnapshot
fields = [
"id",
"backend_plant_id",
"name",
"slug",
"icon",
"description",
"metadata",
"light",
"watering",
"soil",
"temperature",
"growth_stage",
"growth_stages",
"planting_season",
"harvest_time",
"spacing",
"fertilizer",
"health_profile",
"irrigation_profile",
"growth_profile",
"is_active",
"source_updated_at",
"updated_at",
]
class FarmPlantAssignmentSerializer(serializers.ModelSerializer):
plant_id = serializers.IntegerField(source="plant.backend_plant_id", read_only=True)
plant = PlantCatalogSnapshotSerializer(read_only=True)
class Meta:
model = FarmPlantAssignment
fields = [
"plant_id",
"position",
"stage",
"metadata",
"assigned_at",
"updated_at",
"plant",
]
2026-04-06 23:50:24 +03:30
class FarmDetailSerializer(serializers.Serializer):
center_location = FarmCenterLocationSerializer()
weather = WeatherForecastDetailSerializer(allow_null=True)
sensor_payload = serializers.JSONField()
2026-05-05 01:46:10 +03:30
sensor_schema = serializers.JSONField()
2026-04-06 23:50:24 +03:30
soil = FarmSoilPayloadSerializer()
plant_ids = serializers.ListField(child=serializers.IntegerField())
2026-05-05 01:46:10 +03:30
plants = PlantCatalogSnapshotSerializer(many=True)
plant_assignments = FarmPlantAssignmentSerializer(many=True)
2026-04-24 02:50:27 +03:30
irrigation_method_id = serializers.IntegerField(allow_null=True)
irrigation_method = IrrigationMethodSerializer(allow_null=True)
2026-04-06 23:50:24 +03:30
created_at = serializers.DateTimeField()
updated_at = serializers.DateTimeField()