from typing import Optional, Dict, Any from datetime import datetime from pydantic import BaseModel, Field, validator # Shared properties class TelemetryBase(BaseModel): device_id: str latitude: Optional[float] = None longitude: Optional[float] = None altitude: Optional[float] = None speed: Optional[float] = None heading: Optional[float] = None satellites: Optional[int] = None gps_fixed: Optional[bool] = False battery_level: Optional[float] = None battery_voltage: Optional[float] = None signal_strength: Optional[int] = None temperature: Optional[float] = None humidity: Optional[float] = None solar_voltage: Optional[float] = None extra_data: Optional[Dict[str, Any]] = None device_timestamp: Optional[datetime] = None # Properties to receive on telemetry creation class TelemetryCreate(TelemetryBase): pass # IoT Device specific input schema (matches LILYGO device format) class IoTDeviceData(BaseModel): device_id: str device_name: Optional[str] = None firmware: Optional[str] = None temp: Optional[float] = None hum: Optional[float] = None solar_volt: Optional[float] = None battery_volt: Optional[float] = None signal: Optional[int] = None gps_fixed: Optional[bool] = False latitude: Optional[float] = None longitude: Optional[float] = None altitude: Optional[float] = None satellites: Optional[int] = None timestamp: Optional[int] = None # Unix timestamp from device @validator('temp', 'hum', 'solar_volt', 'battery_volt', pre=True) def validate_numbers(cls, v): if v is not None: return float(v) return v @validator('signal', 'satellites', 'timestamp', pre=True) def validate_integers(cls, v): if v is not None: return int(v) return v # Properties shared by models stored in DB class TelemetryInDBBase(TelemetryBase): id: int timestamp: datetime class Config: orm_mode = True # Properties to return to client class TelemetryResponse(TelemetryInDBBase): pass # Enhanced response with device info class TelemetryWithDevice(TelemetryResponse): device_name: Optional[str] = None device_model: Optional[str] = None firmware_version: Optional[str] = None