Person detection via direct MQTT instead of HA entities
- Electron main process subscribes to Frigate's MQTT topics (frigate/<camera>/person and frigate/events) directly via mqtt.js, bypassing the broken HA MQTT integration - Watched cameras: Front_Porch, FPE, Porch_Downstairs, Driveway_door - On person detection, exits photo-frame idle and shows full-screen camera feed for 30 seconds - Removed HA entity-based person detection code (entityToCameraName, personDetectionEntities config dependency) - Deleted unused useFrigateDetection HTTP polling hook (superseded)
This commit is contained in:
60
src/hooks/useFrigateDetection.ts
Normal file
60
src/hooks/useFrigateDetection.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { useEffect, useRef, useCallback } from 'react';
|
||||
import { env } from '@/config/environment';
|
||||
|
||||
interface FrigateEvent {
|
||||
id: string;
|
||||
camera: string;
|
||||
label: string;
|
||||
start_time: number;
|
||||
end_time: number | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls Frigate's /api/events for active (end_time=null) person events
|
||||
* on the specified cameras. Fires onPersonDetected with the camera name
|
||||
* when a NEW event appears. Bypasses MQTT/HA entirely.
|
||||
*/
|
||||
export function useFrigateDetection({
|
||||
cameras,
|
||||
onPersonDetected,
|
||||
pollIntervalMs = 5000,
|
||||
}: {
|
||||
cameras: string[];
|
||||
onPersonDetected: (camera: string) => void;
|
||||
pollIntervalMs?: number;
|
||||
}) {
|
||||
const seenRef = useRef<Set<string>>(new Set());
|
||||
const onDetectRef = useRef(onPersonDetected);
|
||||
onDetectRef.current = onPersonDetected;
|
||||
|
||||
const poll = useCallback(async () => {
|
||||
if (!cameras.length) return;
|
||||
try {
|
||||
const url = `${env.frigateUrl}/api/events?labels=person&limit=5&has_clip=0&in_progress=1`;
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) return;
|
||||
const events: FrigateEvent[] = await resp.json();
|
||||
for (const ev of events) {
|
||||
if (ev.end_time !== null) continue; // already ended
|
||||
if (!cameras.some((c) => c.toLowerCase() === ev.camera.toLowerCase())) continue;
|
||||
if (seenRef.current.has(ev.id)) continue;
|
||||
seenRef.current.add(ev.id);
|
||||
onDetectRef.current(ev.camera);
|
||||
break; // one at a time
|
||||
}
|
||||
// Prune old seen IDs (keep last 50)
|
||||
if (seenRef.current.size > 50) {
|
||||
const arr = [...seenRef.current];
|
||||
seenRef.current = new Set(arr.slice(arr.length - 25));
|
||||
}
|
||||
} catch {
|
||||
// Frigate unreachable — skip silently
|
||||
}
|
||||
}, [cameras]);
|
||||
|
||||
useEffect(() => {
|
||||
poll();
|
||||
const id = setInterval(poll, pollIntervalMs);
|
||||
return () => clearInterval(id);
|
||||
}, [poll, pollIntervalMs]);
|
||||
}
|
||||
Reference in New Issue
Block a user