CreaRack-SL

Validación de capturas disponibles en Signage y control por player

Problema resuelto

Las capturas de pantalla del player CCIB (player 3) llevaban más de 30 días fallando en silencio — el 100% de las veces. La tarea de captura encolaba automáticamente cada 30 minutos y se reencolaba para siempre:

  • 964 tareas generadas en ese período: 619 error, 345 timeout, 0 éxitos.
  • 48 fallos diarios sin alertas, ruido silencioso.
  • Imagen rota en la UI (pestaña Signage): el reproductor CCIB no podía ser capturado por su arquitectura de LAN aislada, y el fichero JPG de la última captura buena se borraba cada 30 días por retención automática.
  • Causa raíz: el player exige un Agente dentro de su misma red local (172.25.10.x); el único Agente de la flota no alcanza esa red, así que todas las capturas fallaban.

Soluciones implementadas

1. Interruptor screenshots_enabled por player (migración 0015)

Se añade nuevo campo en SignagePlayer con default=True:

screenshots_enabled = models.BooleanField(
    default=True,
    help_text="Off = the screenshot dispatcher skips this player (e.g. no Agent can reach its LAN)",
)

Implementación en ambas funciones despachador:

  • capture_all_screenshots() filtra por status="online", screenshots_enabled=True.
  • dispatch_screenshot_ops() filtra por status="online", screenshots_enabled=True.

Impacto operacional: El player CCIB (player 3) se apaga por datos tras el deploy (decisión de infraestructura), y el despachador deja de encolar tareas condenadas a fallar.

2. Validación screenshot_available (propiedad del modelo)

Se añade propiedad que valida existencia real del fichero en media:

@property
def screenshot_available(self) -> bool:
    """True solo si last_screenshot apunta a un fichero que EXISTE en media.
    
    La retención de 30 días puede borrar el JPG dejando la ruta huérfana:
    sin este check la UI pinta una imagen rota (ronda 13-08-2026, #223).
    """
    if not self.last_screenshot:
        return False
    import os
    from django.conf import settings
    
    return os.path.exists(os.path.join(settings.MEDIA_ROOT, self.last_screenshot))

Integración en APIs (3 endpoints):

  • signage/api/players.py → _player_to_dict(): devuelve last_screenshot vacío si no existe fichero.
  • signage/api/portal.py → portal_players(): devuelve last_screenshot vacío si no existe fichero.
  • signage/api/proof_of_play.py → get_screenshot(): devuelve screenshot_path vacío y has_screenshot=False si no existe fichero.

Impacto UI: Desaparece la imagen rota; la pestaña Signage solo muestra capturas reales.

Tests de contrato (test_signage_screenshot_cutover.py)

Se añaden 2 nuevos tests:

  1. test_player_con_screenshots_off_no_se_despacha: Verifica que un player con screenshots_enabled=False no genera ninguna tarea de captura.
  2. test_screenshot_available_exige_fichero_real: Verifica que la propiedad screenshot_available devuelve False si la ruta no apunta a un fichero real, y True si existe.

Deuda conocida (task #223)

El tercer defecto de la cadena de captura:

El mensaje de error del Agente quedaba literalmente vacío (str(asyncio.TimeoutError()) = ""), lo que impedía diagnosis. Esto es código del Agent (local, .exe) y requiere una release del Agente con instalador.

Anotado en task #223 para el próximo ciclo del Agente. NO va en esta versión (v1.66.9).

Límites honestos

Si en el futuro se desean capturas reales del player CCIB, la solución es:

  • Instalar un Agente dentro de la red 172.25.10.x (decisión de infraestructura).
  • O reconfigurar el player para usar un método de captura remota soportado.

Línea de tiempo

  • 13-08-2026: Deploy de v1.66.9 (ronda funcional).
  • Después del deploy: Player CCIB se apaga por datos; el despachador deja de generar 48 tareas fallidas/día.

Véase también

  • [[entity—signage—model—signageplayer]]
  • [[feature—signage—permisos-s121]]
  • [[feature—signage—hito-b-honestidad-adapters]]
  • [[feature—signage—etiqueta-honesta-push-v164]]