Move some Frigate specific interfaces under the Frigate engine.
This commit is contained in:
@@ -4,7 +4,7 @@ import endOfHour from 'date-fns/endOfHour';
|
|||||||
import getUnixTime from 'date-fns/getUnixTime';
|
import getUnixTime from 'date-fns/getUnixTime';
|
||||||
import startOfHour from 'date-fns/startOfHour';
|
import startOfHour from 'date-fns/startOfHour';
|
||||||
import { CAMERA_BIRDSEYE } from '../../const';
|
import { CAMERA_BIRDSEYE } from '../../const';
|
||||||
import { CameraConfig, FrigateRecording, RecordingSegment } from '../../types';
|
import { CameraConfig, RecordingSegment } from '../../types';
|
||||||
import { MediaQueries, MediaQueriesResults } from '../../view';
|
import { MediaQueries, MediaQueriesResults } from '../../view';
|
||||||
import { ViewMedia, ViewMediaClassifier, ViewMediaFactory } from '../../view-media';
|
import { ViewMedia, ViewMediaClassifier, ViewMediaFactory } from '../../view-media';
|
||||||
import { errorToConsole } from '../../utils/basic';
|
import { errorToConsole } from '../../utils/basic';
|
||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
RecordingQuery,
|
RecordingQuery,
|
||||||
RecordingSegmentsQuery,
|
RecordingSegmentsQuery,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { RecordingSummary } from './schema';
|
import { FrigateRecording, RecordingSummary } from './types';
|
||||||
import { getEvents, getRecordingSegments, getRecordingsSummary, NativeFrigateEventQuery, NativeFrigateRecordingSegmentsQuery, retainEvent } from './requests';
|
import { getEvents, getRecordingSegments, getRecordingsSummary, NativeFrigateEventQuery, NativeFrigateRecordingSegmentsQuery, retainEvent } from './requests';
|
||||||
|
|
||||||
const EVENT_REQUEST_CACHE_MAX_AGE_SECONDS = 60;
|
const EVENT_REQUEST_CACHE_MAX_AGE_SECONDS = 60;
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ import { HomeAssistant } from 'custom-card-helpers';
|
|||||||
import { localize } from '../../localize/localize';
|
import { localize } from '../../localize/localize';
|
||||||
import {
|
import {
|
||||||
FrigateCardError,
|
FrigateCardError,
|
||||||
FrigateEvents,
|
|
||||||
frigateEventsSchema,
|
|
||||||
RecordingSegment,
|
RecordingSegment,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { homeAssistantWSRequest } from '../../utils/ha';
|
import { homeAssistantWSRequest } from '../../utils/ha';
|
||||||
import { recordingSegmentsSchema, RecordingSummary, recordingSummarySchema, RetainResult, retainResultSchema } from './schema';
|
import { FrigateEvent, frigateEventsSchema, recordingSegmentsSchema, RecordingSummary, recordingSummarySchema, RetainResult, retainResultSchema } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the recordings summary. May throw.
|
* Get the recordings summary. May throw.
|
||||||
@@ -115,7 +113,7 @@ export interface NativeFrigateEventQuery {
|
|||||||
export const getEvents = async (
|
export const getEvents = async (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
params?: NativeFrigateEventQuery,
|
params?: NativeFrigateEventQuery,
|
||||||
): Promise<FrigateEvents> => {
|
): Promise<FrigateEvent[]> => {
|
||||||
return await homeAssistantWSRequest(
|
return await homeAssistantWSRequest(
|
||||||
hass,
|
hass,
|
||||||
frigateEventsSchema,
|
frigateEventsSchema,
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const eventSchema = z.object({
|
||||||
|
camera: z.string(),
|
||||||
|
end_time: z.number().nullable(),
|
||||||
|
false_positive: z.boolean().nullable(),
|
||||||
|
has_clip: z.boolean(),
|
||||||
|
has_snapshot: z.boolean(),
|
||||||
|
id: z.string(),
|
||||||
|
label: z.string(),
|
||||||
|
start_time: z.number(),
|
||||||
|
top_score: z.number(),
|
||||||
|
zones: z.string().array(),
|
||||||
|
retain_indefinitely: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
export const frigateEventsSchema = eventSchema.array();
|
||||||
|
|
||||||
|
export type FrigateEvent = z.infer<typeof eventSchema>;
|
||||||
|
|
||||||
const recordingSummaryHourSchema = z.object({
|
const recordingSummaryHourSchema = z.object({
|
||||||
hour: z.preprocess((arg) => Number(arg), z.number().min(0).max(23)),
|
hour: z.preprocess((arg) => Number(arg), z.number().min(0).max(23)),
|
||||||
duration: z.number().min(0),
|
duration: z.number().min(0),
|
||||||
@@ -31,3 +48,11 @@ export const retainResultSchema = z.object({
|
|||||||
message: z.string(),
|
message: z.string(),
|
||||||
});
|
});
|
||||||
export type RetainResult = z.infer<typeof retainResultSchema>;
|
export type RetainResult = z.infer<typeof retainResultSchema>;
|
||||||
|
|
||||||
|
export interface FrigateRecording {
|
||||||
|
// Frigate camera name (may not be unique)
|
||||||
|
camera: string;
|
||||||
|
start_time: number;
|
||||||
|
end_time: number;
|
||||||
|
events: number;
|
||||||
|
}
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
import utcToZonedTime from 'date-fns-tz/utcToZonedTime';
|
import utcToZonedTime from 'date-fns-tz/utcToZonedTime';
|
||||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||||
import {
|
import { ClipsOrSnapshots } from '../../types';
|
||||||
ClipsOrSnapshots,
|
|
||||||
FrigateEvent,
|
|
||||||
FrigateRecording,
|
|
||||||
} from '../../types';
|
|
||||||
import { formatDateAndTime, prettifyTitle } from '../../utils/basic';
|
import { formatDateAndTime, prettifyTitle } from '../../utils/basic';
|
||||||
|
import { FrigateEvent, FrigateRecording } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an event generate a title.
|
* Given an event generate a title.
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,5 @@
|
|||||||
import { FrigateEvents, FrigateRecording, RecordingSegment } from '../types';
|
import { RecordingSegment } from '../types';
|
||||||
|
import { FrigateEvent, FrigateRecording } from './frigate/types';
|
||||||
|
|
||||||
// ====
|
// ====
|
||||||
// Base
|
// Base
|
||||||
@@ -119,7 +120,7 @@ export interface RecordingSegmentsQueryResults extends QueryResults {
|
|||||||
|
|
||||||
export interface FrigateEventQueryResults extends EventQueryResults {
|
export interface FrigateEventQueryResults extends EventQueryResults {
|
||||||
engine: Engine.Frigate;
|
engine: Engine.Frigate;
|
||||||
events: FrigateEvents;
|
events: FrigateEvent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FrigateRecordingQueryResults extends RecordingQueryResults {
|
export interface FrigateRecordingQueryResults extends RecordingQueryResults {
|
||||||
|
|||||||
+2
-26
@@ -13,6 +13,7 @@ import {
|
|||||||
} from 'custom-card-helpers';
|
} from 'custom-card-helpers';
|
||||||
import { StyleInfo } from 'lit/directives/style-map.js';
|
import { StyleInfo } from 'lit/directives/style-map.js';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { eventSchema, FrigateEvent, FrigateRecording } from './camera/frigate/types.js';
|
||||||
import { deepRemoveDefaults } from './utils/zod.js';
|
import { deepRemoveDefaults } from './utils/zod.js';
|
||||||
|
|
||||||
// The min allowed size of buttons.
|
// The min allowed size of buttons.
|
||||||
@@ -1415,14 +1416,6 @@ export interface BrowseMediaSource {
|
|||||||
children?: BrowseMediaSource[] | null;
|
children?: BrowseMediaSource[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FrigateRecording {
|
|
||||||
// Frigate camera name (may not be unique)
|
|
||||||
camera: string;
|
|
||||||
start_time: number;
|
|
||||||
end_time: number;
|
|
||||||
events: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FrigateBrowseMediaSource extends BrowseMediaSource {
|
export interface FrigateBrowseMediaSource extends BrowseMediaSource {
|
||||||
children?: FrigateBrowseMediaSource[] | null;
|
children?: FrigateBrowseMediaSource[] | null;
|
||||||
frigate?: {
|
frigate?: {
|
||||||
@@ -1432,23 +1425,6 @@ export interface FrigateBrowseMediaSource extends BrowseMediaSource {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const frigateEventSchema = z.object({
|
|
||||||
camera: z.string(),
|
|
||||||
end_time: z.number().nullable(),
|
|
||||||
false_positive: z.boolean().nullable(),
|
|
||||||
has_clip: z.boolean(),
|
|
||||||
has_snapshot: z.boolean(),
|
|
||||||
id: z.string(),
|
|
||||||
label: z.string(),
|
|
||||||
start_time: z.number(),
|
|
||||||
top_score: z.number(),
|
|
||||||
zones: z.string().array(),
|
|
||||||
retain_indefinitely: z.boolean().optional(),
|
|
||||||
});
|
|
||||||
export type FrigateEvent = z.infer<typeof frigateEventSchema>;
|
|
||||||
|
|
||||||
export const frigateEventsSchema = frigateEventSchema.array();
|
|
||||||
export type FrigateEvents = z.infer<typeof frigateEventsSchema>;
|
|
||||||
|
|
||||||
export const frigateBrowseMediaSourceSchema: z.ZodSchema<BrowseMediaSource> = z.lazy(
|
export const frigateBrowseMediaSourceSchema: z.ZodSchema<BrowseMediaSource> = z.lazy(
|
||||||
() =>
|
() =>
|
||||||
@@ -1464,7 +1440,7 @@ export const frigateBrowseMediaSourceSchema: z.ZodSchema<BrowseMediaSource> = z.
|
|||||||
children: z.array(frigateBrowseMediaSourceSchema).nullable().optional(),
|
children: z.array(frigateBrowseMediaSourceSchema).nullable().optional(),
|
||||||
frigate: z
|
frigate: z
|
||||||
.object({
|
.object({
|
||||||
event: frigateEventSchema,
|
event: eventSchema,
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { HomeAssistant } from 'custom-card-helpers';
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { homeAssistantWSRequest } from '.';
|
import { homeAssistantWSRequest } from '.';
|
||||||
|
import { FrigateEvent, FrigateRecording } from '../../camera/frigate/types';
|
||||||
import { dispatchErrorMessageEvent } from '../../components/message.js';
|
import { dispatchErrorMessageEvent } from '../../components/message.js';
|
||||||
import { localize } from '../../localize/localize.js';
|
import { localize } from '../../localize/localize.js';
|
||||||
import {
|
import {
|
||||||
@@ -9,8 +10,6 @@ import {
|
|||||||
ClipsOrSnapshots,
|
ClipsOrSnapshots,
|
||||||
FrigateBrowseMediaSource,
|
FrigateBrowseMediaSource,
|
||||||
frigateBrowseMediaSourceSchema,
|
frigateBrowseMediaSourceSchema,
|
||||||
FrigateEvent,
|
|
||||||
FrigateRecording,
|
|
||||||
MEDIA_CLASS_PLAYLIST,
|
MEDIA_CLASS_PLAYLIST,
|
||||||
MEDIA_CLASS_VIDEO,
|
MEDIA_CLASS_VIDEO,
|
||||||
MEDIA_TYPE_PLAYLIST,
|
MEDIA_TYPE_PLAYLIST,
|
||||||
|
|||||||
+1
-2
@@ -3,8 +3,6 @@ import isEqual from 'lodash-es/isEqual';
|
|||||||
import {
|
import {
|
||||||
BrowseMediaSource,
|
BrowseMediaSource,
|
||||||
CameraConfig,
|
CameraConfig,
|
||||||
FrigateEvent,
|
|
||||||
FrigateRecording,
|
|
||||||
MEDIA_TYPE_IMAGE,
|
MEDIA_TYPE_IMAGE,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
import { ModifyInterface } from './utils/basic.js';
|
import { ModifyInterface } from './utils/basic.js';
|
||||||
@@ -15,6 +13,7 @@ import {
|
|||||||
getRecordingMediaContentID,
|
getRecordingMediaContentID,
|
||||||
getRecordingTitle,
|
getRecordingTitle,
|
||||||
} from './camera/frigate/util.js';
|
} from './camera/frigate/util.js';
|
||||||
|
import { FrigateEvent, FrigateRecording } from './camera/frigate/types.js';
|
||||||
|
|
||||||
export type ViewMediaType = 'clip' | 'snapshot' | 'recording';
|
export type ViewMediaType = 'clip' | 'snapshot' | 'recording';
|
||||||
export type ViewMediaSourceType = FrigateEvent | FrigateRecording | BrowseMediaSource;
|
export type ViewMediaSourceType = FrigateEvent | FrigateRecording | BrowseMediaSource;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
// Hard:
|
// Hard:
|
||||||
// - TODO: Implement dragging the timeline seeking forward in both Frigate recordings & events.
|
// - TODO: Implement dragging the timeline seeking forward in both Frigate recordings & events.
|
||||||
// - TODO: Implement gallery.
|
// - TODO: Implement gallery.
|
||||||
|
// - TODO: Remove FrigateBrowseMediaSource if not necessary (post-gallery).
|
||||||
// - TODO: In generateMediaViewerContext there is an assumption that recordings start/end on the hour, which is true for Frigate but that assumption should be in the engine.
|
// - TODO: In generateMediaViewerContext there is an assumption that recordings start/end on the hour, which is true for Frigate but that assumption should be in the engine.
|
||||||
// - TODO: What should the timeline do when an event is clicked on that is not in the queryResults (or if queryResults is empty)?
|
// - TODO: What should the timeline do when an event is clicked on that is not in the queryResults (or if queryResults is empty)?
|
||||||
// - TODO: Should the timeline data source clear events (as it currently does) when the query changes?
|
// - TODO: Should the timeline data source clear events (as it currently does) when the query changes?
|
||||||
|
|||||||
Reference in New Issue
Block a user