feat(camera): Hikvision Alarm Server event-push ingress (discovery-first)
Newer Hik firmware can PUSH events to us: Event -> Smart/VCA with "Detection Target: Human/Vehicle" + Notify Surveillance Center + Alarm Settings -> Alarm Server makes the camera HTTP-POST an EventNotificationAlert on each detection. - New POST /api/devices/hikvision/:deviceId/event (routes/hikvision-alarm.ts): same machine-push pattern as the Dingtian Input Link — source-IP guarded + optional HTTP Digest, not behind the SPA cookie/CSRF. - Discovery-first / permissive: a wildcard content-type parser accepts ANY body as raw bytes (event XML, multipart+JPEG, or JSON — Hik varies by firmware), records it verbatim as a kind:"alarm" device_event, and best-effort extracts eventType/target/plate/dateTime/channelID for the summary + a loud log line. The point is to SEE exactly what a camera sends before wiring it further. - hikvision driver gains alarmPushEnabled + pushUser/pushPassword config and pushesToBackend:true (setup offers the backend push IP). - NOT yet a barrier trigger / DeviceReadEvent — records only. A plate read is advisory, never the sole reason a barrier opens; the read-bus/ANPR wiring is a deliberate next step once the real payload is known. Tests: hikvision-alarm.test.ts (6: vehicle XML summary, ANPR plate, raw JSON, wrong-IP 404, disabled 404, unknown-device 404). server 109/109; build+lint 14/14. Wiki: lpr-camera.md + log. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -95,13 +95,47 @@ const channelField: ConfigField = {
|
||||
|
||||
const cameraConfigFields = [hostField, portField(80), usernameField, passwordField, channelField];
|
||||
|
||||
// Hikvision "Alarm Server" PUSH config. The newer firmware (Event → Smart/VCA →
|
||||
// "Detection Target: Human/Vehicle", Notify Surveillance Center, Alarm Settings →
|
||||
// Alarm Server) HTTP-POSTs an EventNotificationAlert to a URL we host every time the
|
||||
// chosen target is detected — same shape as the Dingtian Input Link push. When enabled,
|
||||
// the admin points the camera's Alarm Server at /api/devices/hikvision/:deviceId/event
|
||||
// and we record what it sends. See routes/hikvision-alarm.ts, wiki/entities/lpr-camera.md.
|
||||
const alarmPushFields: ConfigField[] = [
|
||||
{
|
||||
key: "alarmPushEnabled",
|
||||
label: "Alarm Server push (Event → vehicle)",
|
||||
type: "boolean",
|
||||
required: false,
|
||||
default: false,
|
||||
help: "The camera POSTs each detected event to us (set its Alarm Settings → Alarm Server to this backend). No polling.",
|
||||
},
|
||||
{
|
||||
key: "pushUser",
|
||||
label: "Alarm push username (optional)",
|
||||
type: "string",
|
||||
required: false,
|
||||
help: "Only if the camera's Alarm Server is set to authenticate (HTTP Digest). Leave blank to accept by source-IP only.",
|
||||
},
|
||||
{
|
||||
key: "pushPassword",
|
||||
label: "Alarm push password (optional)",
|
||||
type: "secret",
|
||||
required: false,
|
||||
help: "Paired with the username above for Digest auth on the push. Leave blank for source-IP-only.",
|
||||
},
|
||||
];
|
||||
|
||||
export const hikvisionDriver: CameraDriver = {
|
||||
id: "hikvision",
|
||||
category: "camera",
|
||||
label: "Hikvision camera",
|
||||
description: "Hikvision snapshot via ISAPI (HTTP Digest).",
|
||||
description: "Hikvision snapshot via ISAPI (HTTP Digest) + optional Alarm Server event push.",
|
||||
transports: ["tcp-ip"],
|
||||
configFields: cameraConfigFields,
|
||||
// The camera PULLS snapshots, but with Alarm Server on it ALSO pushes events to us —
|
||||
// so it may need the backend push IP at assign time (like the Dingtian).
|
||||
pushesToBackend: true,
|
||||
configFields: [...cameraConfigFields, ...alarmPushFields],
|
||||
// ISAPI channel id: <channel><stream>, e.g. ch1 main = 101, ch2 main = 201.
|
||||
create: (c) =>
|
||||
new HttpCamera("hikvision", c, (ch) => `/ISAPI/Streaming/channels/${ch}01/picture`),
|
||||
|
||||
Reference in New Issue
Block a user