Files
Logic/SENSOR_ARCHITECTURE_RECOMMENDATION.md
2026-05-11 03:27:21 +03:30

13 KiB

پیشنهاد معماری سنسور برای Backend و AI

مسئله اصلی

تو سناریوی شما ممکن است:

  • یک مزرعه چندین سنسور داشته باشد
  • سنسورها از vendorهای مختلف باشند
  • هر سنسور payload متفاوتی بفرستد
  • بعضی سنسورها یک metric مشترک مثل soil_moisture را هم‌زمان گزارش کنند
  • AI مجبور باشد هم raw data را بفهمد و هم یک view تجمیع‌شده برای recommendation داشته باشد

پس معماری سنسور باید این سه ویژگی را هم‌زمان داشته باشد:

  1. انعطاف‌پذیری در نوع سنسور
  2. قابلیت نگهداری چند سنسور برای یک farm
  3. قابلیت تبدیل raw sensor data به metricهای استاندارد برای AI

چیزی که الان در پروژه دارید

در Backend

  • Backend/farm_hub/models.py مدل FarmSensor را دارد برای register کردن سنسورهای هر مزرعه
  • Backend/sensor_catalog/models.py مدل SensorCatalog را دارد برای تعریف نوع/کاتالوگ سنسور
  • Backend/sensor_external_api/models.py لاگ raw requestهای دستگاه‌ها را نگه می‌دارد

یعنی Backend الان تا حد خوبی نقش device registry + ingestion gateway + audit log را دارد.

در AI

  • Ai/farm_data/models.py::SensorData داده سنسورها را در sensor_payload نگه می‌دارد
  • Ai/farm_data/models.py::SensorParameter پارامترهای قابل پشتیبانی هر sensor_key را نگه می‌دارد
  • Ai/farm_data/services.py روی payloadهای چند سنسوره metric resolve می‌کند

یعنی AI الان نقش farm context store + normalized sensor context را دارد.


جمع‌بندی نقش‌ها

به نظر من بهترین تفکیک این است:

Backend = owner دستگاه و جریان ورود داده

Backend باید مسئول این‌ها باشد:

  • ثبت سنسور برای مزرعه
  • نگهداری metadata دستگاه
  • احراز هویت request دستگاه
  • ثبت raw payload
  • forward کردن داده به AI

AI = owner داده تحلیلی و context مزرعه

AI باید مسئول این‌ها باشد:

  • نگهداری normalized view از داده سنسورها برای هر farm
  • استانداردسازی metricها
  • merge / aggregation / conflict resolution
  • feed کردن irrigation / fertilization / crop simulation / alerts / RAG

پیشنهاد معماری نهایی

1) در Backend فقط registry و ingestion را canonical نگه دار

SensorCatalog

این جدول باید تعریف‌کننده template سنسور باشد:

  • code
  • name
  • description
  • returned_data_fields
  • sample_payload
  • customizable_fields
  • supported_power_sources

ولی بهتر است بعداً این metadataها را قوی‌تر کنی:

  • measurement_schema
  • supported_metrics
  • payload_mapping
  • transport_type مثل http, mqtt, lorawan
  • vendor
  • model
  • firmware_constraints

FarmSensor

این جدول باید instance واقعی دستگاه روی مزرعه باشد.

پیشنهاد فیلدهای مفهومی:

  • farm
  • sensor_catalog
  • physical_device_uuid
  • name
  • sensor_type
  • installation_zone
  • depth_cm
  • position
  • status
  • last_seen_at
  • calibration
  • specifications
  • power_source
  • metadata

یعنی FarmSensor باید بگوید:

  • این دستگاه چیست
  • کجا نصب شده
  • چه زمانی آخرین بار data فرستاده
  • به چه farm تعلق دارد

2) در Backend raw event را جدا از registry نگه دار

الان SensorExternalRequestLog فقط لاگ request است. این خوب است، ولی برای مقیاس‌پذیری بهتر است دو لایه داشته باشی:

لایه اول: audit log

همان چیزی که الان داری:

  • raw payload
  • request time
  • physical device uuid
  • farm uuid

لایه دوم: normalized ingestion event

اگر بخواهی معماری تمیزتر شود، بهتر است یک مدل جدا هم داشته باشی، مثلاً:

  • SensorReadingEvent

که در آن این‌ها ذخیره شود:

  • farm_sensor
  • recorded_at
  • received_at
  • payload_raw
  • payload_normalized
  • ingestion_status
  • validation_errors

این مدل لازم نیست الان فوراً ساخته شود، ولی اگر سنسورها زیاد شوند خیلی کمک می‌کند.


3) در AI داده سنسورها را به شکل sensor-centric نگه دار، نه فقط metric-centric

الان Ai/farm_data/models.py::SensorData این ساختار را دارد:

{
  "sensor-7-1": {
    "soil_moisture": 22.4,
    "soil_temperature": 18.1
  },
  "leaf-sensor": {
    "leaf_wetness": 11
  }
}

این از نظر انعطاف‌پذیری خوب است، ولی یک ضعف دارد:

  • sensor_key بیشتر نوع سنسور را نشان می‌دهد، نه instance سنسور

اگر یک farm دو سنسور از یک type داشته باشد، این ساختار collision می‌دهد.

پیشنهاد بهتر

در AI payload را بر اساس sensor instance نگه دار، نه فقط type:

{
  "device:8c1e...": {
    "sensor_key": "sensor-7-1",
    "sensor_type": "soil_probe",
    "recorded_at": "2026-05-02T10:15:00Z",
    "metrics": {
      "soil_moisture": 22.4,
      "soil_temperature": 18.1
    },
    "metadata": {
      "depth_cm": 20,
      "zone": "north-1"
    }
  },
  "device:91af...": {
    "sensor_key": "sensor-7-1",
    "sensor_type": "soil_probe",
    "recorded_at": "2026-05-02T10:15:30Z",
    "metrics": {
      "soil_moisture": 24.1,
      "soil_temperature": 17.9
    },
    "metadata": {
      "depth_cm": 40,
      "zone": "north-1"
    }
  }
}

یعنی key اصلی بهتر است یکی از این‌ها باشد:

  • physical_device_uuid
  • یا farm_sensor.uuid

نه فقط sensor-7-1.


4) در AI یک لایه normalized metrics جدا بساز

AI برای recommendation نباید هر بار raw payload را از صفر تفسیر کند.

بهترین مدل ذهنی این است:

لایه A: raw sensor context

  • هر sensor instance چه چیزی فرستاده؟

لایه B: resolved farm metrics

  • برای farm در این لحظه soil_moisture نهایی چقدر است؟
  • source این metric کدام sensorها بوده؟
  • strategy حل conflict چه بوده؟

الان Ai/farm_data/services.py بخشی از این کار را انجام می‌دهد. این مسیر درست است.

پیشنهاد من:

  • sensor_payload = raw/near-raw normalized by device
  • resolved_metrics = خروجی استاندارد شده برای AI
  • metric_sources = توضیح اینکه هر metric از کجا آمده

این‌ها لازم نیست حتماً همگی DB column جدا باشند؛ فعلاً می‌توانند در service layer ساخته شوند. ولی از نظر معماری باید explicit باشند.


5) resolution strategy باید قابل تنظیم باشد

وقتی چند سنسور یک metric مشترک دارند، AI باید بداند چطور resolve کند.

مثلاً برای soil_moisture:

  • اگر چند سنسور هم‌عمق و هم‌زون باشند → average
  • اگر depth فرق دارد → shallow و deep را جدا نگه دار
  • اگر یکی unhealthy باشد → ignore
  • اگر یکی stale باشد → وزن کمتر بگیرد یا حذف شود

بنابراین برای هر metric این چیزها مهم می‌شوند:

  • recorded_at
  • depth_cm
  • zone
  • sensor_health
  • priority
  • confidence

الان average ساده خوب است برای شروع، ولی برای طراحی نهایی کافی نیست.


6) schema mapping را از business logic جدا کن

Backend و AI نباید به aliasهای vendor-specific وابسته بمانند.

مثلاً:

  • moisture_percent
  • soilMoisture
  • moisture
  • soil_moisture

همه باید به یک metric استاندارد map شوند:

  • soil_moisture

بهترین محل این mapping

به نظر من mapping باید در یک لایه canonical تعریف شود:

  • در SensorCatalog
  • یا در AI داخل SensorParameter.metadata

مثلاً:

{
  "code": "soil_moisture",
  "metadata": {
    "aliases": ["moisture_percent", "soilMoisture", "moisture"],
    "unit": "%",
    "valid_range": [0, 100]
  }
}

پیشنهاد عملی برای Backend

Backend چه چیزی نگه دارد؟

مدل‌های اصلی

  • SensorCatalog = تعریف نوع سنسور
  • FarmSensor = دستگاه نصب‌شده روی مزرعه
  • SensorExternalRequestLog = raw ingress log

مسئولیت‌ها

  • ثبت sensor inventory
  • validate کردن physical device
  • ثبت raw payload برای audit
  • attach کردن payload به farm درست
  • forward کردن payload به AI

چیزی که Backend نباید owner آن باشد

  • منطق aggregation نهایی برای recommendation
  • conflict resolution تخصصی برای سنسورهای متعدد
  • semantic interpretation نهایی برای AI outputs

پیشنهاد عملی برای AI

AI چه چیزی نگه دارد؟

SensorData

برای هر farm_uuid:

  • sensor_payload بر اساس device instance
  • plants
  • irrigation_method
  • center_location
  • weather_forecast

SensorParameter

برای تعریف metricهای استاندارد:

  • sensor_key
  • code
  • name_fa
  • unit
  • data_type
  • metadata

ولی پیشنهاد می‌کنم metadata را برای این موارد غنی‌تر کنی:

  • aliases
  • valid_range
  • aggregation_strategy
  • semantic_group
  • recommended_for

ساختار پیشنهادی payload بین Backend و AI

به‌جای فرستادن فقط این:

{
  "sensor-7-1": {
    "soil_moisture": 45.2
  }
}

بهتر است به این سمت بروی:

{
  "device:22222222-2222-2222-2222-222222222222": {
    "sensor_key": "sensor-7-1",
    "sensor_type": "soil_probe",
    "recorded_at": "2026-05-02T10:15:00Z",
    "metrics": {
      "soil_moisture": 45.2,
      "soil_temperature": 22.5
    },
    "metadata": {
      "depth_cm": 20,
      "zone": "zone-a"
    }
  }
}

اگر فعلاً نمی‌خواهی API را بشکنی، حداقل این migration path را برو:

  1. فعلاً sensor_payload فعلی را نگه دار
  2. اجازه بده علاوه بر sensor_key، physical_device_uuid هم به AI برسد
  3. در AI key داخلی را با device uuid بساز
  4. بعداً schema را کامل migrate کن

الگوی تصمیم‌گیری برای چند سنسور

برای AI پیشنهاد می‌کنم سه خروجی داشته باشی:

1) raw_sensor_payload

همه داده‌های هر device بدون از دست رفتن context

2) resolved_metrics

مثلاً:

{
  "soil_moisture": 23.2,
  "soil_temperature": 18.5
}

3) metric_sources

مثلاً:

{
  "soil_moisture": {
    "strategy": "weighted_average",
    "sensor_keys": ["device:a", "device:b"],
    "depths": [20, 40],
    "conflict": true
  }
}

این ساختار برای explainability خیلی مهم است.


چیزی که من پیشنهاد می‌کنم همین الان تغییر بدهی

تغییرات سریع و پرارزش

در Backend

  • به FarmSensor این فیلدها را اضافه کن:
    • metadata
    • installation_zone
    • depth_cm
    • last_seen_at
    • status

در AI

  • sensor_payload را به‌سمت instance-based key ببر
  • SensorParameter.metadata را برای alias و aggregation strategy غنی کن
  • resolver فعلی را از average ساده به strategy-based resolver ارتقا بده

در API بین Backend و AI

  • همراه payload این اطلاعات را هم بفرست:
    • physical_device_uuid
    • sensor_catalog_uuid
    • sensor_type
    • recorded_at
    • depth_cm یا zone

پیشنهاد naming

برای شفافیت بیشتر:

  • SensorCatalog = نوع سنسور
  • FarmSensor = سنسور نصب‌شده
  • SensorExternalRequestLog = raw ingest log
  • SensorData = farm sensor context

اگر بعداً مدل event اضافه کردی:

  • SensorReadingEvent = reading normalized per device

تصمیم نهایی من

اگر بخواهم خیلی خلاصه بگویم:

  • Backend باید registry, ingestion, audit را handle کند
  • AI باید normalization, aggregation, context-building, recommendation input را handle کند
  • key اصلی داده سنسور باید sensor instance باشد، نه فقط sensor_key
  • raw sensor data و resolved farm metrics باید از هم جدا باشند

نتیجه یک‌خطی

برای سنسورهای انعطاف‌پذیر و چندتایی، Backend را به‌عنوان لایه ثبت دستگاه و ورود raw data نگه دار و AI را به‌عنوان لایه استانداردسازی و تجمیع metricها؛ و مهم‌تر از همه، داده‌ها را بر اساس device instance مدل کن نه فقط نوع سنسور.