feat: Trigger cameras on HA bus events (#2512)
This commit is contained in:
committed by
dermotduffy
parent
406176eebc
commit
0a36358394
@@ -877,6 +877,29 @@ const frigateCardToAdvancedCameraCardStyleTransform = (data: unknown): unknown =
|
||||
return newStyleOverrides;
|
||||
};
|
||||
|
||||
// Legacy `triggers.events: string[]` (Frigate engine media-availability filter)
|
||||
// was renamed to `triggers.media_events` to free up `triggers.events` for the
|
||||
// new HA-bus-event trigger list (object shape). Distinguish old from new by
|
||||
// element type: an all-string array is legacy; any non-string element marks
|
||||
// the new shape and must not be touched. If `media_events` already exists we
|
||||
// refuse to overwrite it -- but we still drop the legacy `events` (otherwise
|
||||
// it would fail the new schema, which expects objects).
|
||||
const triggersEventsToMediaEventsTransform = (triggers: unknown): unknown => {
|
||||
if (typeof triggers !== 'object' || !triggers) {
|
||||
return undefined;
|
||||
}
|
||||
const events = triggers['events'];
|
||||
if (!Array.isArray(events) || events.some((x) => typeof x !== 'string')) {
|
||||
return undefined;
|
||||
}
|
||||
const result = { ...triggers };
|
||||
delete result['events'];
|
||||
if (!('media_events' in result)) {
|
||||
result['media_events'] = events;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const UPGRADES = [
|
||||
// v5.2.0 -> v6.0.0
|
||||
(data: unknown): boolean => {
|
||||
@@ -1090,4 +1113,13 @@ const UPGRADES = [
|
||||
typeof data === 'object' && data ? (data as RawAdvancedCameraCardConfig) : {},
|
||||
);
|
||||
},
|
||||
|
||||
// Legacy `triggers.events: string[]` → `triggers.media_events`. Targets the
|
||||
// two known places a camera config lives: `cameras_global` and `cameras[]`.
|
||||
// Mirrors the PTZ rename migration above.
|
||||
upgradeWithOverrides('cameras_global.triggers', triggersEventsToMediaEventsTransform),
|
||||
upgradeArrayOfObjects(
|
||||
CONF_CAMERAS,
|
||||
upgradeWithOverrides('triggers', triggersEventsToMediaEventsTransform),
|
||||
),
|
||||
];
|
||||
|
||||
@@ -8,7 +8,7 @@ import { imageBaseConfigDefault, imageBaseConfigSchema } from './common/image';
|
||||
import { proxyBaseConfigDefault, proxyBaseConfigSchema } from './common/proxy';
|
||||
import { severitySchema } from './common/severity';
|
||||
|
||||
const CAMERA_TRIGGER_EVENT_TYPES = [
|
||||
const CAMERA_TRIGGER_MEDIA_EVENT_TYPES = [
|
||||
// An event whether or not it has any media yet associated with it.
|
||||
'events',
|
||||
|
||||
@@ -16,7 +16,8 @@ const CAMERA_TRIGGER_EVENT_TYPES = [
|
||||
'clips',
|
||||
'snapshots',
|
||||
] as const;
|
||||
export type CameraTriggerEventType = (typeof CAMERA_TRIGGER_EVENT_TYPES)[number];
|
||||
export type CameraTriggerMediaEventType =
|
||||
(typeof CAMERA_TRIGGER_MEDIA_EVENT_TYPES)[number];
|
||||
|
||||
// *************************************************************************
|
||||
// Live Provider Configuration
|
||||
@@ -149,8 +150,9 @@ export const cameraConfigDefault = {
|
||||
motion: false,
|
||||
occupancy: false,
|
||||
doorbell: false,
|
||||
events: [],
|
||||
media_events: [],
|
||||
entities: [],
|
||||
events: [],
|
||||
reviews: {
|
||||
severities: ['high' as const],
|
||||
description: true,
|
||||
@@ -217,6 +219,12 @@ const cameraMediaConfigSchema = z.object({
|
||||
.default(cameraMediaConfigDefault.reviewed),
|
||||
});
|
||||
|
||||
const triggerEventSchema = z.object({
|
||||
event_type: z.string().min(1),
|
||||
event_data: z.record(z.string(), z.unknown()).optional(),
|
||||
});
|
||||
export type TriggerEvent = z.infer<typeof triggerEventSchema>;
|
||||
|
||||
export const cameraConfigSchema = z
|
||||
.looseObject({
|
||||
camera_entity: z.string().optional(),
|
||||
@@ -251,10 +259,11 @@ export const cameraConfigSchema = z
|
||||
occupancy: z.boolean().default(cameraConfigDefault.triggers.occupancy),
|
||||
doorbell: z.boolean().default(cameraConfigDefault.triggers.doorbell),
|
||||
entities: z.string().array().default(cameraConfigDefault.triggers.entities),
|
||||
events: z
|
||||
.enum(CAMERA_TRIGGER_EVENT_TYPES)
|
||||
events: triggerEventSchema.array().default(cameraConfigDefault.triggers.events),
|
||||
media_events: z
|
||||
.enum(CAMERA_TRIGGER_MEDIA_EVENT_TYPES)
|
||||
.array()
|
||||
.default(cameraConfigDefault.triggers.events),
|
||||
.default(cameraConfigDefault.triggers.media_events),
|
||||
reviews: z
|
||||
.object({
|
||||
severities: severitySchema
|
||||
|
||||
@@ -72,7 +72,7 @@ export const viewConfigDefault = {
|
||||
},
|
||||
untrigger_delay_seconds: 0,
|
||||
untrigger_force_seconds: 0,
|
||||
signal_hold_seconds: 30,
|
||||
event_hold_seconds: 30,
|
||||
},
|
||||
keyboard_shortcuts: keyboardShortcutsDefault,
|
||||
issues: {
|
||||
@@ -110,9 +110,7 @@ export const triggersSchema = z.object({
|
||||
untrigger_force_seconds: z
|
||||
.number()
|
||||
.default(viewConfigDefault.triggers.untrigger_force_seconds),
|
||||
signal_hold_seconds: z
|
||||
.number()
|
||||
.default(viewConfigDefault.triggers.signal_hold_seconds),
|
||||
event_hold_seconds: z.number().default(viewConfigDefault.triggers.event_hold_seconds),
|
||||
});
|
||||
export type TriggersOptions = z.infer<typeof triggersSchema>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user