Ir al contenido

Monitoreo y filtrado de eventos de WebSocket

Suscríbete a eventos de WebSocket en tiempo real de Rhombus — filtra y procesa alertas de políticas, cambios de estado de dispositivos, detección de movimiento y eventos de control de acceso.

En esta página

El flujo de eventos de WebSocket de Rhombus entrega notificaciones en tiempo real sobre la actividad de tu organización que puede ver el rol de tu credencial. Esta guía cubre la estructura de los eventos, los tipos de entidad disponibles y los patrones para filtrar y procesar eventos.

Tópico de eventos

Todos los eventos de la organización se publican en un único tópico:

/topic/change/{orgUuid}

Los cambios en muchos tipos de objetos de tu organización emiten un evento en este tópico, desde nuevas alertas de políticas hasta el estado de las cámaras y los componentes de puertas; la referencia de eventos los enumera. Una conexión recibe los eventos que cubre el rol de su credencial, incluidas las alertas de políticas; los eventos de otros dispositivos y ubicaciones se descartan sin error (consulta Qué recibe una conexión).

Estructura de la carga útil del evento

Cada trama MESSAGE lleva un cuerpo JSON. Una nueva alerta de política se ve así (abreviada):

json
{
  "entity": "POLICY_ALERT",
  "type": "CREATE",
  "update": {
    "uuid": "Xq3vT1bKQ2m8c9Zr0aLwYg",
    "type": "POLICY_ALERT_V2",
    "deviceUuid": "ItkwWv1qT7Wy8-pY8KDesw",
    "locationUuid": "Rk2pQ7yLT0qX4b1nVt8sJw",
    "timestampMs": 1791367200000,
    "policyAlertTriggers": ["MOTION_HUMAN"],
    "textDescription": "Human detected at Front Lobby"
  }
}

Campos principales

CampoTipoDescripción
entitystringEl tipo de objeto que cambió
typestringCREATE, UPDATE, DELETE o REFRESH
entityUuidstringEl objeto que cambió. No aparece en una nueva alerta de política: usa update.uuid
updateobjectEl nuevo estado del objeto o los campos que cambiaron; falta en muchos mensajes. Su forma depende de entity
deviceUuidstringEl dispositivo involucrado, en los pocos mensajes que lo incluyen
subLocationsHierarchyKeystringLa ruta de sububicaciones, en algunos mensajes de monitoreo de alarmas

La organización no está en el cuerpo: está en el destino y en el encabezado ORG_UUID de la trama. La referencia de eventos documenta cada campo, incluida la alerta de política completa.

Tipos de cambio

TipoSignificadoEjemplo
CREATEAlgo nuevo, enviado con el objeto completoUna nueva alerta de política
UPDATEUn objeto existente cambióCambió el estado de una cámara
REFRESHEl objeto cambió; vuelve a leerlo si necesitas su estadoUn sensor de puerta informó un cambio
DELETEEl objeto se eliminó, sin updateUna alerta se eliminó o se archivó

Tipos de entidad

El campo entity indica qué tipo de objeto cambió. Los que más usan las integraciones:

EntidadSe envía cuando
POLICY_ALERTSe crea una alerta (CREATE, con la alerta), se vincula a un caso de amenaza (UPDATE) o se elimina (DELETE)
CAMERA_STATE, AUDIO_STATECambia el estado de una cámara o de un gateway de audio (UPDATE, con el nuevo estado)
DOOR_STATE, CLIMATE_STATE, OCCUPANCY_STATE, PROXIMITY_STATEUn sensor informa un cambio (REFRESH, con los campos que cambiaron)
CAMERA, DOOR_SENSOR, CLIMATE_SENSOR, PROXIMITY_SENSORSe agrega un dispositivo (REFRESH)
ACCESS_CONTROLLED_DOOR, COMPONENT_*_SHADOWCambia una puerta con control de acceso o uno de sus componentes
POLICY, SCHEDULESe modifica una política o un horario
SAVED_CLIPSCambia un clip guardado (REFRESH)

La referencia de eventos enumera todos los tipos de entidad. Todos llegan al mismo destino y no hay filtro del lado del servidor, así que filtra por entity en tu controlador.

Inspección de alertas de política

Una alerta nueva llega como CREATE con la alerta completa en update: su uuid, la cámara (deviceUuid), timestampMs, los policyAlertTriggers que se activaron y más. Se envía una sola vez, cuando la alerta se guarda por primera vez, así que los campos que Rhombus completa después (como las ubicaciones de clips y finalized) pueden tener todavía sus valores iniciales; obtén la alerta con la API REST cuando necesites su estado final.

python
def inspect_alert(payload):
    if payload.get("entity") != "POLICY_ALERT" or payload.get("type") != "CREATE":
        return
    alert = payload["update"]
    print(alert["uuid"], alert.get("deviceUuid"), alert["timestampMs"], alert.get("policyAlertTriggers"))

Filtrado de eventos

Por tipo de entidad

python
def handle_message(payload):
    entity = payload.get("entity")

    if entity == "POLICY_ALERT":
        handle_alert(payload)
    elif entity == "CAMERA_STATE":
        handle_camera_state(payload)
    else:
        pass  # ignora los tipos que no usas

Por tipo de cambio

python
def handle_alert(payload):
    change_type = payload.get("type")

    if change_type == "CREATE":
        send_notification(payload["update"])        # una alerta nueva
    elif change_type == "UPDATE":
        refresh_alert(payload["entityUuid"])        # vinculada a un caso de amenaza
    elif change_type == "DELETE":
        remove_alert(payload["entityUuid"])         # eliminada o archivada

No dependas de los mensajes DELETE para seguir cada alerta eliminada: están limitados a uno por organización cada 10 minutos.

Por dispositivo

Dónde está el dispositivo depende de la entidad: una alerta de política lo indica en update.deviceUuid, y un mensaje de estado de dispositivo trata del dispositivo de entityUuid.

python
WATCHED_DEVICES = {"ItkwWv1qT7Wy8-pY8KDesw"}

def device_of(payload):
    if payload.get("entity") == "POLICY_ALERT":
        return (payload.get("update") or {}).get("deviceUuid")
    return payload.get("deviceUuid") or payload.get("entityUuid")

def handle_message(payload):
    if device_of(payload) in WATCHED_DEVICES:
        process_event(payload)

Enriquecimiento de eventos con datos de la API REST

Los eventos de WebSocket contienen datos mínimos por eficiencia. Usa la API REST para obtener detalles adicionales cuando sea necesario:

Obtener el nombre de la cámara a partir del UUID del dispositivo

python
import requests

def get_camera_name(api_token, device_uuid):
    """Fetch camera name for display purposes."""
    response = requests.post(
        "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
        headers={
            "x-auth-scheme": "api-token",
            "x-auth-apikey": api_token,
            "Content-Type": "application/json"
        },
        json={}
    )
    cameras = response.json().get("cameraStates", [])
    for camera in cameras:
        if camera.get("uuid") == device_uuid:
            return camera.get("name", "Unknown Camera")
    return "Unknown Camera"

Obtener detalles de la alerta

python
def get_alert_details(api_token, alert_uuid):
    """Fetch full policy-alert details from the REST API."""
    response = requests.post(
        "https://api2.rhombussystems.com/api/event/getPolicyAlertDetails",
        headers={
            "x-auth-scheme": "api-token",
            "x-auth-apikey": api_token,
            "Content-Type": "application/json"
        },
        json={"policyAlertUuid": alert_uuid}
    )
    return response.json().get("policyAlert")

Formatos de salida

Visualización de alerta con formato

python
def display_alert(payload, camera_name=""):
    entity = payload.get("entity", "UNKNOWN")
    change = payload.get("type", "UNKNOWN")
    update = payload.get("update", {})

    print(f"{change} {entity}  camera={camera_name}")
    print(f"  device={payload.get('deviceUuid', 'N/A')}")
    print(f"  uuid={payload.get('entityUuid', 'N/A')}")
    # `update` is entity-specific; print its keys to discover available detail.
    if update:
        print(f"  update keys={list(update.keys())}")
    print()

Salida JSON sin procesar

Para canalizar a otras herramientas o sistemas de registro:

python
import json

def output_json(payload):
    print(json.dumps(payload, indent=2))

Patrones de integración

Relé de webhook

Reenvía los eventos de Rhombus a tu propio endpoint de webhook:

python
import requests

WEBHOOK_URL = "https://your-server.com/webhooks/rhombus"

def relay_to_webhook(payload):
    try:
        requests.post(WEBHOOK_URL, json=payload, timeout=5)
    except requests.RequestException as e:
        print(f"Webhook relay failed: {e}")

Notificaciones de Slack

Envía alertas de alta prioridad a un canal de Slack:

python
def send_slack_alert(payload, webhook_url):
    entity = payload.get("entity", "UNKNOWN")
    change = payload.get("type", "UNKNOWN")
    message = {
        "text": f":rotating_light: *Security Alert*\n"
                f"{change} {entity}\n"
                f"Entity: {payload.get('entityUuid', 'N/A')}  "
                f"Device: {payload.get('deviceUuid', 'N/A')}"
    }
    try:
        requests.post(webhook_url, json=message, timeout=5)
    except requests.RequestException as e:
        print(f"Slack notification failed: {e}")

Registro en base de datos

Persiste los eventos para análisis histórico:

python
import sqlite3
import json

def log_event(db_path, payload):
    conn = sqlite3.connect(db_path)
    conn.execute("""
        INSERT INTO events (entity, entity_uuid, change_type, device_uuid, payload)
        VALUES (?, ?, ?, ?, ?)
    """, (
        payload.get("entity"),
        payload.get("entityUuid"),
        payload.get("type"),
        payload.get("deviceUuid"),
        json.dumps(payload)
    ))
    conn.commit()
    conn.close()