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 porstatus="online", screenshots_enabled=True.dispatch_screenshot_ops()filtra porstatus="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(): devuelvelast_screenshotvacío si no existe fichero.signage/api/portal.py→portal_players(): devuelvelast_screenshotvacío si no existe fichero.signage/api/proof_of_play.py→get_screenshot(): devuelvescreenshot_pathvacío yhas_screenshot=Falsesi 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:
test_player_con_screenshots_off_no_se_despacha: Verifica que un player conscreenshots_enabled=Falseno genera ninguna tarea de captura.test_screenshot_available_exige_fichero_real: Verifica que la propiedadscreenshot_availabledevuelveFalsesi la ruta no apunta a un fichero real, yTruesi 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]]