Initial low performance profile mode.

This commit is contained in:
Dermot Duffy
2022-10-04 20:00:53 -07:00
parent 5f30fc67ff
commit c8c9098501
14 changed files with 203 additions and 23 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ import type {
RawFrigateCardConfig,
} from './types';
import { HassEntities } from 'home-assistant-js-websocket';
import { cloneDeep, merge } from 'lodash-es';
import { merge } from 'lodash-es';
export interface ConditionState {
view?: string;
@@ -109,7 +109,7 @@ export function getOverriddenConfig(
overrides: Readonly<RawOverrides> | undefined,
conditionState?: Readonly<ConditionState>,
): RawFrigateCardConfig {
const output = cloneDeep(config);
const output = structuredClone(config);
let overridden = false;
if (overrides) {
for (const override of overrides) {
+6 -2
View File
@@ -101,6 +101,7 @@ import { View } from './view.js';
import pkg from '../package.json';
import { ViewContext } from 'view';
import { DataManager } from './utils/data-manager.js';
import { setLowPerformanceProfile } from './performance.js';
/** A note on media callbacks:
*
@@ -933,7 +934,10 @@ export class FrigateCard extends LitElement {
: localize('error.invalid_configuration_no_hint')),
);
}
const config = parseResult.data;
const config =
parseResult.data.performance.profile !== 'low'
? parseResult.data
: setLowPerformanceProfile(inputConfig, parseResult.data);
if (config.test_gui) {
getLovelace().setEditMode(true);
@@ -1052,7 +1056,7 @@ export class FrigateCard extends LitElement {
}
if (this._cameras && (changedProps.has('_config') || changedProps.has('_cameras'))) {
this._dataManager = new DataManager(this._cameras, this._config.timeline.media);
this._dataManager = new DataManager(this._cameras);
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ import {
getFullDependentBrowseMediaQueryParametersOrDispatchError,
} from '../utils/ha/browse-media';
import { changeViewToRecentRecordingForCameraAndDependents } from '../utils/media-to-view.js';
import { DataManager } from '../utils/data-manager';
import { DataManager } from '../utils/data-manager.js';
import { View } from '../view.js';
import { renderProgressIndicator } from './message.js';
import './thumbnail.js';
+4 -4
View File
@@ -52,9 +52,9 @@ export class FrigateCardNextPreviousControl extends LitElement {
const classes = {
controls: true,
previous: this.direction == 'previous',
next: this.direction == 'next',
thumbnails: this._controlConfig.style == 'thumbnails',
previous: this.direction === 'previous',
next: this.direction === 'next',
thumbnails: this._controlConfig.style === 'thumbnails',
icons: ['chevrons', 'icons'].includes(this._controlConfig.style),
button: ['chevrons', 'icons'].includes(this._controlConfig.style),
};
@@ -62,7 +62,7 @@ export class FrigateCardNextPreviousControl extends LitElement {
if (['chevrons', 'icons'].includes(this._controlConfig.style)) {
let icon: string;
if (this._controlConfig.style === 'chevrons') {
icon = this.direction == 'previous' ? 'mdi:chevron-left' : 'mdi:chevron-right';
icon = this.direction === 'previous' ? 'mdi:chevron-left' : 'mdi:chevron-right';
} else {
if (!this.icon) {
return html``;
+1 -1
View File
@@ -200,7 +200,7 @@ export class FrigateCardSurround extends LitElement {
>
</frigate-card-thumbnail-carousel>`
: ''}
${this.timelineConfig && !this.inBackground
${this.timelineConfig?.mode && this.timelineConfig.mode !== 'none' && !this.inBackground
? html` <frigate-card-timeline-core
slot=${this.timelineConfig.mode}
.hass=${this.hass}
+3 -3
View File
@@ -1,4 +1,4 @@
import { cloneDeep, get, isEqual, set } from 'lodash-es';
import { get, isEqual, set } from 'lodash-es';
import {
CONF_CAMERAS,
CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
@@ -104,7 +104,7 @@ export const upgradeConfig = function (obj: RawFrigateCardConfig): boolean {
* @returns `true` if the configuration is upgradeable.
*/
export const isConfigUpgradeable = function (obj: RawFrigateCardConfig): boolean {
const newObj = JSON.parse(JSON.stringify(obj));
const newObj = structuredClone(obj);
return upgradeConfig(newObj);
};
@@ -136,7 +136,7 @@ export const trimConfig = function (obj: RawFrigateCardConfig): boolean {
* @returns A new deeply-copied configuration.
*/
export const copyConfig = function (obj: RawFrigateCardConfig): RawFrigateCardConfig {
return cloneDeep(obj);
return structuredClone(obj);
};
/**
+2
View File
@@ -192,7 +192,9 @@ export const CONF_MENU_BUTTONS_FRIGATE_UI = `${CONF_MENU}.buttons.frigate_ui` as
export const CONF_MENU_BUTTONS_FULLSCREEN = `${CONF_MENU}.buttons.fullscreen` as const;
export const CONF_MENU_BUTTONS_IMAGE = `${CONF_MENU}.buttons.image` as const;
export const CONF_MENU_BUTTONS_LIVE = `${CONF_MENU}.buttons.live` as const;
export const CONF_MENU_BUTTONS_MEDIA_PLAYER = `${CONF_MENU}.buttons.media_player` as const;
export const CONF_MENU_BUTTONS_SNAPSHOTS = `${CONF_MENU}.buttons.snapshots` as const;
export const CONF_MENU_BUTTONS_TIMELINE = `${CONF_MENU}.buttons.timeline` as const;
export const CONF_DIMENSIONS = 'dimensions' as const;
export const CONF_DIMENSIONS_ASPECT_RATIO = `${CONF_DIMENSIONS}.aspect_ratio` as const;
+24 -2
View File
@@ -300,6 +300,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
value: 'none',
label: localize('config.common.controls.next_previous.styles.none'),
},
{
value: 'thumbnails',
label: localize('config.common.controls.next_previous.styles.thumbnails'),
},
];
protected _aspectRatioModes: EditorSelectOption[] = [
@@ -912,6 +916,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
domain: string,
configPathStyle: string,
configPathSize: string,
options?: {
allowIcons?: boolean;
allowThumbnails?: boolean;
},
): TemplateResult | void {
return this._putInSubmenu(
domain,
@@ -919,9 +927,17 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
'config.common.controls.next_previous.editor_label',
{ name: 'mdi:arrow-right-bold-circle' },
html`
${this._renderOptionSelector(configPathStyle, this._nextPreviousControlStyles, {
${this._renderOptionSelector(
configPathStyle,
this._nextPreviousControlStyles.filter(
(item) =>
(!!options?.allowThumbnails || item.value !== 'thumbnails') &&
(!!options?.allowIcons || item.value !== 'icons'),
),
{
label: localize('config.common.controls.next_previous.style'),
})}
},
)}
${this._renderNumberInput(configPathSize, {
min: BUTTON_SIZE_MIN,
label: localize('config.common.controls.next_previous.size'),
@@ -1494,6 +1510,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
MENU_LIVE_CONTROLS_NEXT_PREVIOUS,
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE,
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
{
allowIcons: true,
},
)}
${this._renderThumbnailsControls(
MENU_LIVE_CONTROLS_THUMBNAILS,
@@ -1584,6 +1603,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
MENU_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS,
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE,
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_SIZE,
{
allowThumbnails: true,
},
)}
${this._renderThumbnailsControls(
MENU_MEDIA_VIEWER_CONTROLS_THUMBNAILS,
+2 -1
View File
@@ -89,7 +89,8 @@
"styles": {
"chevrons": "Chevrons",
"icons": "Icons",
"none": "None"
"none": "None",
"thumbnails": "Thumbnails"
}
},
"timeline": {
+2 -1
View File
@@ -88,7 +88,8 @@
"styles": {
"chevrons": "Chevrons",
"icons": "Icone",
"none": "Icone"
"none": "Nessuno",
"thumbnails": "Miniature"
}
},
"timeline": {
+2 -1
View File
@@ -88,7 +88,8 @@
"styles": {
"chevrons": "Setas",
"icons": "Ícones",
"none": "Nenhum"
"none": "Nenhum",
"thumbnails": "Miniaturas"
}
},
"timeline": {
+141
View File
@@ -0,0 +1,141 @@
// TODO: Change defaults themselves?
// TODO: Camera auto-dep detection
// TODO: CSS
// TODO: Renderprogress
import { deepRemoveDefaults } from './utils/zod.js';
import {
frigateCardConfigSchema,
FrigateCardConfig,
RawFrigateCardConfig,
} from './types';
import { getConfigValue, setConfigValue } from './config-mgmt.js';
import {
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS,
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
CONF_LIVE_AUTO_MUTE,
CONF_LIVE_AUTO_PLAY,
CONF_LIVE_CONTROLS_THUMBNAILS_MODE,
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS,
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS,
CONF_LIVE_CONTROLS_TITLE_MODE,
CONF_LIVE_DRAGGABLE,
CONF_LIVE_LAZY_UNLOAD,
CONF_LIVE_SHOW_IMAGE_DURING_LOAD,
CONF_LIVE_TRANSITION_EFFECT,
CONF_MEDIA_VIEWER_AUTO_MUTE,
CONF_MEDIA_VIEWER_AUTO_PAUSE,
CONF_MEDIA_VIEWER_AUTO_PLAY,
CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE,
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE,
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_DETAILS,
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS,
CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE,
CONF_MEDIA_VIEWER_DRAGGABLE,
CONF_MEDIA_VIEWER_TRANSITION_EFFECT,
CONF_MENU_BUTTONS_FRIGATE,
CONF_MENU_BUTTONS_MEDIA_PLAYER,
CONF_MENU_BUTTONS_TIMELINE,
CONF_MENU_STYLE,
CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE,
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS,
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
CONF_TIMELINE_SHOW_RECORDINGS,
} from './const.js';
// Caution: These values are applied after parsing (since we cannot know the
// performance profile until afterwards), so there is no validation on these
// defaults.
const LOW_PROFILE_DEFAULTS = {
// Disable thumbnail carousels.
[CONF_LIVE_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
[CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
// Do not show recordings on timelines.
[CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS]: false,
[CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS]: false,
[CONF_TIMELINE_SHOW_RECORDINGS]: false,
// Take no automatic media actions.
[CONF_LIVE_AUTO_PLAY]: 'never' as const,
[CONF_LIVE_AUTO_MUTE]: 'never' as const,
[CONF_MEDIA_VIEWER_AUTO_PLAY]: 'never' as const,
[CONF_MEDIA_VIEWER_AUTO_PAUSE]: 'never' as const,
[CONF_MEDIA_VIEWER_AUTO_MUTE]: 'never' as const,
// Always unload resources that are lazily loaded.
[CONF_LIVE_LAZY_UNLOAD]: 'all' as const,
// Media carousels do not drag.
[CONF_LIVE_DRAGGABLE]: false,
[CONF_MEDIA_VIEWER_DRAGGABLE]: false,
// Media carousels have no effects.
[CONF_LIVE_TRANSITION_EFFECT]: 'none' as const,
[CONF_MEDIA_VIEWER_TRANSITION_EFFECT]: 'none' as const,
// Do not show image during load.
[CONF_LIVE_SHOW_IMAGE_DURING_LOAD]: false,
// Media player next/previous are chevrons.
[CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE]: 'chevrons' as const,
[CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE]: 'none' as const,
[CONF_LIVE_CONTROLS_TITLE_MODE]: 'none' as const,
// Move the menu to outside to remove the need to interact with it with open.
[CONF_MENU_STYLE]: 'outside',
// Hide several buttons that are otherwise visible by default.
[`${CONF_MENU_BUTTONS_FRIGATE}.enabled`]: false,
[`${CONF_MENU_BUTTONS_TIMELINE}.enabled`]: false,
[`${CONF_MENU_BUTTONS_MEDIA_PLAYER}.enabled`]: false,
[`${CONF_MENU_BUTTONS_TIMELINE}.enabled`]: false,
// Disable all options in thumbnails.
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
[CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
[CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL]: false,
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL]: false,
[CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS]: false,
};
/**
* Set low performance profile mode. Sets flags as defined in
* LOW_PROFILE_DEFAULTS unless they are explicitly overriden in the
* configuration.
* @param inputConfig The raw unparsed input configuration.
* @param parsedConfig The parsed input configuration.
* @returns A changed (in-place) parsed input configuration.
*/
export const setLowPerformanceProfile = (
inputConfig: RawFrigateCardConfig,
parsedConfig: FrigateCardConfig,
): FrigateCardConfig => {
const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse(
inputConfig,
);
if (defaultLessParseResult.success) {
const defaultLessConfig = defaultLessParseResult.data;
Object.entries(LOW_PROFILE_DEFAULTS).forEach(([k, v]: [string, unknown]) => {
if (getConfigValue(defaultLessConfig, k) === undefined) {
setConfigValue(parsedConfig, k, v);
}
});
}
return parsedConfig;
};
+10
View File
@@ -1206,6 +1206,14 @@ const liveOverridesSchema = z
.optional();
export type LiveOverrides = z.infer<typeof liveOverridesSchema>;
const performanceConfigDefault = {
profile: 'high' as const,
}
const performanceConfigSchema = z.object({
profile: z.enum(['low', 'high'])
}).default(performanceConfigDefault);
/**
* Main card config.
*/
@@ -1221,6 +1229,7 @@ export const frigateCardConfigSchema = z.object({
elements: pictureElementsSchema,
dimensions: dimensionsConfigSchema,
timeline: timelineConfigSchema,
performance: performanceConfigSchema,
// Configuration overrides.
overrides: overridesSchema,
@@ -1246,6 +1255,7 @@ export const frigateCardConfigDefaults = {
image: imageConfigDefault,
timeline: timelineConfigDefault,
mini_timeline: timelineCoreConfigDefault,
performance: performanceConfigDefault,
};
const menuButtonSchema = z.discriminatedUnion('type', [
+1 -3
View File
@@ -104,7 +104,6 @@ export class DataManager {
protected _maxAgeSeconds: number = DATA_MANAGER_MAX_AGE_SECONDS;
protected _cameras: Map<string, CameraConfig>;
protected _mediaType: TimelineMediaType;
// Garbage collect segments at most once an hour.
protected _throttledSegmentGarbageCollector = throttle(
@@ -115,9 +114,8 @@ export class DataManager {
{ trailing: true },
);
constructor(cameras: Map<string, CameraConfig>, mediaType: TimelineMediaType) {
constructor(cameras: Map<string, CameraConfig>) {
this._cameras = cameras;
this._mediaType = mediaType;
}
// Get the last event fetch date.