Files
imperial-command-center/electron/preload.ts
root 3b38a78295 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)
2026-04-16 21:46:28 -05:00

91 lines
3.1 KiB
TypeScript

import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
export interface ElectronAPI {
screen: {
wake: () => Promise<boolean>;
sleep: () => Promise<boolean>;
setIdleTimeout: (timeout: number) => Promise<boolean>;
activity: () => Promise<boolean>;
};
presence: {
start: () => Promise<boolean>;
stop: () => Promise<boolean>;
onDetected: (callback: () => void) => () => void;
onCleared: (callback: () => void) => () => void;
};
frigate: {
startStream: (rtspUrl: string) => Promise<boolean>;
stopStream: () => Promise<boolean>;
onPersonDetected: (callback: (camera: string) => void) => () => void;
};
app: {
quit: () => void;
toggleFullscreen: () => void;
toggleDevTools: () => void;
};
config: {
getStoredToken: () => Promise<string | null>;
getJellyfinApiKey: () => Promise<string | null>;
};
photos: {
list: () => Promise<string[]>;
getDir: () => Promise<string>;
getUrl: (relative: string) => Promise<string | null>;
};
}
const electronAPI: ElectronAPI = {
screen: {
wake: () => ipcRenderer.invoke('screen:wake'),
sleep: () => ipcRenderer.invoke('screen:sleep'),
setIdleTimeout: (timeout: number) => ipcRenderer.invoke('screen:setIdleTimeout', timeout),
activity: () => ipcRenderer.invoke('screen:activity'),
},
presence: {
start: () => ipcRenderer.invoke('presence:start'),
stop: () => ipcRenderer.invoke('presence:stop'),
onDetected: (callback: () => void) => {
const handler = (_event: IpcRendererEvent) => callback();
ipcRenderer.on('presence:detected', handler);
return () => ipcRenderer.removeListener('presence:detected', handler);
},
onCleared: (callback: () => void) => {
const handler = (_event: IpcRendererEvent) => callback();
ipcRenderer.on('presence:cleared', handler);
return () => ipcRenderer.removeListener('presence:cleared', handler);
},
},
frigate: {
startStream: (rtspUrl: string) => ipcRenderer.invoke('frigate:startStream', rtspUrl),
stopStream: () => ipcRenderer.invoke('frigate:stopStream'),
onPersonDetected: (callback: (camera: string) => void) => {
const handler = (_event: IpcRendererEvent, camera: string) => callback(camera);
ipcRenderer.on('frigate:personDetected', handler);
return () => ipcRenderer.removeListener('frigate:personDetected', handler);
},
},
app: {
quit: () => ipcRenderer.invoke('app:quit'),
toggleFullscreen: () => ipcRenderer.invoke('app:toggleFullscreen'),
toggleDevTools: () => ipcRenderer.invoke('app:toggleDevTools'),
},
config: {
getStoredToken: () => ipcRenderer.invoke('config:getStoredToken'),
getJellyfinApiKey: () => ipcRenderer.invoke('config:getJellyfinApiKey'),
},
photos: {
list: () => ipcRenderer.invoke('photos:list'),
getDir: () => ipcRenderer.invoke('photos:getDir'),
getUrl: (relative: string) => ipcRenderer.invoke('photos:getUrl', relative),
},
};
contextBridge.exposeInMainWorld('electronAPI', electronAPI);
// Type declaration for renderer
declare global {
interface Window {
electronAPI: ElectronAPI;
}
}