UPDATE
This commit is contained in:
+107
-5
@@ -21,21 +21,34 @@ class SensorPayloadMixin:
|
||||
block = payload.get(sensor_key, {})
|
||||
return block if isinstance(block, dict) else {}
|
||||
|
||||
for block in payload.values():
|
||||
if isinstance(block, dict):
|
||||
return block
|
||||
for _sensor_key, block in self.iter_sensor_blocks():
|
||||
return block
|
||||
return {}
|
||||
|
||||
def iter_sensor_blocks(self):
|
||||
for sensor_key, block in self._payload().items():
|
||||
if isinstance(block, dict):
|
||||
yield sensor_key, block
|
||||
|
||||
def get_metric(self, metric_name: str, sensor_key: str | None = None):
|
||||
block = self.get_sensor_block(sensor_key)
|
||||
if metric_name in block:
|
||||
return block.get(metric_name)
|
||||
|
||||
for candidate in self._payload().values():
|
||||
if isinstance(candidate, dict) and metric_name in candidate:
|
||||
for _candidate_key, candidate in self.iter_sensor_blocks():
|
||||
if metric_name in candidate:
|
||||
return candidate.get(metric_name)
|
||||
return None
|
||||
|
||||
def get_sensor_keys(self) -> list[str]:
|
||||
return [sensor_key for sensor_key, _block in self.iter_sensor_blocks()]
|
||||
|
||||
def get_all_metrics(self) -> dict[str, dict]:
|
||||
return {
|
||||
sensor_key: dict(block)
|
||||
for sensor_key, block in self.iter_sensor_blocks()
|
||||
}
|
||||
|
||||
@property
|
||||
def soil_moisture(self):
|
||||
return self.get_metric("soil_moisture")
|
||||
@@ -151,6 +164,95 @@ class SensorData(SensorPayloadMixin, models.Model):
|
||||
def location_id(self):
|
||||
return self.center_location_id
|
||||
|
||||
@property
|
||||
def plant_snapshots(self):
|
||||
return [assignment.plant for assignment in self.plant_assignments.select_related("plant").order_by("position", "id")]
|
||||
|
||||
|
||||
class PlantCatalogSnapshot(models.Model):
|
||||
"""
|
||||
کپی خواندنی از کاتالوگ گیاه Backend برای مصرف ماژولهای AI.
|
||||
"""
|
||||
|
||||
backend_plant_id = models.PositiveIntegerField(
|
||||
unique=True,
|
||||
db_index=True,
|
||||
help_text="شناسه گیاه در Backend/plants",
|
||||
)
|
||||
name = models.CharField(max_length=255, db_index=True)
|
||||
slug = models.SlugField(max_length=255, blank=True, default="")
|
||||
icon = models.CharField(max_length=255, blank=True, default="leaf")
|
||||
description = models.TextField(blank=True, default="")
|
||||
metadata = models.JSONField(default=dict, blank=True)
|
||||
light = models.CharField(max_length=255, blank=True, default="")
|
||||
watering = models.CharField(max_length=255, blank=True, default="")
|
||||
soil = models.CharField(max_length=255, blank=True, default="")
|
||||
temperature = models.CharField(max_length=255, blank=True, default="")
|
||||
growth_stage = models.CharField(max_length=255, blank=True, default="")
|
||||
growth_stages = models.JSONField(blank=True, default=list)
|
||||
planting_season = models.CharField(max_length=255, blank=True, default="")
|
||||
harvest_time = models.CharField(max_length=255, blank=True, default="")
|
||||
spacing = models.CharField(max_length=255, blank=True, default="")
|
||||
fertilizer = models.CharField(max_length=255, blank=True, default="")
|
||||
health_profile = models.JSONField(default=dict, blank=True)
|
||||
irrigation_profile = models.JSONField(default=dict, blank=True)
|
||||
growth_profile = models.JSONField(default=dict, blank=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
source_updated_at = models.DateTimeField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="updated_at رکورد canonical در Backend",
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "farm_data_plantcatalogsnapshot"
|
||||
ordering = ["name", "backend_plant_id"]
|
||||
verbose_name = "plant catalog snapshot"
|
||||
verbose_name_plural = "plant catalog snapshots"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.backend_plant_id})"
|
||||
|
||||
|
||||
class FarmPlantAssignment(models.Model):
|
||||
"""
|
||||
رابطه مزرعه با snapshot گیاه برای read-model هوش مصنوعی.
|
||||
"""
|
||||
|
||||
farm = models.ForeignKey(
|
||||
SensorData,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="plant_assignments",
|
||||
db_column="farm_uuid",
|
||||
)
|
||||
plant = models.ForeignKey(
|
||||
PlantCatalogSnapshot,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="farm_assignments",
|
||||
)
|
||||
position = models.PositiveIntegerField(default=0)
|
||||
stage = models.CharField(max_length=64, blank=True, default="")
|
||||
metadata = models.JSONField(default=dict, blank=True)
|
||||
assigned_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "farm_data_farmplantassignment"
|
||||
ordering = ["position", "id"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["farm", "plant"],
|
||||
name="farm_data_unique_farm_plant_assignment",
|
||||
)
|
||||
]
|
||||
verbose_name = "farm plant assignment"
|
||||
verbose_name_plural = "farm plant assignments"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.farm_id} -> {self.plant_id}"
|
||||
|
||||
|
||||
class SensorParameter(models.Model):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user