FlotillasGPS - Sistema completo de monitoreo de flotillas GPS
Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
This commit is contained in:
264
backend/app/schemas/video.py
Normal file
264
backend/app/schemas/video.py
Normal file
@@ -0,0 +1,264 @@
|
||||
"""
|
||||
Schemas Pydantic para Cámara, Grabación y Evento de Video.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from app.schemas.base import BaseSchema, TimestampSchema
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Schemas de Cámara
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class CamaraBase(BaseSchema):
|
||||
"""Schema base de cámara."""
|
||||
|
||||
nombre: str = Field(..., min_length=2, max_length=100)
|
||||
posicion: str = Field(default="frontal", max_length=50)
|
||||
tipo: str = Field(default="ip", max_length=50)
|
||||
|
||||
|
||||
class CamaraCreate(CamaraBase):
|
||||
"""Schema para crear cámara."""
|
||||
|
||||
vehiculo_id: int
|
||||
marca: Optional[str] = Field(None, max_length=50)
|
||||
modelo: Optional[str] = Field(None, max_length=50)
|
||||
numero_serie: Optional[str] = Field(None, max_length=100)
|
||||
resolucion: Optional[str] = Field(None, max_length=20)
|
||||
url_stream: Optional[str] = Field(None, max_length=500)
|
||||
puerto: Optional[int] = Field(None, ge=1, le=65535)
|
||||
protocolo: str = Field(default="rtsp", max_length=20)
|
||||
usuario: Optional[str] = Field(None, max_length=100)
|
||||
password: Optional[str] = Field(None, max_length=100) # Se encriptará
|
||||
mediamtx_path: Optional[str] = Field(None, max_length=100)
|
||||
grabacion_continua: bool = False
|
||||
grabacion_evento: bool = True
|
||||
duracion_pre_evento: int = Field(default=10, ge=0, le=60)
|
||||
duracion_post_evento: int = Field(default=20, ge=0, le=120)
|
||||
deteccion_colision: bool = False
|
||||
deteccion_distraccion: bool = False
|
||||
deteccion_fatiga: bool = False
|
||||
deteccion_cambio_carril: bool = False
|
||||
notas: Optional[str] = None
|
||||
|
||||
|
||||
class CamaraUpdate(BaseSchema):
|
||||
"""Schema para actualizar cámara."""
|
||||
|
||||
nombre: Optional[str] = Field(None, min_length=2, max_length=100)
|
||||
posicion: Optional[str] = Field(None, max_length=50)
|
||||
tipo: Optional[str] = Field(None, max_length=50)
|
||||
marca: Optional[str] = Field(None, max_length=50)
|
||||
modelo: Optional[str] = Field(None, max_length=50)
|
||||
numero_serie: Optional[str] = Field(None, max_length=100)
|
||||
resolucion: Optional[str] = Field(None, max_length=20)
|
||||
url_stream: Optional[str] = Field(None, max_length=500)
|
||||
puerto: Optional[int] = Field(None, ge=1, le=65535)
|
||||
protocolo: Optional[str] = Field(None, max_length=20)
|
||||
usuario: Optional[str] = Field(None, max_length=100)
|
||||
password: Optional[str] = Field(None, max_length=100)
|
||||
mediamtx_path: Optional[str] = Field(None, max_length=100)
|
||||
grabacion_continua: Optional[bool] = None
|
||||
grabacion_evento: Optional[bool] = None
|
||||
duracion_pre_evento: Optional[int] = Field(None, ge=0, le=60)
|
||||
duracion_post_evento: Optional[int] = Field(None, ge=0, le=120)
|
||||
deteccion_colision: Optional[bool] = None
|
||||
deteccion_distraccion: Optional[bool] = None
|
||||
deteccion_fatiga: Optional[bool] = None
|
||||
deteccion_cambio_carril: Optional[bool] = None
|
||||
activa: Optional[bool] = None
|
||||
notas: Optional[str] = None
|
||||
|
||||
|
||||
class CamaraResponse(CamaraBase, TimestampSchema):
|
||||
"""Schema de respuesta de cámara."""
|
||||
|
||||
id: int
|
||||
vehiculo_id: int
|
||||
marca: Optional[str] = None
|
||||
modelo: Optional[str] = None
|
||||
numero_serie: Optional[str] = None
|
||||
resolucion: Optional[str] = None
|
||||
url_stream: Optional[str] = None
|
||||
puerto: Optional[int] = None
|
||||
protocolo: str
|
||||
usuario: Optional[str] = None
|
||||
# password no se expone
|
||||
mediamtx_path: Optional[str] = None
|
||||
estado: str
|
||||
activa: bool
|
||||
ultima_conexion: Optional[datetime] = None
|
||||
grabacion_continua: bool
|
||||
grabacion_evento: bool
|
||||
duracion_pre_evento: int
|
||||
duracion_post_evento: int
|
||||
deteccion_colision: bool
|
||||
deteccion_distraccion: bool
|
||||
deteccion_fatiga: bool
|
||||
deteccion_cambio_carril: bool
|
||||
notas: Optional[str] = None
|
||||
|
||||
|
||||
class CamaraConVehiculo(CamaraResponse):
|
||||
"""Schema de cámara con información del vehículo."""
|
||||
|
||||
vehiculo_nombre: Optional[str] = None
|
||||
vehiculo_placa: Optional[str] = None
|
||||
|
||||
|
||||
class CamaraStreamURL(BaseSchema):
|
||||
"""Schema con URLs de streaming de una cámara."""
|
||||
|
||||
camara_id: int
|
||||
camara_nombre: str
|
||||
rtsp_url: Optional[str] = None
|
||||
hls_url: Optional[str] = None
|
||||
webrtc_url: Optional[str] = None
|
||||
estado: str
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Schemas de Grabación
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class GrabacionBase(BaseSchema):
|
||||
"""Schema base de grabación."""
|
||||
|
||||
camara_id: int
|
||||
vehiculo_id: int
|
||||
inicio_tiempo: datetime
|
||||
tipo: str = Field(default="continua", max_length=50)
|
||||
|
||||
|
||||
class GrabacionCreate(GrabacionBase):
|
||||
"""Schema para crear registro de grabación."""
|
||||
|
||||
archivo_url: str = Field(..., max_length=500)
|
||||
archivo_nombre: str = Field(..., max_length=255)
|
||||
formato: str = Field(default="mp4", max_length=10)
|
||||
|
||||
|
||||
class GrabacionResponse(GrabacionBase, TimestampSchema):
|
||||
"""Schema de respuesta de grabación."""
|
||||
|
||||
id: int
|
||||
fin_tiempo: Optional[datetime] = None
|
||||
duracion_segundos: Optional[int] = None
|
||||
archivo_url: str
|
||||
archivo_nombre: str
|
||||
tamaño_mb: Optional[float] = None
|
||||
formato: str
|
||||
resolucion: Optional[str] = None
|
||||
evento_video_id: Optional[int] = None
|
||||
lat: Optional[float] = None
|
||||
lng: Optional[float] = None
|
||||
estado: str
|
||||
thumbnail_url: Optional[str] = None
|
||||
notas: Optional[str] = None
|
||||
|
||||
# Calculado
|
||||
duracion_formateada: str
|
||||
|
||||
|
||||
class GrabacionResumen(BaseSchema):
|
||||
"""Schema resumido de grabación."""
|
||||
|
||||
id: int
|
||||
camara_id: int
|
||||
vehiculo_id: int
|
||||
inicio_tiempo: datetime
|
||||
duracion_formateada: str
|
||||
tipo: str
|
||||
thumbnail_url: Optional[str] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Schemas de Evento de Video
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class EventoVideoBase(BaseSchema):
|
||||
"""Schema base de evento de video."""
|
||||
|
||||
camara_id: int
|
||||
vehiculo_id: int
|
||||
tipo: str = Field(..., max_length=50)
|
||||
severidad: str = Field(default="media", pattern="^(baja|media|alta|critica)$")
|
||||
tiempo: datetime
|
||||
|
||||
|
||||
class EventoVideoCreate(EventoVideoBase):
|
||||
"""Schema para crear evento de video."""
|
||||
|
||||
lat: Optional[float] = Field(None, ge=-90, le=90)
|
||||
lng: Optional[float] = Field(None, ge=-180, le=180)
|
||||
velocidad: Optional[float] = Field(None, ge=0)
|
||||
descripcion: Optional[str] = None
|
||||
confianza: Optional[float] = Field(None, ge=0, le=100)
|
||||
datos_extra: Optional[str] = None
|
||||
snapshot_url: Optional[str] = Field(None, max_length=500)
|
||||
clip_url: Optional[str] = Field(None, max_length=500)
|
||||
clip_duracion: Optional[int] = Field(None, ge=0)
|
||||
|
||||
|
||||
class EventoVideoUpdate(BaseSchema):
|
||||
"""Schema para actualizar evento de video."""
|
||||
|
||||
revisado: Optional[bool] = None
|
||||
notas_revision: Optional[str] = None
|
||||
falso_positivo: Optional[bool] = None
|
||||
|
||||
|
||||
class EventoVideoResponse(EventoVideoBase, TimestampSchema):
|
||||
"""Schema de respuesta de evento de video."""
|
||||
|
||||
id: int
|
||||
lat: Optional[float] = None
|
||||
lng: Optional[float] = None
|
||||
velocidad: Optional[float] = None
|
||||
descripcion: Optional[str] = None
|
||||
confianza: Optional[float] = None
|
||||
datos_extra: Optional[str] = None
|
||||
revisado: bool
|
||||
revisado_por_id: Optional[int] = None
|
||||
revisado_en: Optional[datetime] = None
|
||||
notas_revision: Optional[str] = None
|
||||
falso_positivo: bool
|
||||
snapshot_url: Optional[str] = None
|
||||
clip_url: Optional[str] = None
|
||||
clip_duracion: Optional[int] = None
|
||||
|
||||
|
||||
class EventoVideoConRelaciones(EventoVideoResponse):
|
||||
"""Schema con información de cámara y vehículo."""
|
||||
|
||||
camara_nombre: Optional[str] = None
|
||||
vehiculo_nombre: Optional[str] = None
|
||||
vehiculo_placa: Optional[str] = None
|
||||
|
||||
|
||||
class EventoVideoResumen(BaseSchema):
|
||||
"""Schema resumido de evento de video."""
|
||||
|
||||
id: int
|
||||
tipo: str
|
||||
severidad: str
|
||||
tiempo: datetime
|
||||
vehiculo_nombre: str
|
||||
camara_nombre: str
|
||||
revisado: bool
|
||||
falso_positivo: bool
|
||||
snapshot_url: Optional[str] = None
|
||||
|
||||
|
||||
class TiposEventoVideoResponse(BaseSchema):
|
||||
"""Schema con tipos de eventos de video disponibles."""
|
||||
|
||||
tipos: List[dict] # [{codigo, nombre, severidad}]
|
||||
Reference in New Issue
Block a user