""" Modelo de Dispositivo GPS/Tracker para vehículos. """ from datetime import datetime from sqlalchemy import ( Boolean, DateTime, Float, ForeignKey, Integer, String, Text, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.database import Base from app.models.base import TimestampMixin class Dispositivo(Base, TimestampMixin): """Modelo de dispositivo GPS/tracker instalado en un vehículo.""" __tablename__ = "dispositivos" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) # Relación con vehículo vehiculo_id: Mapped[int] = mapped_column( ForeignKey("vehiculos.id", ondelete="CASCADE"), nullable=False, index=True, ) # Tipo de dispositivo tipo: Mapped[str] = mapped_column( String(50), nullable=False, default="gps", ) # gps, obd, meshtastic, smartphone # Identificación identificador: Mapped[str] = mapped_column( String(100), unique=True, nullable=False, index=True, ) # ID único del dispositivo nombre: Mapped[str | None] = mapped_column(String(100), nullable=True) marca: Mapped[str | None] = mapped_column(String(50), nullable=True) modelo: Mapped[str | None] = mapped_column(String(50), nullable=True) numero_serie: Mapped[str | None] = mapped_column(String(100), nullable=True) # Información de SIM telefono_sim: Mapped[str | None] = mapped_column(String(20), nullable=True) operador_sim: Mapped[str | None] = mapped_column(String(50), nullable=True) iccid: Mapped[str | None] = mapped_column(String(25), nullable=True) # ID de la SIM # IMEI (para dispositivos celulares) imei: Mapped[str | None] = mapped_column(String(20), nullable=True, unique=True) # Protocolo de comunicación protocolo: Mapped[str] = mapped_column( String(50), default="osmand", nullable=False, ) # osmand, traccar, gt06, meshtastic, mqtt # Estado de conexión ultimo_contacto: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) bateria: Mapped[float | None] = mapped_column(Float, nullable=True) # Porcentaje 0-100 señal_gsm: Mapped[int | None] = mapped_column(Integer, nullable=True) # Nivel de señal satelites: Mapped[int | None] = mapped_column(Integer, nullable=True) # Satélites GPS # Configuración del dispositivo intervalo_reporte: Mapped[int] = mapped_column( Integer, default=30, nullable=False, ) # Segundos entre reportes configuracion: Mapped[str | None] = mapped_column(Text, nullable=True) # JSON con config adicional # Firmware firmware_version: Mapped[str | None] = mapped_column(String(50), nullable=True) # Estado activo: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) conectado: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # Notas notas: Mapped[str | None] = mapped_column(Text, nullable=True) # Relaciones ORM vehiculo: Mapped["Vehiculo"] = relationship( "Vehiculo", back_populates="dispositivos", lazy="selectin", ) @property def esta_online(self) -> bool: """Verifica si el dispositivo está online (último contacto < 5 minutos).""" if not self.ultimo_contacto: return False from datetime import timezone, timedelta tiempo_limite = datetime.now(timezone.utc) - timedelta(minutes=5) return self.ultimo_contacto > tiempo_limite def __repr__(self) -> str: return f""