Golden-rule-6 design-discussion issue (new background task per subscribed camera; discuss before code). Deferred/tracked.
Ingest cameras' onboard AI/analytics (Dahua SMD/IVS, Hikvision AcuSense, Uniview, the large Dahua-OEM ecosystem) as a first-class detection source, giving person/vehicle classification for zero server compute — the cheapest path to "object detection without Frigate + a GPU", a gap the project's own docs acknowledge ("fix is exclusion zones or object detection, not thresholds").
Approach: ONVIF PullPoint events, NOT the RTSP metadata track
Implement crumb_common::detection::DetectionSource (like Frigate/HA), one PullPoint subscription per opted-in camera → NormalizedEvents through the existing detection_ingester.rs → events table → timeline / notifications / clips / plate path, all for free.
Why not the vnd.onvif.metadata RTSP application track (observed on the Uniview LPR):
- go2rtc does not restream application tracks → would need a second, direct RTSP session per camera, bypassing the DB-managed go2rtc model (a seam AGENTS.md flags as having bitten before).
- The metadata XML stream is the most vendor-fragmented part of ONVIF; PullPoint event topics are cruder but far more uniform and are the proven route (Home Assistant, Scrypted ship on PullPoint).
- Events ("person on camera X at T") are what the timeline/notification pipeline consumes; bounding boxes are a later nicety (
NormalizedEvent.bounding_box is already Option; Frigate Phase 1 shipped without boxes).
Cheap because the plumbing exists: the api already depends on the pinned lumeohq/onvif-rs SOAP client and ptz::resolve_onvif_config (per-camera ONVIF endpoint + creds). PullPoint = enabling the event WSDL feature + one new module, not a new heavyweight dep.
Phases
- Phase 0: this discussion + a DECISIONS.md entry (PullPoint-not-metadata-track; RTSP-parser and vendor HTTP APIs rejected for v1).
- Phase 1 (detection-only, opt-in, default off):
services/api/src/detection/onvif_events.rs implementing DetectionSource; per-camera cameras.onvif_events_enabled column (register in MIGRATIONS); topic→DetectionLabel mapping (unknown → Other(topic)); active/inactive → new/end lifecycle debounce; wire beside the Frigate supervisor in main.rs; admin toggle + provider health on /status.
- Phase 2: grow the vendor topic map from real reports; Dahua ANPR events could feed
plate_string() → the existing plate pipeline (fail-closed engine-gate arm).
- Phase 3 (separate decision, recorder-correctness review): let camera events arm Motion-mode recording as an additive source (migration-0049 pattern). Do NOT bundle with Phase 1 — event latency gates footage capture.
Honest costs
- Permanent per-vendor topic-mapping maintenance tail (HA's ONVIF integration is the cautionary tale). Mitigation: mapping lives in data, unknown topics preserved as
Other, the contribute-a-camera flow doubles as the reporting channel.
- Lifecycle synthesis from boolean events (where the subtle bugs live).
- Test hardware: Dahua-family/Uniview/Reolink validatable in-house; Hikvision community-validated.
- Some cameras only expose AI over vendor HTTP APIs (Dahua
eventManager.cgi, Hik ISAPI), not ONVIF — Phase 1 ships ONVIF-first regardless; vendor HTTP listeners are possible later providers behind the same trait, never the first cut.
Open question to confirm before committing
Verify the pinned onvif-rs rev exposes the event schema feature.
Direction fit: camera → Crumb on the LAN, nothing leaves the box, opt-in per camera, off by default. This is the second of the two planned camera features (do the caveat-notices epic first).
Golden-rule-6 design-discussion issue (new background task per subscribed camera; discuss before code). Deferred/tracked.
Ingest cameras' onboard AI/analytics (Dahua SMD/IVS, Hikvision AcuSense, Uniview, the large Dahua-OEM ecosystem) as a first-class detection source, giving person/vehicle classification for zero server compute — the cheapest path to "object detection without Frigate + a GPU", a gap the project's own docs acknowledge ("fix is exclusion zones or object detection, not thresholds").
Approach: ONVIF PullPoint events, NOT the RTSP metadata track
Implement
crumb_common::detection::DetectionSource(like Frigate/HA), one PullPoint subscription per opted-in camera →NormalizedEvents through the existingdetection_ingester.rs→eventstable → timeline / notifications / clips / plate path, all for free.Why not the
vnd.onvif.metadataRTSP application track (observed on the Uniview LPR):NormalizedEvent.bounding_boxis alreadyOption; Frigate Phase 1 shipped without boxes).Cheap because the plumbing exists: the api already depends on the pinned
lumeohq/onvif-rsSOAP client andptz::resolve_onvif_config(per-camera ONVIF endpoint + creds). PullPoint = enabling theeventWSDL feature + one new module, not a new heavyweight dep.Phases
services/api/src/detection/onvif_events.rsimplementingDetectionSource; per-cameracameras.onvif_events_enabledcolumn (register inMIGRATIONS); topic→DetectionLabelmapping (unknown →Other(topic)); active/inactive →new/endlifecycle debounce; wire beside the Frigate supervisor inmain.rs; admin toggle + provider health on/status.plate_string()→ the existing plate pipeline (fail-closed engine-gate arm).Honest costs
Other, the contribute-a-camera flow doubles as the reporting channel.eventManager.cgi, Hik ISAPI), not ONVIF — Phase 1 ships ONVIF-first regardless; vendor HTTP listeners are possible later providers behind the same trait, never the first cut.Open question to confirm before committing
Verify the pinned onvif-rs rev exposes the
eventschema feature.Direction fit: camera → Crumb on the LAN, nothing leaves the box, opt-in per camera, off by default. This is the second of the two planned camera features (do the caveat-notices epic first).