← Volver al blog
Plugins #safety

Receta: seguridad laboral con detección de EPP y monitoreo de presencia

Marcá cascos y chalecos faltantes en una zona de trabajo durante el horario laboral, y detectá un puesto vacío o presencia fuera de hora. Dos apps de seguridad — con una nota honesta sobre cuál es experimental.

4 min de lectura
Read in English

Por qué monitorear la seguridad

Dos preguntas de seguridad se repiten en una obra: ¿todos usan su equipo de protección, y está la persona correcta en su puesto (y nadie cuando no debería)? StreamHub responde ambas desde cámaras que ya tenés — detección de EPP para cascos y chalecos, y monitoreo de presencia para puestos vacíos y actividad fuera de hora. Una advertencia por adelantado, dicha con honestidad: la detección de EPP es experimental y de carácter orientativo, no un sistema de seguridad certificado.

La arquitectura en palabras

Ambas son Studio Apps con workers Python. safety-ppe corre un modelo YOLOv8 de EPP de la comunidad (vía ONNX) sobre el stream, asocia el equipo con las personas en zonas durante el horario laboral configurado, y dispara ppe.violation con una captura cuando a alguien le falta un elemento requerido. presence corre detección de personas en zonas rectangulares y dispara presence.absent cuando una zona queda vacía demasiado tiempo, presence.returned cuando alguien vuelve, y presence.after_hours cuando una zona está ocupada fuera del horario.

1. Detección de EPP (experimental)

export BASE="https://your-server.example.com/api/v1"
export TOKEN="sk_...."

curl -X POST $BASE/apps/site/plugins/safety-ppe/install -H "Authorization: Bearer $TOKEN"

curl -X PATCH $BASE/apps/site/plugins/safety-ppe -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
        "enabled": true,
        "config": {
          "room": "dock",
          "requireHelmet": true,
          "requireVest": true,
          "zones": "[{\"name\":\"dock\",\"rect\":[0.1,0.2,0.5,0.7]}]",
          "workHours": "08:00-18:00",
          "workDays": "mon-fri",
          "callbackUrl": "https://safety.example.com/hooks/ppe"
        }
      }'

Defaults clave: requireHelmet / requireVest true; zones vacío significa una zona a cuadro completo; workHours / workDays vacíos significan siempre activo; sustainFrames 3 (dispara tras más de 3 detecciones consecutivas); cooldownSeconds 120; confidence 0.35; association 0.5; fps 1 (YOLOv8m es ~1s por cuadro por núcleo de CPU — mantenelo en 1 en CPU). El payload de ppe.violation es { event, app, room, ts, zone, missing, confidence, snapshot_path }, donde missing es helmet, vest o helmet,vest, firmado cuando callbackSecret está seteado.

2. Monitoreo de presencia

curl -X POST $BASE/apps/site/plugins/presence/install -H "Authorization: Bearer $TOKEN"

curl -X PATCH $BASE/apps/site/plugins/presence -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
        "enabled": true,
        "config": {
          "room": "front-desk",
          "zones": "[{\"id\":\"desk-1\",\"name\":\"Recepcion\",\"x\":0.1,\"y\":0.2,\"w\":0.3,\"h\":0.4}]",
          "schedule": "08:00-18:00",
          "scheduleDays": "mon-fri",
          "thresholdMin": 5,
          "afterHours": true,
          "timezone": "America/Argentina/Buenos_Aires"
        }
      }'

Las zonas de presence son rectángulos (x/y/w/h, normalizados), no polígonos. thresholdMin 5 significa que una zona vacía por más de cinco minutos dispara presence.absent; afterHours true dispara presence.after_hours ante presencia fuera del horario. Los eventos van por los callbacks firmados de la app (más un callbackUrl crudo opcional), y el historial cae en apps/site/presence/presence.db.

3. Consumir los eventos

Ambas apps exponen su estado en vivo en la pestaña del dashboard (GET /apps/site/plugins/presence/data), y ambas hacen POST a tu webhook. Enrutá ppe.violation a un canal de supervisor, presence.absent a un jefe de turno, presence.after_hours a seguridad.

Qué deberías ver

Alguien que entra al muelle sin casco, en horario laboral, produce un ppe.violation con una captura tras unos cuadros sostenidos. Una recepción dejada vacía más de cinco minutos dispara presence.absent; la persona que vuelve dispara presence.returned; cualquiera en la recepción a las 3 de la mañana dispara presence.after_hours.

Resolución de problemas

  • Falsos positivos/negativos de EPP — esperado. El modelo es de entrenamiento comunitario (mAP50 ≈ 0.78), sesgado hacia imágenes de construcción al aire libre, y más débil en las clases de "sin equipo" y en cascos chicos y lejanos. Tratá los eventos como señales orientativas; no construyas un control de cumplimiento solo sobre ellos.
  • Picos de CPU con EPP — YOLOv8m cuesta ~1s de un núcleo por cuadro; mantené fps en 1 o menos en CPU, o sumá una GPU.
  • Presence nunca dispara ausente — el temporizador de vacío ancla en la primera muestra del worker, así que una zona ya vacía dispara thresholdMin después; confirmá que el rectángulo de la zona realmente cubra el puesto.

Cierre

Esto corre enteramente en tu hardware, y la app de EPP deliberadamente mantiene su evidencia local. Si necesitás un despliegue de seguridad robusto — modelos validados, flujos de aprobación, integración con un sistema de acceso al predio — es un servicio de consultoría donde fijamos las expectativas correctas y construimos hacia ellas, en vez de vender un modelo experimental como si estuviera certificado.