Integración Hanwha → Milestone XProtect¶
Discriminación de zonas de analíticas Hanwha en Milestone XProtect.
El problema¶
Las cámaras Hanwha reportan a Milestone un evento plano:
"hubo intrusión en NAT1-T17"
No dicen en qué zona. Y sin zona no se pueden armar reglas ni alarmas distintas para el portón, la playa de carga o el perímetro: todo dispara lo mismo.
No es un descuido del fabricante. Es estructural: los 203 tipos de evento de
driver de Milestone declaran <Parameters/> vacío. La zona no tiene dónde
viajar. El driver de la cámara tiene exactamente tres eventos cableados —
IntrusionStart, Tripwire y Tampering — y ninguno lleva índice.
Por qué el driver no trae zona →
La solución¶
La cámara sí expone la zona por SUNAPI. Alcanza con agregar un parámetro al endpoint que ya se usaba:
Channel.0.VideoAnalytics.Intrusion.DefinedAreaID.1=False
Channel.0.VideoAnalytics.Intrusion.DefinedAreaID.2=True ← zona 2
Channel.0.VideoAnalytics.Passing.LineID.1=False ← línea 1
Un servicio de Windows lee ese stream de todas las cámaras Hanwha del sistema y inyecta los eventos en Milestone como Analytics Events con el índice de zona en el nombre del tipo, de modo que la zona quede disponible al definir reglas y alarmas.

Cómo funciona¶
CÁMARA HANWHA HANWHA ZONE BRIDGE MILESTONE XPROTECT
───────────── ────────────────── ──────────────────
DefinedArea 1 ──────────► slot 1 ──────────────────► Hanwha Intrusion_1
DefinedArea 2 ──────────► slot 2 ──────────────────► Hanwha Intrusion_2
DefinedArea 9 ──► (Mode vacío: ignorada)
Line 1 ──────────► slot 1 ──────────────────► Hanwha Line Crossing_1
SUNAPI mapeo persistido Analytics Events
eventstatus.cgi mapeo-slots.json TCP 9090
Y en Milestone la alarma queda así:
| Campo | Valor |
|---|---|
| Tipo de evento | Hanwha Intrusion_2 |
| Fuente | NAT1-T17 |
| Nombre | Intrusión — Portón Norte |
Empezar¶
-
Desde cero sobre un servidor Milestone limpio. Requisitos, armado del paquete, verificación y problemas frecuentes.
-
El panel, nombrar zonas, armar alarmas por zona, API y diagnóstico.
-
Decisiones de diseño, nomenclatura de eventos, el mapeo pegajoso y riesgos.
-
Todo lo que se descubrió sondeando el sistema real, con evidencia.
Lo que costó averiguar¶
Cuatro cosas que no están en ninguna documentación y que hacen fallar en silencio. Están detalladas en la sección de investigación, pero vale tenerlas a mano:
El curl de Windows Server 2022 no puede autenticar contra estas cámaras
El curl 7.79.1 que trae el sistema no completa el handshake Digest contra el
lighttpd de las Hanwha: recibe el 401, reutiliza la conexión y nunca manda
la segunda request. Termina con exit=67 y salida vacía, que parece un
problema de credenciales y no lo es. Hay que usar HttpClient con
CredentialCache.
monitordiff no es un long-poll, es un stream que no termina
Es multipart/x-mixed-replace con boundary SamsungTechwin. Hay que leerlo
con ResponseHeadersRead e ir procesando línea a línea. Con
ReadAsStringAsync el cliente espera un cuerpo que nunca cierra y muere por
timeout.
El nombre del tipo va en <Message>, no en <Type>
Y el XML necesita xmlns="urn:milestone-systems", porque el Event Server
busca con XPath /ns:AnalyticsEvent/ns:EventHeader/ns:Message. Sin el
namespace no matchea nada.
El Event Server responde 200 OK aunque descarte el evento
El rechazo viene en el cuerpo de la respuesta
(Warning: Event message not known, Warning: Device not known). Si se
manda y se cierra el socket sin leer, todo parece funcionar y no llega nada.
Protocolo completo de Analytics Events →
Estado¶
| Componente | Estado |
|---|---|
| Lectura de zonas por SUNAPI | ✅ verificado con eventos reales |
| Inyección en Analytics Events | ✅ verificado, 1408 alarmas generadas |
| Discriminación por zona en alarmas | ✅ verificado con prueba de control |
| Credenciales desde Milestone | ✅ verificado, sin doble carga |
| Servicio de Windows | ✅ instalación limpia verificada |
| Panel web | ✅ funcionando |
| Prueba de carga con 100+ cámaras | ❌ pendiente (el lab tiene una) |
Validado sobre XProtect VMS 2026 R1 con una Hanwha TNO-4050T (firmware 2.11.13, CGI 2.6.0).