Add update trigger action.
This commit is contained in:
@@ -28,7 +28,7 @@ Principles used in the selection of options set by `low-profile` profile mode:
|
|||||||
- Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card.
|
- Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card.
|
||||||
- Do not break the visual aesthetic of the card.
|
- Do not break the visual aesthetic of the card.
|
||||||
|
|
||||||
See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of options set by this profile.
|
See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of defaults set by this profile.
|
||||||
|
|
||||||
## `scrubbing`
|
## `scrubbing`
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ view:
|
|||||||
untrigger_seconds: 0
|
untrigger_seconds: 0
|
||||||
actions:
|
actions:
|
||||||
interaction_mode: inactive
|
interaction_mode: inactive
|
||||||
trigger: default
|
trigger: update
|
||||||
untrigger: none
|
untrigger: none
|
||||||
keyboard_shortcuts:
|
keyboard_shortcuts:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ This could be for any number of reasons. Chromecast devices can be quite picky
|
|||||||
on network, DNS and certificate issues, as well as audio and video codecs. Check
|
on network, DNS and certificate issues, as well as audio and video codecs. Check
|
||||||
your Home Assistant log as there may be more information in there.
|
your Home Assistant log as there may be more information in there.
|
||||||
|
|
||||||
!>: In particular, for Frigate to support casting of clips, the default ffmpeg
|
!> In particular, for Frigate to support casting of clips, the default ffmpeg
|
||||||
settings for Frigate must be modified, i.e. Frigate does not encode clips in a
|
settings for Frigate must be modified, i.e. Frigate does not encode clips in a
|
||||||
Chromecast compatible format out of the box (specifically: audio must be enabled
|
Chromecast compatible format out of the box (specifically: audio must be enabled
|
||||||
in the AAC codec, whether your camera supports audio or not). See the [Frigate
|
in the AAC codec, whether your camera supports audio or not). See the [Frigate
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ export class TriggersManager {
|
|||||||
|
|
||||||
// If this is a high-fidelity event where we are certain about new media,
|
// If this is a high-fidelity event where we are certain about new media,
|
||||||
// don't take action unless it's to change to live (Frigate engine may pump
|
// don't take action unless it's to change to live (Frigate engine may pump
|
||||||
// out events where there's no new media to show).
|
// out events where there's no new media to show). Other trigger actions
|
||||||
|
// (e.g. media, update) do not make sense without having some new media.
|
||||||
if (
|
if (
|
||||||
ev.fidelity === 'high' &&
|
ev.fidelity === 'high' &&
|
||||||
!ev.snapshot &&
|
!ev.snapshot &&
|
||||||
@@ -96,7 +97,19 @@ export class TriggersManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._hasAllowableInteractionStateForAction()) {
|
if (this._hasAllowableInteractionStateForAction()) {
|
||||||
if (triggerAction === 'live') {
|
if (triggerAction === 'update') {
|
||||||
|
const view = this._api.getViewManager().getView()?.evolve({
|
||||||
|
// Reset the media queries to catch media to be refetched in the
|
||||||
|
// current view.
|
||||||
|
query: null,
|
||||||
|
queryResults: null,
|
||||||
|
});
|
||||||
|
/* istanbul ignore else: the else path cannot be reached, as the camera
|
||||||
|
cannot be triggered without a view -- @preserve */
|
||||||
|
if (view) {
|
||||||
|
this._api.getViewManager().setView(view.clone());
|
||||||
|
}
|
||||||
|
} else if (triggerAction === 'live') {
|
||||||
this._api.getViewManager().setViewByParameters({
|
this._api.getViewManager().setViewByParameters({
|
||||||
viewName: 'live',
|
viewName: 'live',
|
||||||
cameraID: ev.cameraID,
|
cameraID: ev.cameraID,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import {
|
|||||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
|
||||||
CONF_TIMELINE_SHOW_RECORDINGS,
|
CONF_TIMELINE_SHOW_RECORDINGS,
|
||||||
|
CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER,
|
||||||
} from '../../const.js';
|
} from '../../const.js';
|
||||||
|
|
||||||
export const LOW_PERFORMANCE_PROFILE = {
|
export const LOW_PERFORMANCE_PROFILE = {
|
||||||
@@ -134,4 +135,7 @@ export const LOW_PERFORMANCE_PROFILE = {
|
|||||||
// Refresh the live camera image every 10 seconds (same as stock Home
|
// Refresh the live camera image every 10 seconds (same as stock Home
|
||||||
// Assistant Picture Glance).
|
// Assistant Picture Glance).
|
||||||
[CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10,
|
[CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10,
|
||||||
|
|
||||||
|
// No trigger actions.
|
||||||
|
[CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER]: 'none'
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-9
@@ -1406,7 +1406,7 @@ const viewConfigDefault = {
|
|||||||
filter_selected_camera: true,
|
filter_selected_camera: true,
|
||||||
actions: {
|
actions: {
|
||||||
interaction_mode: 'inactive' as const,
|
interaction_mode: 'inactive' as const,
|
||||||
trigger: 'default' as const,
|
trigger: 'update' as const,
|
||||||
untrigger: 'none' as const,
|
untrigger: 'none' as const,
|
||||||
},
|
},
|
||||||
untrigger_seconds: 0,
|
untrigger_seconds: 0,
|
||||||
@@ -1415,26 +1415,25 @@ const viewConfigDefault = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const triggersSchema = z.object({
|
export const triggersSchema = z.object({
|
||||||
filter_selected_camera: z
|
|
||||||
.boolean()
|
|
||||||
.default(viewConfigDefault.triggers.filter_selected_camera),
|
|
||||||
show_trigger_status: z
|
|
||||||
.boolean()
|
|
||||||
.default(viewConfigDefault.triggers.show_trigger_status),
|
|
||||||
|
|
||||||
actions: z
|
actions: z
|
||||||
.object({
|
.object({
|
||||||
interaction_mode: z
|
interaction_mode: z
|
||||||
.enum(['all', 'inactive', 'active'])
|
.enum(['all', 'inactive', 'active'])
|
||||||
.default(viewConfigDefault.triggers.actions.interaction_mode),
|
.default(viewConfigDefault.triggers.actions.interaction_mode),
|
||||||
trigger: z
|
trigger: z
|
||||||
.enum(['live', 'default', 'media', 'none'])
|
.enum(['default', 'live', 'media', 'none', 'update'])
|
||||||
.default(viewConfigDefault.triggers.actions.trigger),
|
.default(viewConfigDefault.triggers.actions.trigger),
|
||||||
untrigger: z
|
untrigger: z
|
||||||
.enum(['default', 'none'])
|
.enum(['default', 'none'])
|
||||||
.default(viewConfigDefault.triggers.actions.untrigger),
|
.default(viewConfigDefault.triggers.actions.untrigger),
|
||||||
})
|
})
|
||||||
.default(viewConfigDefault.triggers.actions),
|
.default(viewConfigDefault.triggers.actions),
|
||||||
|
filter_selected_camera: z
|
||||||
|
.boolean()
|
||||||
|
.default(viewConfigDefault.triggers.filter_selected_camera),
|
||||||
|
show_trigger_status: z
|
||||||
|
.boolean()
|
||||||
|
.default(viewConfigDefault.triggers.show_trigger_status),
|
||||||
untrigger_seconds: z.number().default(viewConfigDefault.triggers.untrigger_seconds),
|
untrigger_seconds: z.number().default(viewConfigDefault.triggers.untrigger_seconds),
|
||||||
});
|
});
|
||||||
export type TriggersOptions = z.infer<typeof triggersSchema>;
|
export type TriggersOptions = z.infer<typeof triggersSchema>;
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { add } from 'date-fns';
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { CardController } from '../../src/card-controller/controller';
|
import { CardController } from '../../src/card-controller/controller';
|
||||||
import { TriggersManager } from '../../src/card-controller/triggers-manager';
|
import { TriggersManager } from '../../src/card-controller/triggers-manager';
|
||||||
import { TriggersOptions, triggersSchema } from '../../src/config/types';
|
import {
|
||||||
|
FrigateCardView,
|
||||||
|
TriggersOptions,
|
||||||
|
triggersSchema,
|
||||||
|
} from '../../src/config/types';
|
||||||
import {
|
import {
|
||||||
createCameraConfig,
|
createCameraConfig,
|
||||||
createCameraManager,
|
createCameraManager,
|
||||||
@@ -16,11 +20,12 @@ vi.mock('lodash-es/throttle', () => ({
|
|||||||
default: vi.fn((fn) => fn),
|
default: vi.fn((fn) => fn),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const baseTriggersConfig: Partial<TriggersOptions> = {
|
const baseTriggersConfig: TriggersOptions = {
|
||||||
untrigger_seconds: 10,
|
untrigger_seconds: 10,
|
||||||
filter_selected_camera: false,
|
filter_selected_camera: false,
|
||||||
|
show_trigger_status: false,
|
||||||
actions: {
|
actions: {
|
||||||
trigger: 'live' as const,
|
trigger: 'update' as const,
|
||||||
untrigger: 'default' as const,
|
untrigger: 'default' as const,
|
||||||
interaction_mode: 'inactive' as const,
|
interaction_mode: 'inactive' as const,
|
||||||
},
|
},
|
||||||
@@ -30,6 +35,7 @@ const baseTriggersConfig: Partial<TriggersOptions> = {
|
|||||||
// function reduces it.
|
// function reduces it.
|
||||||
const createTriggerAPI = (options?: {
|
const createTriggerAPI = (options?: {
|
||||||
config?: Partial<TriggersOptions>;
|
config?: Partial<TriggersOptions>;
|
||||||
|
default?: FrigateCardView;
|
||||||
interaction?: boolean;
|
interaction?: boolean;
|
||||||
}): CardController => {
|
}): CardController => {
|
||||||
const api = createCardAPI();
|
const api = createCardAPI();
|
||||||
@@ -39,6 +45,7 @@ const createTriggerAPI = (options?: {
|
|||||||
triggers: options?.config
|
triggers: options?.config
|
||||||
? triggersSchema.parse(options.config)
|
? triggersSchema.parse(options.config)
|
||||||
: baseTriggersConfig,
|
: baseTriggersConfig,
|
||||||
|
...(options?.default && { default: options.default }),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -101,161 +108,266 @@ describe('TriggersManager', () => {
|
|||||||
expect(manager.isTriggered()).toBeFalsy();
|
expect(manager.isTriggered()).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger and untrigger based on low fidelity event', () => {
|
describe('trigger actions', () => {
|
||||||
const api = createTriggerAPI();
|
it('update', () => {
|
||||||
const manager = new TriggersManager(api);
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
manager.handleCameraEvent({
|
...baseTriggersConfig,
|
||||||
cameraID: 'camera_1',
|
actions: {
|
||||||
type: 'new',
|
...baseTriggersConfig.actions,
|
||||||
});
|
trigger: 'update',
|
||||||
|
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
|
||||||
expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({
|
|
||||||
triggered: new Set(['camera_1']),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
|
||||||
viewName: 'live' as const,
|
|
||||||
cameraID: 'camera_1' as const,
|
|
||||||
});
|
|
||||||
|
|
||||||
vi.mocked(api.getConditionsManager().getState).mockReturnValue({
|
|
||||||
triggered: new Set(['camera_1']),
|
|
||||||
});
|
|
||||||
|
|
||||||
manager.handleCameraEvent({
|
|
||||||
cameraID: 'camera_1',
|
|
||||||
type: 'end',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Will still be triggered, but untrigger timer will be running.
|
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
|
||||||
|
|
||||||
vi.setSystemTime(add(start, { seconds: 10 }));
|
|
||||||
vi.runOnlyPendingTimers();
|
|
||||||
|
|
||||||
expect(manager.isTriggered()).toBeFalsy();
|
|
||||||
expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({
|
|
||||||
triggered: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(api.getViewManager().setViewDefault).toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('should treat high fidelity events appropriately', () => {
|
|
||||||
it('with no media', () => {
|
|
||||||
const api = createTriggerAPI();
|
|
||||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
|
||||||
createConfig({
|
|
||||||
view: {
|
|
||||||
default: 'clips',
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
);
|
});
|
||||||
|
|
||||||
const manager = new TriggersManager(api);
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
manager.handleCameraEvent({
|
manager.handleCameraEvent({
|
||||||
cameraID: 'camera_1',
|
cameraID: 'camera_1',
|
||||||
type: 'new',
|
type: 'new',
|
||||||
fidelity: 'high',
|
|
||||||
|
|
||||||
// Intentionally blank.
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
expect(manager.isTriggered()).toBeTruthy();
|
||||||
|
expect(api.getViewManager().setView).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('default', () => {
|
||||||
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
|
...baseTriggersConfig,
|
||||||
|
actions: {
|
||||||
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
|
|
||||||
|
expect(manager.isTriggered()).toBeTruthy();
|
||||||
|
expect(api.getViewManager().setViewDefault).toBeCalledWith({
|
||||||
|
cameraID: 'camera_1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('live', () => {
|
||||||
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
|
...baseTriggersConfig,
|
||||||
|
actions: {
|
||||||
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'live',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
|
|
||||||
|
expect(manager.isTriggered()).toBeTruthy();
|
||||||
|
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||||
|
viewName: 'live',
|
||||||
|
cameraID: 'camera_1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('media', () => {
|
||||||
|
it.each([
|
||||||
|
[false, false, null],
|
||||||
|
[false, true, 'clip' as const],
|
||||||
|
[true, false, 'snapshot' as const],
|
||||||
|
[true, true, 'clip' as const],
|
||||||
|
])(
|
||||||
|
'with snapshot %s and clip %s',
|
||||||
|
async (
|
||||||
|
hasSnapshot: boolean,
|
||||||
|
hasClip: boolean,
|
||||||
|
viewName: 'clip' | 'snapshot' | null,
|
||||||
|
) => {
|
||||||
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
|
actions: {
|
||||||
|
interaction_mode: 'all',
|
||||||
|
trigger: 'media',
|
||||||
|
untrigger: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
|
manager.handleCameraEvent({
|
||||||
|
cameraID: 'camera_1',
|
||||||
|
type: 'new',
|
||||||
|
fidelity: 'high',
|
||||||
|
snapshot: hasSnapshot,
|
||||||
|
clip: hasClip,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!viewName) {
|
||||||
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||||
|
} else {
|
||||||
|
expect(manager.isTriggered()).toBeTruthy();
|
||||||
|
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
||||||
|
cameraID: 'camera_1',
|
||||||
|
viewName: viewName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('none', () => {
|
||||||
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
|
...baseTriggersConfig,
|
||||||
|
actions: {
|
||||||
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
|
|
||||||
|
expect(manager.isTriggered()).toBeTruthy();
|
||||||
|
expect(api.getViewManager().setView).not.toBeCalled();
|
||||||
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||||
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('untrigger actions', () => {
|
||||||
|
it('none', () => {
|
||||||
|
const api = createTriggerAPI({
|
||||||
|
config: {
|
||||||
|
...baseTriggersConfig,
|
||||||
|
actions: {
|
||||||
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'none',
|
||||||
|
untrigger: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' });
|
||||||
|
|
||||||
|
vi.setSystemTime(add(start, { seconds: 10 }));
|
||||||
|
vi.runOnlyPendingTimers();
|
||||||
|
|
||||||
|
expect(manager.isTriggered()).toBeFalsy();
|
||||||
|
|
||||||
|
expect(api.getViewManager().setView).not.toBeCalled();
|
||||||
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with media', () => {
|
it('default', () => {
|
||||||
const api = createTriggerAPI();
|
const api = createTriggerAPI({
|
||||||
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
|
config: {
|
||||||
createConfig({
|
...baseTriggersConfig,
|
||||||
view: {
|
actions: {
|
||||||
default: 'clips',
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'none',
|
||||||
|
untrigger: 'default',
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
);
|
|
||||||
|
|
||||||
const manager = new TriggersManager(api);
|
|
||||||
manager.handleCameraEvent({
|
|
||||||
cameraID: 'camera_1',
|
|
||||||
type: 'new',
|
|
||||||
fidelity: 'high',
|
|
||||||
clip: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
const manager = new TriggersManager(api);
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' });
|
||||||
|
|
||||||
|
vi.setSystemTime(add(start, { seconds: 10 }));
|
||||||
|
vi.runOnlyPendingTimers();
|
||||||
|
|
||||||
|
expect(manager.isTriggered()).toBeFalsy();
|
||||||
|
|
||||||
expect(api.getViewManager().setViewDefault).toBeCalled();
|
expect(api.getViewManager().setViewDefault).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should change to default view when suitably configured', () => {
|
it('should manage condition state', () => {
|
||||||
const api = createTriggerAPI({
|
const api = createTriggerAPI({
|
||||||
config: {
|
config: {
|
||||||
|
...baseTriggersConfig,
|
||||||
actions: {
|
actions: {
|
||||||
interaction_mode: 'all',
|
...baseTriggersConfig.actions,
|
||||||
trigger: 'default',
|
trigger: 'none',
|
||||||
untrigger: 'none',
|
untrigger: 'none',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const manager = new TriggersManager(api);
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
manager.handleCameraEvent({
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' });
|
||||||
cameraID: 'camera_1',
|
|
||||||
type: 'new',
|
expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({
|
||||||
|
triggered: new Set(['camera_1']),
|
||||||
|
});
|
||||||
|
vi.mocked(api.getConditionsManager().getState).mockReturnValue({
|
||||||
|
triggered: new Set(['camera_1']),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' });
|
||||||
expect(api.getViewManager().setViewDefault).toBeCalledWith({
|
|
||||||
cameraID: 'camera_1',
|
vi.setSystemTime(add(start, { seconds: 10 }));
|
||||||
|
vi.runOnlyPendingTimers();
|
||||||
|
|
||||||
|
expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({
|
||||||
|
triggered: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should change to media view', () => {
|
describe('should take no actions with high-fidelity event', () => {
|
||||||
it.each([
|
it('with non-live action', () => {
|
||||||
[false, false, null],
|
const api = createTriggerAPI({
|
||||||
[false, true, 'clip' as const],
|
config: {
|
||||||
[true, false, 'snapshot' as const],
|
...baseTriggersConfig,
|
||||||
[true, true, 'clip' as const],
|
actions: {
|
||||||
])(
|
...baseTriggersConfig.actions,
|
||||||
'with snapshot %s and clip %s',
|
trigger: 'media',
|
||||||
async (
|
|
||||||
hasSnapshot: boolean,
|
|
||||||
hasClip: boolean,
|
|
||||||
viewName: 'clip' | 'snapshot' | null,
|
|
||||||
) => {
|
|
||||||
const api = createTriggerAPI({
|
|
||||||
config: {
|
|
||||||
actions: {
|
|
||||||
interaction_mode: 'all',
|
|
||||||
trigger: 'media',
|
|
||||||
untrigger: 'none',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
const manager = new TriggersManager(api);
|
default: 'live',
|
||||||
|
});
|
||||||
|
|
||||||
manager.handleCameraEvent({
|
const manager = new TriggersManager(api);
|
||||||
cameraID: 'camera_1',
|
|
||||||
type: 'new',
|
|
||||||
fidelity: 'high',
|
|
||||||
snapshot: hasSnapshot,
|
|
||||||
clip: hasClip,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!viewName) {
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' });
|
||||||
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
|
||||||
} else {
|
expect(api.getViewManager().setView).not.toBeCalled();
|
||||||
expect(manager.isTriggered()).toBeTruthy();
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||||
expect(api.getViewManager().setViewByParameters).toBeCalledWith({
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||||
cameraID: 'camera_1',
|
});
|
||||||
viewName: viewName,
|
|
||||||
});
|
it('with non-live default', () => {
|
||||||
}
|
const api = createTriggerAPI({
|
||||||
},
|
config: {
|
||||||
);
|
...baseTriggersConfig,
|
||||||
|
actions: {
|
||||||
|
...baseTriggersConfig.actions,
|
||||||
|
trigger: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: 'clips',
|
||||||
|
});
|
||||||
|
|
||||||
|
const manager = new TriggersManager(api);
|
||||||
|
|
||||||
|
manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' });
|
||||||
|
|
||||||
|
expect(api.getViewManager().setView).not.toBeCalled();
|
||||||
|
expect(api.getViewManager().setViewDefault).not.toBeCalled();
|
||||||
|
expect(api.getViewManager().setViewByParameters).not.toBeCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should take no actions with human interactions', () => {
|
it('should take no actions with human interactions', () => {
|
||||||
|
|||||||
@@ -50,5 +50,6 @@ it('low performance profile', () => {
|
|||||||
'timeline.controls.thumbnails.show_favorite_control': false,
|
'timeline.controls.thumbnails.show_favorite_control': false,
|
||||||
'timeline.controls.thumbnails.show_timeline_control': false,
|
'timeline.controls.thumbnails.show_timeline_control': false,
|
||||||
'timeline.show_recordings': false,
|
'timeline.show_recordings': false,
|
||||||
|
'view.triggers.actions.trigger': 'none',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ describe('config defaults', () => {
|
|||||||
show_trigger_status: false,
|
show_trigger_status: false,
|
||||||
untrigger_seconds: 0,
|
untrigger_seconds: 0,
|
||||||
actions: {
|
actions: {
|
||||||
trigger: 'default',
|
trigger: 'update',
|
||||||
untrigger: 'none',
|
untrigger: 'none',
|
||||||
interaction_mode: 'inactive',
|
interaction_mode: 'inactive',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user