This commit is contained in:
2026-05-05 23:54:44 +03:30
parent 4e28bacad6
commit 35f4d09225
12 changed files with 1291 additions and 29 deletions
+734
View File
@@ -0,0 +1,734 @@
# Device Hub API Guide
این فایل مستند API های تعریف‌شده در `device_hub/urls.py` را توضیح می‌دهد. مسیر پایه این API ها طبق `config/urls.py` برابر است با:
- `api/device-hub/`
بیشتر endpointها نیاز به احراز هویت کاربر دارند و معمولاً با ساختار زیر پاسخ می‌دهند:
```json
{
"code": 200,
"msg": "success",
"data": {}
}
```
## نحوه ارتباط با API ها
### 1) احراز هویت
- برای بیشتر endpointها باید کاربر لاگین باشد.
- معمولاً توکن را در هدر `Authorization` ارسال می‌کنید.
- نمونه:
```http
Authorization: Bearer <token>
Content-Type: application/json
```
### 2) آدرس پایه
اگر دامنه پروژه مثلاً `https://example.com` باشد، آدرس کامل endpointها به این صورت است:
- `https://example.com/api/device-hub/catalog/`
- `https://example.com/api/device-hub/devices/<physical_device_uuid>/latest/?device_code=<code>`
### 3) پارامترهای مهم
- `physical_device_uuid`: شناسه فیزیکی دستگاه
- `device_code`: کد نوع device داخل catalog
- `range`: بازه زمانی (`1h`, `24h`, `7d`, `30d`, `today` بسته به endpoint)
- `page` و `page_size`: برای صفحه‌بندی لاگ‌ها
---
## 1. دریافت لیست کاتالوگ دستگاه‌ها
### Endpoint
- `GET /api/device-hub/catalog/`
- `GET /api/device-hub/`
### کاربرد
برای گرفتن لیست همه device catalogها استفاده می‌شود.
### درخواست نمونه
```bash
curl -X GET "https://example.com/api/device-hub/catalog/" \
-H "Authorization: Bearer <token>"
```
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"data": [
{
"uuid": "11111111-1111-1111-1111-111111111111",
"code": "soil_sensor_v2",
"name": "Soil Sensor V2",
"description": "",
"device_communication_type": "output_only",
"customizable_fields": [],
"supported_power_sources": [],
"returned_data_fields": ["soil_moisture", "soil_temperature"],
"payload_mapping": {
"soil_moisture": ["moisture", "soil_moisture"],
"soil_temperature": ["temperature", "soil_temperature"]
},
"display_schema": {},
"supported_widgets": ["values_list", "comparison_chart", "radar_chart"],
"commands_schema": [],
"capabilities": [],
"sample_payload": {},
"is_active": true
}
]
}
```
### فیلدهای مهم پاسخ
- `device_communication_type`: نوع ارتباط دستگاه (`output_only` یا `input_only`)
- `returned_data_fields`: داده‌هایی که device برمی‌گرداند
- `payload_mapping`: نگاشت کلیدهای payload خام به فیلدهای نرمال
- `supported_widgets`: ویجت‌هایی که فرانت می‌تواند نمایش دهد
- `commands_schema`: لیست commandهای قابل ارسال برای deviceهای commandable
---
## 2. جزئیات یک دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/?device_code=<device_code>`
### کاربرد
اطلاعات کلی دستگاه ثبت‌شده در فارم را برمی‌گرداند.
### Query Params
- `device_code` اجباری
### درخواست نمونه
```bash
curl -X GET "https://example.com/api/device-hub/devices/22222222-2222-2222-2222-222222222222/?device_code=soil_sensor_v2" \
-H "Authorization: Bearer <token>"
```
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"data": {
"uuid": "33333333-3333-3333-3333-333333333333",
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"name": "Soil Device 1",
"sensor_type": "soil",
"is_active": true,
"specifications": {},
"power_source": {},
"device_catalog": {
"uuid": "11111111-1111-1111-1111-111111111111",
"code": "soil_sensor_v2",
"name": "Soil Sensor V2",
"description": "",
"device_communication_type": "output_only",
"customizable_fields": [],
"supported_power_sources": [],
"returned_data_fields": ["soil_moisture", "soil_temperature"],
"payload_mapping": {},
"display_schema": {},
"supported_widgets": ["values_list", "comparison_chart", "radar_chart"],
"commands_schema": [],
"capabilities": [],
"sample_payload": {},
"is_active": true
},
"device_catalogs": [],
"last_payload_at": "2025-01-01T10:00:00Z",
"created_at": "2025-01-01T09:00:00Z",
"updated_at": "2025-01-01T09:00:00Z"
}
}
```
### نکته
- اگر `physical_device_uuid` متعلق به کاربر نباشد، خطای 400 با متن `Device not found.` برمی‌گردد.
- اگر `device_code` به این دستگاه attach نشده باشد، خطای validation دریافت می‌کنید.
---
## 3. آخرین payload دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/latest/?device_code=<device_code>`
### کاربرد
آخرین payload خام و نرمال‌شده دستگاه را می‌دهد.
### Query Params
- `device_code` اجباری
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"data": {
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"device_code": "soil_sensor_v2",
"device_catalog_code": "soil_sensor_v2",
"raw_payload": {
"moisture": 52.4,
"temperature": 23.1
},
"normalized_payload": {
"soil_moisture": 52.4,
"soil_temperature": 23.1
},
"readings": {
"soil_moisture": 52.4,
"soil_temperature": 23.1
},
"created_at": "2025-01-01T10:00:00Z"
}
}
```
### معنی فیلدها
- `raw_payload`: داده خامی که از لاگ ذخیره‌شده آمده
- `normalized_payload`: داده تبدیل‌شده بر اساس `payload_mapping`
- `readings`: مقادیر قابل نمایش برای UI
---
## 4. خلاصه دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/summary/?device_code=<device_code>`
### کاربرد
یک summary مناسب UI برمی‌گرداند؛ مثلاً ویجت‌های قابل نمایش، values list، chartها و commandها.
### Query Params
- `device_code` اجباری
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"data": {
"sensor": {
"name": "Soil Device 1",
"physicalDeviceUuid": "22222222-2222-2222-2222-222222222222",
"sensorCatalogCode": "soil_sensor_v2",
"updatedAt": "2025-01-01T10:00:00Z"
},
"supportedWidgets": ["values_list", "comparison_chart", "radar_chart"],
"sensorValuesList": {
"sensor": {
"name": "Soil Device 1",
"physicalDeviceUuid": "22222222-2222-2222-2222-222222222222",
"sensorCatalogCode": "soil_sensor_v2",
"updatedAt": "2025-01-01T10:00:00Z"
},
"sensors": [
{
"id": "soil_moisture",
"title": "رطوبت خاک",
"subtitle": "45-65%",
"trendNumber": 52.4,
"trend": "normal",
"unit": "%"
}
]
},
"commands": []
}
}
```
### نکته
- شکل دقیق `data` بسته به `supported_widgets` و نوع catalog تغییر می‌کند.
- اگر history وجود نداشته باشد، معمولاً خطای 400 برمی‌گردد.
---
## 5. نمودار مقایسه‌ای دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/comparison-chart/?device_code=<device_code>&range=7d`
### Query Params
- `device_code` اجباری
- `range` اختیاری: `7d` یا `30d`
### پاسخ نمونه
```json
{
"series": [
{
"name": "Moisture",
"data": [50.0, 51.2, 52.4]
},
{
"name": "Temperature",
"data": [22.0, 22.4, 23.1]
}
],
"categories": ["شنبه", "یکشنبه", "دوشنبه"],
"currentValue": 52.4,
"vsLastWeek": "+3.1%"
}
```
### نکته
- این endpoint برخلاف بعضی endpointهای دیگر wrapper `code/msg` ندارد و مستقیم data chart را برمی‌گرداند.
---
## 6. لیست مقادیر دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/values-list/?device_code=<device_code>&range=7d`
### Query Params
- `device_code` اجباری
- `range` اختیاری: `1h`، `24h`، `7d`
### پاسخ نمونه
```json
{
"sensors": [
{
"title": "Moisture",
"subtitle": "45-65%",
"trendNumber": 52.4,
"trend": "positive",
"unit": "%"
},
{
"title": "Temperature",
"subtitle": "18-28°C",
"trendNumber": 23.1,
"trend": "positive",
"unit": "°C"
}
]
}
```
### نکته
- این endpoint هم مستقیم JSON داده را برمی‌گرداند و wrapper `code/msg` ندارد.
---
## 7. رادار چارت دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/radar-chart/?device_code=<device_code>&range=7d`
### Query Params
- `device_code` اجباری
- `range` اختیاری: `today`، `7d`، `30d`
### پاسخ نمونه
```json
{
"labels": ["Moisture", "Temperature", "PH", "EC"],
"series": [
{
"name": "Current",
"data": [52.4, 23.1, 6.7, 1.1]
}
]
}
```
### نکته
- این endpoint هم مستقیم data را برمی‌گرداند.
---
## 8. لاگ‌های دستگاه
### Endpoint
- `GET /api/device-hub/devices/<physical_device_uuid>/logs/?device_code=<device_code>&page=1&page_size=20`
### Query Params
- `device_code` اجباری
- `page` اختیاری، پیش‌فرض `1`
- `page_size` اختیاری، پیش‌فرض `20`، حداکثر `100`
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"count": 1,
"next": null,
"previous": null,
"data": [
{
"id": 10,
"farm_uuid": "44444444-4444-4444-4444-444444444444",
"sensor_catalog_uuid": "11111111-1111-1111-1111-111111111111",
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"farm_device": {
"uuid": "33333333-3333-3333-3333-333333333333",
"sensor_catalog_uuid": "11111111-1111-1111-1111-111111111111",
"device_catalogs": [],
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"name": "Soil Device 1",
"sensor_type": "soil",
"is_active": true,
"specifications": {},
"power_source": {},
"created_at": "2025-01-01T09:00:00Z",
"updated_at": "2025-01-01T09:00:00Z"
},
"sensor_catalog": {
"uuid": "11111111-1111-1111-1111-111111111111",
"code": "soil_sensor_v2",
"name": "Soil Sensor V2",
"description": "",
"device_communication_type": "output_only",
"customizable_fields": [],
"supported_power_sources": [],
"returned_data_fields": [],
"payload_mapping": {},
"display_schema": {},
"supported_widgets": [],
"commands_schema": [],
"capabilities": [],
"sample_payload": {},
"is_active": true,
"created_at": "2025-01-01T09:00:00Z",
"updated_at": "2025-01-01T09:00:00Z"
},
"payload": {
"moisture": 52.4,
"temperature": 23.1
},
"created_at": "2025-01-01T10:00:00Z"
}
]
}
```
### کاربرد
- برای history دستگاه
- برای نمایش payloadهای دریافت‌شده از device
- برای debug یا audit
---
## 9. ارسال command به دستگاه
### Endpoint
- `POST /api/device-hub/devices/<physical_device_uuid>/commands/`
### کاربرد
برای deviceهایی که `input_only` یا commandable هستند، command ارسال می‌کند.
### Body
```json
{
"device_code": "valve_v1",
"command": "open",
"payload": {
"duration_seconds": 120
}
}
```
### درخواست نمونه
```bash
curl -X POST "https://example.com/api/device-hub/devices/22222222-2222-2222-2222-222222222222/commands/" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"device_code": "valve_v1",
"command": "open",
"payload": {
"duration_seconds": 120
}
}'
```
### پاسخ نمونه
```json
{
"code": 200,
"msg": "command accepted",
"data": {
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"command": "open",
"status": "accepted"
}
}
```
### نکات
- `device_code` باید جزو catalogهای متصل به آن device باشد.
- اگر command یا device code معتبر نباشد، خطای 400 برمی‌گردد.
---
## 10. خلاصه سنسور 7in1
### Endpoint
- `GET /api/device-hub/summary/?farm_uuid=<farm_uuid>`
### کاربرد
خلاصه‌ای از سنسور اصلی مزرعه برای UI برمی‌گرداند.
### Query Params
- `farm_uuid` اجباری
### پاسخ نمونه
```json
{
"code": 200,
"msg": "OK",
"data": {
"sensor": {
"name": "Main Soil Sensor",
"physicalDeviceUuid": "22222222-2222-2222-2222-222222222222",
"sensorCatalogCode": "sensor-7-in-1",
"updatedAt": "2025-01-01T10:00:00Z"
},
"sensorValuesList": {},
"avgSoilMoisture": {},
"sensorRadarChart": {},
"sensorComparisonChart": {},
"anomalyDetectionCard": {},
"soilMoistureHeatmap": {}
}
}
```
---
## 11. ثبت payload خارجی دستگاه
### Endpoint
- `POST /api/device-hub/external/`
### کاربرد
این endpoint برای سیستم یا دستگاه خارجی است تا payload را به backend ارسال کند.
این endpoint با API key اختصاصی کار می‌کند، نه با توکن کاربر.
### Header
```http
X-API-Key: <api_key>
Content-Type: application/json
```
### Body
```json
{
"uuid": "22222222-2222-2222-2222-222222222222",
"payload": {
"moisture_percent": 32.5,
"temperature_c": 21.3,
"ph": 6.7,
"ec_ds_m": 1.1,
"nitrogen_mg_kg": 42,
"phosphorus_mg_kg": 18,
"potassium_mg_kg": 210
}
}
```
### رفتار endpoint
- payload را در `SensorExternalRequestLog` ذخیره می‌کند
- notification می‌سازد
- payload را به farm-data service فوروارد می‌کند
### پاسخ موفق نمونه
```json
{
"code": 201,
"msg": "success",
"data": {
"id": 1,
"title": "Sensor external API request"
}
}
```
### خطاهای مهم
- `401`: اگر `X-API-Key` اشتباه یا خالی باشد
- `404`: اگر `physical device` پیدا نشود
- `503`: اگر migrationها آماده نباشند یا سرویس farm-data در دسترس نباشد
---
## 12. لیست لاگ‌های ورودی خارجی
### Endpoint
- `GET /api/device-hub/external/logs/?farm_uuid=<farm_uuid>&page=1&page_size=20`
### Query Params
- `farm_uuid` اجباری
- `page` اجباری در داکیومنت، ولی در عمل اگر نفرستید پیش‌فرض `1` دارد در paginator
- `page_size` اجباری در داکیومنت
- `physical_device_uuid` اختیاری
- `sensor_type` اختیاری
- `date_from` اختیاری
- `date_to` اختیاری
### پاسخ نمونه
```json
{
"code": 200,
"msg": "success",
"count": 25,
"next": "https://example.com/api/device-hub/external/logs/?page=2",
"previous": null,
"data": [
{
"id": 10,
"farm_uuid": "44444444-4444-4444-4444-444444444444",
"sensor_catalog_uuid": "11111111-1111-1111-1111-111111111111",
"physical_device_uuid": "22222222-2222-2222-2222-222222222222",
"farm_device": null,
"sensor_catalog": null,
"payload": {
"moisture": 52.4
},
"created_at": "2025-01-01T10:00:00Z"
}
]
}
```
---
## الگوی خطاها
### Validation Error
در بیشتر خطاهای اعتبارسنجی، پاسخ شبیه این است:
```json
{
"device_code": [
"Device code is not attached to this farm device."
]
}
```
یا:
```json
{
"physical_device_uuid": [
"Device not found."
]
}
```
### Unauthorized
اگر توکن کاربر یا API key درست نباشد، پاسخ 401 دریافت می‌کنید.
### Service Unavailable
در endpointهای `external` اگر migration یا سرویس وابسته آماده نباشد:
```json
{
"code": 503,
"msg": "Required tables are not ready. Run migrations."
}
```
---
## ترتیب پیشنهادی استفاده در فرانت
برای صفحه جزئیات device معمولاً این ترتیب مناسب است:
1. گرفتن catalogها از `GET /api/device-hub/catalog/`
2. گرفتن جزئیات device از `GET /api/device-hub/devices/<uuid>/?device_code=...`
3. گرفتن summary از `GET /api/device-hub/devices/<uuid>/summary/?device_code=...`
4. در صورت نیاز گرفتن:
- latest payload
- comparison chart
- radar chart
- values list
- logs
برای deviceهای commandable:
1. از `commands_schema` در catalog commandهای مجاز را بخوانید
2. سپس به `POST /api/device-hub/devices/<uuid>/commands/` درخواست بزنید
---
## محل فایل‌های مرتبط در کد
- مسیرها: `device_hub/urls.py`
- ویوها: `device_hub/views.py`
- serializerها: `device_hub/serializers.py`
- serializerهای summary/chart: `device_hub/sensor_serializers.py`
- مسیر پایه پروژه: `config/urls.py`
+5
View File
@@ -155,6 +155,11 @@ class DeviceCommandResponseSerializer(serializers.Serializer):
status = serializers.CharField()
class DeviceCodeListResponseSerializer(serializers.Serializer):
physical_device_uuid = serializers.UUIDField()
device_codes = serializers.ListField(child=serializers.CharField())
class SensorExternalRequestLogSerializer(serializers.ModelSerializer):
farm_device = serializers.SerializerMethodField()
sensor_catalog = serializers.SerializerMethodField()
+2 -2
View File
@@ -1097,7 +1097,7 @@ def build_device_soil_moisture_heatmap(farm_device, context=None, *, device_cata
message=f"Device heatmap has no usable numeric series for farm_device_id={getattr(farm_device, 'id', None)}.",
details={"farm_device_id": getattr(farm_device, "id", None)},
)
sensor_name = farm_device.name if farm_device and farm_device.name else SOIL_MOISTURE_HEATMAP["zones"][0]
sensor_name = farm_device.name if farm_device and farm_device.name else "Sensor"
return {
"zones": [sensor_name],
"hours": [point["x"] for point in chart_points],
@@ -1128,7 +1128,7 @@ def build_device_avg_primary_metric(farm_device, context=None, *, device_catalog
)
chip_text, chip_color, avatar_color = _calculate_status_chip(primary_value)
return {
**deepcopy(AVG_SOIL_MOISTURE),
**deepcopy(AVG_SOIL_MOISTURE_TEMPLATE),
"title": primary_field["label"],
"stats": _format_value(primary_value, primary_field["unit"]),
"chipText": chip_text,
+31 -1
View File
@@ -6,7 +6,7 @@ from farm_hub.models import FarmHub, FarmType
from .models import DeviceCatalog, SensorExternalRequestLog
from .services import DeviceDataUnavailableError, build_device_anomaly_detection_card
from .views import DeviceCommandView, DeviceDetailView, DeviceLatestPayloadView, DeviceSummaryView
from .views import DeviceCodeListView, DeviceCommandView, DeviceDetailView, DeviceLatestPayloadView, DeviceSummaryView
class DeviceHubGenericViewsTests(TestCase):
@@ -66,6 +66,36 @@ class DeviceHubGenericViewsTests(TestCase):
self.assertEqual(response.data["data"]["physical_device_uuid"], str(self.device.physical_device_uuid))
self.assertEqual(response.data["data"]["device_catalog"]["code"], self.catalog.code)
def test_device_code_list_view_returns_attached_device_codes(self):
secondary_catalog = DeviceCatalog.objects.create(
code="air_sensor_v1",
name="Air Sensor V1",
device_communication_type=DeviceCatalog.OUTPUT_ONLY,
)
self.device.device_catalogs.add(self.catalog, secondary_catalog)
request = self.factory.get(
f"/api/device-hub/devices/{self.device.physical_device_uuid}/device-codes/",
)
force_authenticate(request, user=self.user)
response = DeviceCodeListView.as_view()(request, physical_device_uuid=self.device.physical_device_uuid)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["data"]["physical_device_uuid"], str(self.device.physical_device_uuid))
self.assertEqual(response.data["data"]["device_codes"], [self.catalog.code, secondary_catalog.code])
def test_device_code_list_view_returns_primary_catalog_when_no_m2m_catalogs_exist(self):
request = self.factory.get(
f"/api/device-hub/devices/{self.device.physical_device_uuid}/device-codes/",
)
force_authenticate(request, user=self.user)
response = DeviceCodeListView.as_view()(request, physical_device_uuid=self.device.physical_device_uuid)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["data"]["device_codes"], [self.catalog.code])
def test_device_latest_payload_view_returns_normalized_readings(self):
request = self.factory.get(
f"/api/device-hub/devices/{self.device.physical_device_uuid}/latest/",
+2 -1
View File
@@ -1,9 +1,10 @@
from django.urls import path
from .views import DeviceCatalogListView, DeviceCommandView, DeviceComparisonChartView, DeviceDetailView, DeviceLatestPayloadView, DeviceLogListView, DeviceRadarChartView, DeviceSummaryView, DeviceValuesListView, Sensor7In1SummaryView, SensorExternalAPIView, SensorExternalRequestLogListAPIView
from .views import DeviceCatalogListView, DeviceCodeListView, DeviceCommandView, DeviceComparisonChartView, DeviceDetailView, DeviceLatestPayloadView, DeviceLogListView, DeviceRadarChartView, DeviceSummaryView, DeviceValuesListView, Sensor7In1SummaryView, SensorExternalAPIView, SensorExternalRequestLogListAPIView
urlpatterns = [
path("catalog/", DeviceCatalogListView.as_view(), name="device-catalog-list"),
path("devices/<uuid:physical_device_uuid>/device-codes/", DeviceCodeListView.as_view(), name="device-code-list"),
path("devices/<uuid:physical_device_uuid>/", DeviceDetailView.as_view(), name="device-detail"),
path("devices/<uuid:physical_device_uuid>/latest/", DeviceLatestPayloadView.as_view(), name="device-latest-payload"),
path("devices/<uuid:physical_device_uuid>/summary/", DeviceSummaryView.as_view(), name="device-summary"),
+19 -1
View File
@@ -12,7 +12,7 @@ from soil.serializers import SoilComparisonChartSerializer, SoilRadarChartSerial
from .authentication import SensorExternalAPIKeyAuthentication
from .sensor_serializers import DeviceSummarySerializer, Sensor7In1SummarySerializer, SensorComparisonChartQuerySerializer, SensorComparisonChartResponseSerializer, SensorRadarChartQuerySerializer, SensorRadarChartResponseSerializer, SensorValuesListQuerySerializer, SensorValuesListResponseSerializer
from .serializers import DeviceCatalogSerializer, DeviceCodeQuerySerializer, DeviceCommandRequestSerializer, DeviceCommandResponseSerializer, DeviceDetailSerializer, DeviceLatestPayloadSerializer, DeviceRangeQuerySerializer, SensorExternalRequestLogQuerySerializer, SensorExternalRequestLogSerializer, SensorExternalRequestSerializer
from .serializers import DeviceCatalogSerializer, DeviceCodeListResponseSerializer, DeviceCodeQuerySerializer, DeviceCommandRequestSerializer, DeviceCommandResponseSerializer, DeviceDetailSerializer, DeviceLatestPayloadSerializer, DeviceRangeQuerySerializer, SensorExternalRequestLogQuerySerializer, SensorExternalRequestLogSerializer, SensorExternalRequestSerializer
from .services import DeviceDataUnavailableError, FarmDataForwardError, build_device_comparison_chart, build_device_latest_payload, build_device_radar_chart, build_device_summary, build_device_values_list, create_sensor_external_notification, execute_device_command, forward_sensor_payload_to_farm_data, get_farm_device_by_physical_uuid, get_farm_device_map_for_logs, get_primary_soil_sensor, get_sensor_7_in_1_comparison_chart_data, get_sensor_7_in_1_radar_chart_data, get_sensor_7_in_1_summary_data, get_sensor_comparison_chart_data, get_sensor_external_request_logs_for_farm, get_sensor_radar_chart_data, get_sensor_values_list_data, validate_output_device_catalog
@@ -51,6 +51,24 @@ class DeviceDetailView(DeviceBaseView):
return Response({"code": 200, "msg": "success", "data": serializer.data}, status=status.HTTP_200_OK)
class DeviceCodeListView(DeviceBaseView):
@extend_schema(tags=["Device Hub"], responses={200: code_response("DeviceCodeListResponse", data=DeviceCodeListResponseSerializer())})
def get(self, request, physical_device_uuid):
farm_device = self.get_farm_device(request, physical_device_uuid)
device_codes = [catalog.code for catalog in farm_device.get_device_catalogs() if getattr(catalog, "code", "")]
return Response(
{
"code": 200,
"msg": "success",
"data": {
"physical_device_uuid": farm_device.physical_device_uuid,
"device_codes": device_codes,
},
},
status=status.HTTP_200_OK,
)
class DeviceLatestPayloadView(DeviceBaseView):
@extend_schema(tags=["Device Hub"], parameters=[OpenApiParameter(name="device_code", type=OpenApiTypes.STR, location=OpenApiParameter.QUERY, required=True)], responses={200: code_response("DeviceLatestPayloadResponse", data=DeviceLatestPayloadSerializer())})
def get(self, request, physical_device_uuid):