feat: Add event-based automation triggers (#2537)
This commit is contained in:
committed by
dermotduffy
parent
b701366762
commit
a31816c168
@@ -7,21 +7,18 @@ import {
|
||||
CameraQuery,
|
||||
QueryType,
|
||||
} from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { BROWSE_MEDIA_CACHE_SECONDS } from '../../../src/ha/browse-media/types';
|
||||
import { BrowseMediaWalker } from '../../../src/ha/browse-media/walker';
|
||||
import { ResolvedMediaCache } from '../../../src/ha/resolved-media';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
import { ViewMedia } from '../../../src/view/item';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import { createCameraConfig, createHASS } from '../../test-utils';
|
||||
import { createCameraConfig, createHASS, createHASSManager } from '../../test-utils';
|
||||
|
||||
const createEngine = (): BrowseMediaCameraManagerEngine => {
|
||||
return new BrowseMediaCameraManagerEngine(
|
||||
new EntityRegistryManagerMock(),
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
createHASSManager(),
|
||||
new BrowseMediaWalker(),
|
||||
new ResolvedMediaCache(),
|
||||
new CameraManagerRequestCache(),
|
||||
|
||||
+150
-218
@@ -13,6 +13,8 @@ import {
|
||||
createCameraConfig,
|
||||
createCapabilities,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createHASSEvent,
|
||||
createInitializedCamera,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
@@ -25,10 +27,7 @@ describe('Camera', () => {
|
||||
const config = createCameraConfig();
|
||||
const camera = new Camera(
|
||||
config,
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getConfig()).toBe(config);
|
||||
});
|
||||
@@ -38,10 +37,7 @@ describe('Camera', () => {
|
||||
const capabilities = createCapabilities();
|
||||
const camera = await createInitializedCamera(
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
capabilities,
|
||||
);
|
||||
expect(camera.getCapabilities()).toBe(capabilities);
|
||||
@@ -50,20 +46,14 @@ describe('Camera', () => {
|
||||
it('when unpopulated', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getCapabilities()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get engine', async () => {
|
||||
const engine = new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
);
|
||||
const engine = new GenericCameraManagerEngine(createHASSManager());
|
||||
const camera = new Camera(createCameraConfig(), engine);
|
||||
expect(camera.getEngine()).toBe(engine);
|
||||
});
|
||||
@@ -71,10 +61,7 @@ describe('Camera', () => {
|
||||
it('should set and get id', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
camera.setID('foo');
|
||||
expect(camera.getID()).toBe('foo');
|
||||
@@ -84,10 +71,7 @@ describe('Camera', () => {
|
||||
it('should throw without id', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(() => camera.getID()).toThrowError(
|
||||
'Could not determine camera id for the following ' +
|
||||
@@ -107,17 +91,12 @@ describe('Camera', () => {
|
||||
entities: ['camera.foo'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
@@ -130,6 +109,26 @@ describe('Camera', () => {
|
||||
expect(stateWatcher.unsubscribe).toBeCalled();
|
||||
});
|
||||
|
||||
it('should skip initialization when hass is unavailable', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({
|
||||
triggers: {
|
||||
entities: ['camera.foo'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hassManager: createHASSManager({ hass: null, stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(stateWatcher.subscribe).not.toBeCalled();
|
||||
expect(camera.getCapabilities()).toBeNull();
|
||||
});
|
||||
|
||||
it('should set capabilities and use go2rtc metadata endpoint', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({
|
||||
@@ -138,18 +137,13 @@ describe('Camera', () => {
|
||||
stream: 'stream',
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(true);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).toHaveBeenCalledWith(
|
||||
@@ -180,18 +174,13 @@ describe('Camera', () => {
|
||||
stream: 'stream',
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(false);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.has('2-way-audio')).toBe(false);
|
||||
@@ -206,18 +195,13 @@ describe('Camera', () => {
|
||||
metadata_fetch_timeout_seconds: 20,
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(true);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).toHaveBeenCalledWith(
|
||||
@@ -240,10 +224,7 @@ describe('Camera', () => {
|
||||
live: true,
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(true);
|
||||
@@ -252,9 +233,7 @@ describe('Camera', () => {
|
||||
hass.config.components = ['hass_web_proxy'];
|
||||
|
||||
await camera.initialize({
|
||||
hass,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ hass }),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).toHaveBeenCalledWith(
|
||||
@@ -281,10 +260,7 @@ describe('Camera', () => {
|
||||
createCameraConfig({
|
||||
proxy: { live: true },
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getLiveProxyConfig()).toEqual(
|
||||
expect.objectContaining({ enabled: true, enforce: true }),
|
||||
@@ -296,10 +272,7 @@ describe('Camera', () => {
|
||||
createCameraConfig({
|
||||
proxy: { media: true },
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getMediaProxyConfig()).toEqual(
|
||||
expect.objectContaining({ enabled: true, enforce: true }),
|
||||
@@ -312,10 +285,7 @@ describe('Camera', () => {
|
||||
live_provider: 'go2rtc',
|
||||
go2rtc: { url: 'http://go2rtc' },
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getLiveProxyConfig()).toEqual(
|
||||
expect.objectContaining({ enabled: true, enforce: false }),
|
||||
@@ -327,10 +297,7 @@ describe('Camera', () => {
|
||||
createCameraConfig({
|
||||
proxy: { media: 'auto' },
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getMediaProxyConfig()).toEqual(
|
||||
expect.objectContaining({ enabled: false, enforce: false }),
|
||||
@@ -344,16 +311,11 @@ describe('Camera', () => {
|
||||
force: ['2-way-audio'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).not.toHaveBeenCalled();
|
||||
@@ -368,16 +330,11 @@ describe('Camera', () => {
|
||||
force: ['2-way-audio'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).not.toHaveBeenCalled();
|
||||
@@ -392,16 +349,11 @@ describe('Camera', () => {
|
||||
force: ['2-way-audio'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).not.toHaveBeenCalled();
|
||||
@@ -415,16 +367,11 @@ describe('Camera', () => {
|
||||
disable: ['2-way-audio'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).not.toHaveBeenCalled();
|
||||
@@ -438,16 +385,11 @@ describe('Camera', () => {
|
||||
disable_except: ['substream'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).not.toHaveBeenCalled();
|
||||
@@ -461,17 +403,12 @@ describe('Camera', () => {
|
||||
disable_except: ['substream', '2-way-audio'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(true);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).toHaveBeenCalled();
|
||||
@@ -485,17 +422,12 @@ describe('Camera', () => {
|
||||
disable_except: [],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
vi.mocked(liveProviderSupports2WayAudio).mockResolvedValue(true);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(liveProviderSupports2WayAudio).toHaveBeenCalled();
|
||||
@@ -510,16 +442,11 @@ describe('Camera', () => {
|
||||
});
|
||||
const camera = new Camera(
|
||||
createCameraConfig({ camera_entity: 'camera.front_door' }),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
});
|
||||
|
||||
@@ -529,16 +456,11 @@ describe('Camera', () => {
|
||||
it('should leave entity null when camera_entity is unset', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig(),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
});
|
||||
|
||||
@@ -548,16 +470,11 @@ describe('Camera', () => {
|
||||
it('should leave entity null when entityRegistryManager is not provided', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({ camera_entity: 'camera.front_door' }),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
});
|
||||
|
||||
expect(camera.getEntity()).toBeNull();
|
||||
@@ -594,10 +511,7 @@ describe('Camera', () => {
|
||||
...(options?.userEntities && { entities: options.userEntities }),
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
const hass = createHASS(
|
||||
@@ -609,9 +523,7 @@ describe('Camera', () => {
|
||||
},
|
||||
);
|
||||
await camera.initialize({
|
||||
hass,
|
||||
stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ hass, stateWatcher }),
|
||||
...(!options?.omitRegistryManager && {
|
||||
entityRegistryManager: new EntityRegistryManagerMock(
|
||||
options?.registryEntities ?? [cameraEntity, doorbellEntity],
|
||||
@@ -737,10 +649,7 @@ describe('Camera', () => {
|
||||
entities: ['binary_sensor.foo'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
{
|
||||
eventCallback: eventCallback,
|
||||
},
|
||||
@@ -748,9 +657,7 @@ describe('Camera', () => {
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
@@ -780,27 +687,25 @@ describe('Camera', () => {
|
||||
events: [{ event_type: 'zha_event' }],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
{ eventCallback },
|
||||
);
|
||||
|
||||
const eventWatcher = mock<EventWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher,
|
||||
hassManager: createHASSManager({ eventWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(eventWatcher.subscribe).toBeCalledTimes(1);
|
||||
const request = vi.mocked(eventWatcher.subscribe).mock.calls[0][1];
|
||||
const request = vi.mocked(eventWatcher.subscribe).mock.calls[0][0];
|
||||
expect(request.event_type).toBe('zha_event');
|
||||
expect(request.matcher).toBeUndefined();
|
||||
|
||||
callEventWatcherCallback(eventWatcher, { command: 'press' });
|
||||
callEventWatcherCallback(
|
||||
eventWatcher,
|
||||
createHASSEvent('zha_event', { command: 'press' }),
|
||||
);
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
cameraID: 'camera_1',
|
||||
@@ -812,6 +717,63 @@ describe('Camera', () => {
|
||||
expect(eventWatcher.unsubscribe).toBeCalled();
|
||||
});
|
||||
|
||||
it('should attach a context-only matcher when only a context filter is set', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({
|
||||
id: 'camera_1',
|
||||
triggers: {
|
||||
events: [{ event_type: 'zha_event', context: { user_id: 'u-1' } }],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const eventWatcher = mock<EventWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hassManager: createHASSManager({ eventWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
const matcher = vi.mocked(eventWatcher.subscribe).mock.calls[0][0].matcher;
|
||||
expect(matcher).toBeDefined();
|
||||
expect(
|
||||
matcher?.(
|
||||
createHASSEvent('zha_event', {}, { id: 'i', user_id: 'u-1', parent_id: null }),
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
matcher?.(
|
||||
createHASSEvent('zha_event', {}, { id: 'i', user_id: 'u-2', parent_id: null }),
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should expand list-form event_type into one subscription per type', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({
|
||||
id: 'camera_1',
|
||||
triggers: {
|
||||
events: [{ event_type: ['zha_event', 'deconz_event'] }],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const eventWatcher = mock<EventWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hassManager: createHASSManager({ eventWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
expect(eventWatcher.subscribe).toBeCalledTimes(2);
|
||||
expect(vi.mocked(eventWatcher.subscribe).mock.calls[0][0].event_type).toBe(
|
||||
'zha_event',
|
||||
);
|
||||
expect(vi.mocked(eventWatcher.subscribe).mock.calls[1][0].event_type).toBe(
|
||||
'deconz_event',
|
||||
);
|
||||
});
|
||||
|
||||
it('should attach a matcher when triggers.events entry has data filter', async () => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig({
|
||||
@@ -820,24 +782,23 @@ describe('Camera', () => {
|
||||
events: [{ event_type: 'zha_event', event_data: { command: 'press' } }],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const eventWatcher = mock<EventWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher,
|
||||
hassManager: createHASSManager({ eventWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
const matcher = vi.mocked(eventWatcher.subscribe).mock.calls[0][1].matcher;
|
||||
const matcher = vi.mocked(eventWatcher.subscribe).mock.calls[0][0].matcher;
|
||||
expect(matcher).toBeDefined();
|
||||
expect(matcher?.({ command: 'press', extra: 1 })).toBe(true);
|
||||
expect(matcher?.({ command: 'release' })).toBe(false);
|
||||
expect(
|
||||
matcher?.(createHASSEvent('zha_event', { command: 'press', extra: 1 })),
|
||||
).toBe(true);
|
||||
expect(matcher?.(createHASSEvent('zha_event', { command: 'release' }))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not subscribe to events when trigger capability is disabled', async () => {
|
||||
@@ -848,17 +809,12 @@ describe('Camera', () => {
|
||||
events: [{ event_type: 'zha_event' }],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
const eventWatcher = mock<EventWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher,
|
||||
hassManager: createHASSManager({ eventWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: false }) },
|
||||
});
|
||||
|
||||
@@ -876,10 +832,7 @@ describe('Camera', () => {
|
||||
entities: ['event.front_door_doorbell'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
{
|
||||
eventCallback: eventCallback,
|
||||
},
|
||||
@@ -887,9 +840,7 @@ describe('Camera', () => {
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
@@ -913,10 +864,7 @@ describe('Camera', () => {
|
||||
entities: ['event.front_door_doorbell'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
{
|
||||
eventCallback: eventCallback,
|
||||
},
|
||||
@@ -924,9 +872,7 @@ describe('Camera', () => {
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
|
||||
@@ -953,10 +899,7 @@ describe('Camera', () => {
|
||||
entities: ['binary_sensor.foo'],
|
||||
},
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
{
|
||||
eventCallback: eventCallback,
|
||||
},
|
||||
@@ -964,9 +907,7 @@ describe('Camera', () => {
|
||||
|
||||
const stateWatcher = mock<StateWatcherSubscriptionInterface>();
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
stateWatcher: stateWatcher,
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ stateWatcher }),
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: false }) },
|
||||
});
|
||||
|
||||
@@ -1128,10 +1069,7 @@ describe('Camera', () => {
|
||||
(_name: string, cameraConfig: unknown, expectedResult: CameraProxyConfig) => {
|
||||
const camera = new Camera(
|
||||
createCameraConfig(cameraConfig),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getProxyConfig()).toEqual(expectedResult);
|
||||
},
|
||||
@@ -1145,10 +1083,7 @@ describe('Camera', () => {
|
||||
go2rtc: { stream: '' },
|
||||
camera_entity: '',
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
expect(camera.getEndpoints()).toBeNull();
|
||||
});
|
||||
@@ -1162,10 +1097,7 @@ describe('Camera', () => {
|
||||
},
|
||||
camera_entity: 'camera.foo',
|
||||
}),
|
||||
new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
),
|
||||
new GenericCameraManagerEngine(createHASSManager()),
|
||||
);
|
||||
|
||||
expect(camera.getEndpoints()).toEqual({
|
||||
|
||||
@@ -7,8 +7,6 @@ import { MotionEyeCameraManagerEngine } from '../../src/camera-manager/motioneye
|
||||
import { ReolinkCameraManagerEngine } from '../../src/camera-manager/reolink/engine-reolink.js';
|
||||
import { TPLinkCameraManagerEngine } from '../../src/camera-manager/tplink/engine-tplink.js';
|
||||
import { Engine } from '../../src/camera-manager/types.js';
|
||||
import { EventWatcherSubscriptionInterface } from '../../src/card-controller/hass/event-watcher.js';
|
||||
import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
import { CardWideConfig } from '../../src/config/schema/types.js';
|
||||
import { DeviceRegistryManager } from '../../src/ha/registry/device';
|
||||
import { EntityRegistryManager } from '../../src/ha/registry/entity/types.js';
|
||||
@@ -17,6 +15,7 @@ import { EntityRegistryManagerMock } from '../ha/registry/entity/mock.js';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
} from '../test-utils';
|
||||
@@ -232,8 +231,7 @@ describe('createEngine()', () => {
|
||||
it('should create generic engine', async () => {
|
||||
expect(
|
||||
await createFactory().createEngine(Engine.Generic, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
}),
|
||||
).toBeInstanceOf(GenericCameraManagerEngine);
|
||||
@@ -241,8 +239,7 @@ describe('createEngine()', () => {
|
||||
it('should create frigate engine', async () => {
|
||||
expect(
|
||||
await createFactory().createEngine(Engine.Frigate, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
}),
|
||||
).toBeInstanceOf(FrigateCameraManagerEngine);
|
||||
@@ -250,8 +247,7 @@ describe('createEngine()', () => {
|
||||
it('should create motioneye engine', async () => {
|
||||
expect(
|
||||
await createFactory().createEngine(Engine.MotionEye, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
}),
|
||||
).toBeInstanceOf(MotionEyeCameraManagerEngine);
|
||||
@@ -259,8 +255,7 @@ describe('createEngine()', () => {
|
||||
it('should create reolink engine', async () => {
|
||||
expect(
|
||||
await createFactory().createEngine(Engine.Reolink, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
}),
|
||||
).toBeInstanceOf(ReolinkCameraManagerEngine);
|
||||
@@ -268,8 +263,7 @@ describe('createEngine()', () => {
|
||||
it('should create tplink engine', async () => {
|
||||
expect(
|
||||
await createFactory().createEngine(Engine.TPLink, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
}),
|
||||
).toBeInstanceOf(TPLinkCameraManagerEngine);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { format } from 'date-fns';
|
||||
import { assert, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { FrigateCamera } from '../../../src/camera-manager/frigate/camera';
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
FrigateReviewWatcher,
|
||||
} from '../../../src/camera-manager/frigate/watcher';
|
||||
import { ActionsExecutor } from '../../../src/card-controller/actions/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { PTZAction } from '../../../src/config/schema/actions/custom/ptz';
|
||||
import { CameraTriggerMediaEventType } from '../../../src/config/schema/cameras';
|
||||
import { Entity, EntityRegistryManager } from '../../../src/ha/registry/entity/types';
|
||||
@@ -29,6 +27,7 @@ import {
|
||||
createCameraConfig,
|
||||
createCapabilities,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
} from '../../test-utils';
|
||||
@@ -42,7 +41,7 @@ const callEventWatcherCallback = (
|
||||
): void => {
|
||||
const mock = vi.mocked(eventWatcher.subscribe).mock;
|
||||
expect(mock.calls.length).greaterThan(n);
|
||||
mock.calls[n][1].callback(event);
|
||||
mock.calls[n][0].callback(event);
|
||||
};
|
||||
|
||||
const callReviewWatcherCallback = (
|
||||
@@ -52,7 +51,7 @@ const callReviewWatcherCallback = (
|
||||
): void => {
|
||||
const mock = vi.mocked(reviewWatcher.subscribe).mock;
|
||||
expect(mock.calls.length).greaterThan(n);
|
||||
mock.calls[n][1].callback(review);
|
||||
mock.calls[n][0].callback(review);
|
||||
};
|
||||
|
||||
describe('FrigateCamera', () => {
|
||||
@@ -69,10 +68,8 @@ describe('FrigateCamera', () => {
|
||||
const beforeConfig = { ...config };
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -92,10 +89,8 @@ describe('FrigateCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
}),
|
||||
@@ -118,10 +113,8 @@ describe('FrigateCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -144,10 +137,8 @@ describe('FrigateCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -170,10 +161,8 @@ describe('FrigateCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -191,15 +180,15 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: { client_id: 'remote_frigate' },
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: { client_id: 'remote_frigate' },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -215,15 +204,15 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: {},
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: {},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -238,10 +227,8 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -257,15 +244,15 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: { client_id: 'something_else' },
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
attributes: { client_id: 'something_else' },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -281,16 +268,16 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
state: 'unavailable',
|
||||
attributes: {},
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'camera.front_door': createStateEntity({
|
||||
entity_id: 'camera.front_door',
|
||||
state: 'unavailable',
|
||||
attributes: {},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -311,10 +298,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -340,10 +325,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -373,10 +356,8 @@ describe('FrigateCamera', () => {
|
||||
vi.mocked(getPTZInfo).mockRejectedValue(new Error());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -404,10 +385,8 @@ describe('FrigateCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -442,10 +421,8 @@ describe('FrigateCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -475,10 +452,8 @@ describe('FrigateCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -512,10 +487,8 @@ describe('FrigateCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -842,15 +815,12 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
expect(eventWatcher.subscribe).toBeCalledWith(
|
||||
hass,
|
||||
expect.objectContaining({
|
||||
instanceID: 'CLIENT_ID',
|
||||
}),
|
||||
@@ -874,10 +844,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -901,10 +869,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -927,10 +893,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -953,10 +917,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -966,9 +928,10 @@ describe('FrigateCamera', () => {
|
||||
expect(eventWatcher.unsubscribe).toBeCalled();
|
||||
});
|
||||
|
||||
it('should unsubscribe on destroy while event subscription is pending', async () => {
|
||||
it('should not subscribe when destroyed while base initialization is pending', async () => {
|
||||
const camera = new FrigateCamera(
|
||||
createCameraConfig({
|
||||
camera_entity: 'camera.front_door',
|
||||
frigate: { client_id: 'CLIENT_ID', camera_name: 'front_door' },
|
||||
triggers: {
|
||||
media_events: ['events'],
|
||||
@@ -978,45 +941,40 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
const hass = createHASS();
|
||||
let resolveSubscribe: () => void = () => {};
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
vi.mocked(eventWatcher.subscribe).mockReturnValue(
|
||||
new Promise<void>((resolve) => {
|
||||
resolveSubscribe = resolve;
|
||||
|
||||
// Pend base initialization on entity resolution so destroy() can flip
|
||||
// `_destroyed` before initialize() reaches the subscribe calls.
|
||||
let resolveEntity: () => void = () => {};
|
||||
const entityRegistryManager = mock<EntityRegistryManager>();
|
||||
vi.mocked(entityRegistryManager.getEntity).mockReturnValue(
|
||||
new Promise((resolve) => {
|
||||
resolveEntity = () => resolve(createRegistryEntity());
|
||||
}),
|
||||
);
|
||||
|
||||
const initializePromise = camera.initialize({
|
||||
hass: hass,
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
|
||||
// Pre-built so `_buildCapabilities` (which calls the un-mocked
|
||||
// `liveProviderSupports2WayAudio`) is skipped and init reaches the
|
||||
// pending Frigate event subscribe.
|
||||
capabilityOptions: { capabilities: createCapabilities({ trigger: true }) },
|
||||
});
|
||||
await vi.waitFor(() => expect(eventWatcher.subscribe).toBeCalled());
|
||||
await vi.waitFor(() => expect(entityRegistryManager.getEntity).toBeCalled());
|
||||
|
||||
await camera.destroy();
|
||||
|
||||
// Destroy iterated `_destroyCallbacks` and called the unsubscribe that
|
||||
// was registered before the (still pending) event subscribe.
|
||||
const subscribeCall = vi.mocked(eventWatcher.subscribe).mock.calls[0];
|
||||
assert(subscribeCall);
|
||||
expect(eventWatcher.unsubscribe).toBeCalledWith(subscribeCall[1]);
|
||||
// `_destroyed` short-circuits initialize() after the pending await, so
|
||||
// neither watcher is ever subscribed.
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
|
||||
resolveSubscribe();
|
||||
resolveEntity();
|
||||
await initializePromise;
|
||||
|
||||
// The subsequent `_subscribeToReviews` short-circuited on `_destroyed`,
|
||||
// so the review watcher was never subscribed (and so never needs an
|
||||
// unsubscribe -- which would otherwise be ordered before the subscribe
|
||||
// in the per-key PQueue and leak the resulting subscription).
|
||||
expect(eventWatcher.subscribe).not.toBeCalled();
|
||||
expect(eventWatcher.unsubscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.subscribe).not.toBeCalled();
|
||||
expect(reviewWatcher.unsubscribe).not.toBeCalled();
|
||||
});
|
||||
@@ -1106,10 +1064,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -1152,6 +1108,75 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('should always forward end events to clear the trigger', () => {
|
||||
it.each([
|
||||
['with media still present', true, ['front_steps']],
|
||||
['with no media present at end', false, ['front_steps']],
|
||||
['even after the object left the configured zone', true, []],
|
||||
])('%s', async (_name: string, hasClip: boolean, currentZones: string[]) => {
|
||||
const eventCallback = vi.fn();
|
||||
const camera = new FrigateCamera(
|
||||
createCameraConfig({
|
||||
id: 'CAMERA_1',
|
||||
frigate: {
|
||||
camera_name: 'camera.front_door',
|
||||
zones: ['front_steps'],
|
||||
},
|
||||
triggers: {
|
||||
media_events: ['clips'],
|
||||
},
|
||||
}),
|
||||
mock<CameraManagerEngine>(),
|
||||
{
|
||||
eventCallback: eventCallback,
|
||||
},
|
||||
);
|
||||
|
||||
const hass = createHASS();
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
|
||||
// An 'end' clears the trigger regardless of the start criteria: the
|
||||
// media may be unchanged or absent, and the object may have left the
|
||||
// zone by now.
|
||||
callEventWatcherCallback(eventWatcher, {
|
||||
type: 'end',
|
||||
before: {
|
||||
id: 'event-1',
|
||||
camera: 'camera.front_door',
|
||||
snapshot: null,
|
||||
has_clip: hasClip,
|
||||
has_snapshot: false,
|
||||
label: 'person',
|
||||
current_zones: currentZones,
|
||||
},
|
||||
after: {
|
||||
id: 'event-1',
|
||||
camera: 'camera.front_door',
|
||||
snapshot: null,
|
||||
has_clip: hasClip,
|
||||
has_snapshot: false,
|
||||
label: 'person',
|
||||
current_zones: currentZones,
|
||||
},
|
||||
});
|
||||
|
||||
expect(eventCallback).toBeCalledWith({
|
||||
type: 'end',
|
||||
cameraID: 'CAMERA_1',
|
||||
id: 'event-1',
|
||||
clip: false,
|
||||
snapshot: false,
|
||||
fidelity: 'high',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should handle zones correctly', () => {
|
||||
it.each([
|
||||
['has no zone', [], false],
|
||||
@@ -1179,10 +1204,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -1239,10 +1262,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -1296,10 +1317,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const eventWatcher = mock<FrigateEventWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: eventWatcher,
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -1350,15 +1369,12 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
expect(reviewWatcher.subscribe).toBeCalledWith(
|
||||
hass,
|
||||
expect.objectContaining({
|
||||
instanceID: 'CLIENT_ID',
|
||||
}),
|
||||
@@ -1384,10 +1400,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1414,10 +1428,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1449,10 +1461,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1514,10 +1524,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1587,10 +1595,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1660,10 +1666,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1719,10 +1723,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1777,10 +1779,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1839,10 +1839,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1898,10 +1896,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -1965,10 +1961,8 @@ describe('FrigateCamera', () => {
|
||||
const hass = createHASS();
|
||||
const reviewWatcher = mock<FrigateReviewWatcher>();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: reviewWatcher,
|
||||
});
|
||||
@@ -2044,10 +2038,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2075,10 +2067,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2100,10 +2090,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2126,10 +2114,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
await expect(
|
||||
camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
}),
|
||||
@@ -2153,10 +2139,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2179,10 +2163,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2204,10 +2186,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2238,10 +2218,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2274,10 +2252,8 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2295,10 +2271,8 @@ describe('FrigateCamera', () => {
|
||||
|
||||
const hass = createHASS();
|
||||
await camera.initialize({
|
||||
hass: hass,
|
||||
hassManager: createHASSManager({ hass }),
|
||||
entityRegistryManager: mock<EntityRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2327,12 +2301,10 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
createRegistryEntity({ entity_id: 'camera.office_frigate' }),
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2366,12 +2338,10 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
createRegistryEntity({ entity_id: 'camera.office_frigate' }),
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2420,12 +2390,10 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
createRegistryEntity({ entity_id: 'camera.office_frigate' }),
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
@@ -2457,12 +2425,10 @@ describe('FrigateCamera', () => {
|
||||
);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
createRegistryEntity({ entity_id: 'camera.office_frigate' }),
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
frigateEventWatcher: mock<FrigateEventWatcher>(),
|
||||
frigateReviewWatcher: mock<FrigateReviewWatcher>(),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { afterEach, assert, describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { RecordingSegmentsCache } from '../../../src/camera-manager/cache';
|
||||
import { Camera } from '../../../src/camera-manager/camera';
|
||||
import {
|
||||
@@ -33,8 +32,6 @@ import {
|
||||
QueryResultsType,
|
||||
QueryType,
|
||||
} from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcher } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { CameraConfig } from '../../../src/config/schema/cameras';
|
||||
import { RawAdvancedCameraCardConfig } from '../../../src/config/types';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
@@ -47,6 +44,7 @@ import {
|
||||
createFrigateRecording,
|
||||
createFrigateReview,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createStore,
|
||||
TestViewMedia,
|
||||
} from '../../test-utils';
|
||||
@@ -59,8 +57,7 @@ const createEngine = (options?: {
|
||||
}): FrigateCameraManagerEngine => {
|
||||
return new FrigateCameraManagerEngine(
|
||||
new EntityRegistryManagerMock(),
|
||||
new StateWatcher(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
createHASSManager(),
|
||||
options?.cache ?? new RecordingSegmentsCache(),
|
||||
options?.requestCache ?? new CameraManagerRequestCache(),
|
||||
);
|
||||
@@ -223,10 +220,7 @@ describe('FrigateCameraManagerEngine', () => {
|
||||
const engine = createEngine();
|
||||
vi.mocked(getPTZInfo).mockResolvedValue({ features: [], presets: [] });
|
||||
|
||||
const camera = await engine.createCamera(
|
||||
createHASS(),
|
||||
createFrigateCameraConfig(),
|
||||
);
|
||||
const camera = await engine.createCamera(createFrigateCameraConfig());
|
||||
|
||||
expect(camera).toBeInstanceOf(Camera);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { afterEach, assert, describe, expect, it, vi } from 'vitest';
|
||||
import { Connection } from 'home-assistant-js-websocket';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import {
|
||||
FrigateEventChange,
|
||||
FrigateReviewChange,
|
||||
@@ -8,7 +10,7 @@ import {
|
||||
FrigateReviewWatcher,
|
||||
} from '../../../src/camera-manager/frigate/watcher.js';
|
||||
import { HomeAssistant } from '../../../src/ha/types.js';
|
||||
import { createHASS } from '../../test-utils.js';
|
||||
import { createHASS, createHASSSource, flushPromises } from '../../test-utils.js';
|
||||
|
||||
const createEventChange = (): FrigateEventChange => {
|
||||
return {
|
||||
@@ -68,110 +70,91 @@ const createReviewChange = (): FrigateReviewChange => {
|
||||
},
|
||||
};
|
||||
};
|
||||
const callHASubscribeMessageCallback = (
|
||||
hass: HomeAssistant,
|
||||
data: unknown,
|
||||
n = 0,
|
||||
): void => {
|
||||
|
||||
// Drive the dispatcher registered with `hass.connection.subscribeMessage` to
|
||||
// simulate a Frigate WS message arriving over the bus.
|
||||
const fireMessage = (hass: HomeAssistant, data: unknown, n = 0): void => {
|
||||
const mock = vi.mocked(hass.connection.subscribeMessage).mock;
|
||||
expect(mock.calls.length).greaterThan(n);
|
||||
mock.calls[n][0](data);
|
||||
};
|
||||
|
||||
// @vitest-environment jsdom
|
||||
describe('FrigateEventWatcher', () => {
|
||||
it('should subscribe to a given topic once', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
|
||||
await stateWatcher.subscribe(hass, {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
});
|
||||
|
||||
await stateWatcher.subscribe(hass, {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
});
|
||||
|
||||
expect(hass.connection.subscribeMessage).toBeCalledTimes(1);
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should only subscribe from a given topic once', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
it('should open a WS subscription with the frigate event type and instance id', async () => {
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
|
||||
const unsubscribeCallback = vi.fn();
|
||||
vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubscribeCallback);
|
||||
watcher.subscribe({ instanceID: 'frigate', callback: vi.fn() });
|
||||
await flushPromises();
|
||||
|
||||
const request_1 = {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
};
|
||||
const request_2 = { ...request_1 };
|
||||
|
||||
await stateWatcher.subscribe(hass, request_1);
|
||||
await stateWatcher.subscribe(hass, request_2);
|
||||
|
||||
await stateWatcher.unsubscribe(request_1);
|
||||
expect(unsubscribeCallback).not.toBeCalled();
|
||||
|
||||
await stateWatcher.unsubscribe(request_2);
|
||||
expect(unsubscribeCallback).toBeCalledTimes(1);
|
||||
expect(hass.connection.subscribeMessage).toBeCalledWith(
|
||||
expect.any(Function),
|
||||
expect.objectContaining({
|
||||
type: 'frigate/events/subscribe',
|
||||
instance_id: 'frigate',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle unsubscribe during pending subscription', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
it('should unsubscribe from the WS subscription', async () => {
|
||||
const hass = createHASS();
|
||||
const unsub = vi.fn();
|
||||
vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsub);
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
const request = { instanceID: 'frigate', callback: vi.fn() };
|
||||
|
||||
let resolveSubscription: ((callback: () => Promise<void>) => void) | undefined;
|
||||
const subscriptionPromise = new Promise<() => Promise<void>>((resolve) => {
|
||||
resolveSubscription = resolve;
|
||||
});
|
||||
vi.mocked(hass.connection.subscribeMessage).mockReturnValue(subscriptionPromise);
|
||||
watcher.subscribe(request);
|
||||
await flushPromises();
|
||||
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
};
|
||||
watcher.unsubscribe(request);
|
||||
await flushPromises();
|
||||
|
||||
// Start subscription (doesn't complete yet as not awaited).
|
||||
const subscribePromise = stateWatcher.subscribe(hass, request);
|
||||
expect(unsub).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
// Unsubscribe while subscription is still pending.
|
||||
const unsubscribePromise = stateWatcher.unsubscribe(request);
|
||||
it('should drop messages from an old-connection subscription after a swap', async () => {
|
||||
const oldHass = createHASS();
|
||||
const { source, push } = createHASSSource(oldHass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
const callback = vi.fn();
|
||||
|
||||
// Complete the subscription: both subscribe and unsubscribe await the same
|
||||
// pending promise, and unsubscribe then invokes the resolved unsub.
|
||||
const unsubscribeCallback = vi.fn();
|
||||
assert(resolveSubscription);
|
||||
resolveSubscription(unsubscribeCallback);
|
||||
await subscribePromise;
|
||||
await unsubscribePromise;
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
|
||||
expect(unsubscribeCallback).toBeCalledTimes(1);
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(createEventChange()));
|
||||
expect(request.callback).not.toBeCalled();
|
||||
// Capture the dispatcher registered against the OLD connection before the
|
||||
// swap, so it still points at the now-stale era guard.
|
||||
const oldDispatcher = vi.mocked(oldHass.connection.subscribeMessage).mock
|
||||
.calls[0][0];
|
||||
|
||||
const newHass = createHASS();
|
||||
newHass.connection = mock<Connection>();
|
||||
vi.mocked(newHass.connection.subscribeMessage).mockResolvedValue(vi.fn());
|
||||
push(newHass);
|
||||
await flushPromises();
|
||||
|
||||
oldDispatcher(JSON.stringify(createEventChange()));
|
||||
expect(callback).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('should call handler', () => {
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('with invalid JSON', async () => {
|
||||
const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
callHASubscribeMessageCallback(hass, 'NOT_JSON');
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
fireMessage(hass, 'NOT_JSON');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(spy).toBeCalledWith(
|
||||
@@ -183,18 +166,15 @@ describe('FrigateEventWatcher', () => {
|
||||
it('with malformed event', async () => {
|
||||
const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
const data = JSON.stringify({});
|
||||
callHASubscribeMessageCallback(hass, data);
|
||||
fireMessage(hass, data);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(spy).toBeCalledWith(
|
||||
@@ -204,71 +184,40 @@ describe('FrigateEventWatcher', () => {
|
||||
});
|
||||
|
||||
it('without a matcher', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
const eventChange = createEventChange();
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(eventChange));
|
||||
fireMessage(hass, JSON.stringify(eventChange));
|
||||
|
||||
expect(callback).toBeCalledWith(eventChange);
|
||||
});
|
||||
|
||||
it('with a non-matching instance_id', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
|
||||
const callback_1 = vi.fn();
|
||||
const request_1 = {
|
||||
instanceID: 'frigate_1',
|
||||
callback: callback_1,
|
||||
};
|
||||
|
||||
const callback_2 = vi.fn();
|
||||
const request_2 = {
|
||||
instanceID: 'frigate_2',
|
||||
callback: callback_2,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request_1);
|
||||
await stateWatcher.subscribe(hass, request_2);
|
||||
|
||||
const eventChange = createEventChange();
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(eventChange), 1);
|
||||
|
||||
expect(callback_1).not.toBeCalledWith(eventChange);
|
||||
expect(callback_2).toBeCalledWith(eventChange);
|
||||
});
|
||||
|
||||
it('with a matcher', async () => {
|
||||
const stateWatcher = new FrigateEventWatcher();
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateEventWatcher(source);
|
||||
|
||||
const matching_callback = vi.fn();
|
||||
const matching_request = {
|
||||
const non_matching_callback = vi.fn();
|
||||
watcher.subscribe({
|
||||
instanceID: 'frigate',
|
||||
callback: matching_callback,
|
||||
matcher: (event: FrigateEventChange) => event.after.camera === 'front_door',
|
||||
};
|
||||
|
||||
const non_matching_callback = vi.fn();
|
||||
const non_matching_request = {
|
||||
});
|
||||
watcher.subscribe({
|
||||
instanceID: 'frigate',
|
||||
callback: non_matching_callback,
|
||||
matcher: (event: FrigateEventChange) => event.after.camera === 'back_door',
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, matching_request);
|
||||
await stateWatcher.subscribe(hass, non_matching_request);
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
const eventChange = createEventChange();
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(eventChange));
|
||||
fireMessage(hass, JSON.stringify(eventChange));
|
||||
|
||||
expect(non_matching_callback).not.toBeCalledWith(eventChange);
|
||||
expect(matching_callback).toBeCalledWith(eventChange);
|
||||
@@ -276,20 +225,20 @@ describe('FrigateEventWatcher', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// @vitest-environment jsdom
|
||||
describe('FrigateReviewWatcher', () => {
|
||||
it('should subscribe to a given topic once', async () => {
|
||||
const stateWatcher = new FrigateReviewWatcher();
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should subscribe to the frigate reviews channel and dispatch review changes', async () => {
|
||||
const hass = createHASS();
|
||||
const { source } = createHASSSource(hass);
|
||||
const watcher = new FrigateReviewWatcher(source);
|
||||
|
||||
await stateWatcher.subscribe(hass, {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
});
|
||||
|
||||
await stateWatcher.subscribe(hass, {
|
||||
instanceID: 'frigate',
|
||||
callback: vi.fn(),
|
||||
});
|
||||
const callback = vi.fn();
|
||||
watcher.subscribe({ instanceID: 'frigate', callback });
|
||||
await flushPromises();
|
||||
|
||||
expect(hass.connection.subscribeMessage).toBeCalledWith(
|
||||
expect.any(Function),
|
||||
@@ -297,73 +246,10 @@ describe('FrigateReviewWatcher', () => {
|
||||
type: 'frigate/reviews/subscribe',
|
||||
}),
|
||||
);
|
||||
expect(hass.connection.subscribeMessage).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('should call handler', () => {
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
const reviewChange = createReviewChange();
|
||||
fireMessage(hass, JSON.stringify(reviewChange));
|
||||
|
||||
it('with a review change', async () => {
|
||||
const stateWatcher = new FrigateReviewWatcher();
|
||||
const hass = createHASS();
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
|
||||
const reviewChange = createReviewChange();
|
||||
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(reviewChange));
|
||||
|
||||
expect(callback).toBeCalledWith(reviewChange);
|
||||
});
|
||||
|
||||
it('with a genai review change', async () => {
|
||||
const stateWatcher = new FrigateReviewWatcher();
|
||||
const hass = createHASS();
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
|
||||
const reviewChange = createReviewChange();
|
||||
reviewChange.type = 'genai';
|
||||
|
||||
callHASubscribeMessageCallback(hass, JSON.stringify(reviewChange));
|
||||
|
||||
expect(callback).toBeCalledWith(reviewChange);
|
||||
});
|
||||
|
||||
it('with invalid JSON', async () => {
|
||||
const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true);
|
||||
|
||||
const stateWatcher = new FrigateReviewWatcher();
|
||||
const hass = createHASS();
|
||||
|
||||
const callback = vi.fn();
|
||||
const request = {
|
||||
instanceID: 'frigate',
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
await stateWatcher.subscribe(hass, request);
|
||||
callHASubscribeMessageCallback(hass, 'NOT_JSON');
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
expect(spy).toBeCalledWith(
|
||||
'Received non-JSON payload from subscription: frigate/reviews/subscribe',
|
||||
'NOT_JSON',
|
||||
);
|
||||
});
|
||||
expect(callback).toBeCalledWith(reviewChange);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { GenericCameraManagerEngine } from '../../../src/camera-manager/generic/engine-generic';
|
||||
import { Engine, QueryResultsType, QueryType } from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { CameraConfig } from '../../../src/config/schema/cameras';
|
||||
import { RawAdvancedCameraCardConfig } from '../../../src/config/types';
|
||||
import { QuerySource } from '../../../src/query-source';
|
||||
@@ -11,15 +8,13 @@ import {
|
||||
TestViewMedia,
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createStateEntity,
|
||||
createStore,
|
||||
} from '../../test-utils';
|
||||
|
||||
const createEngine = (): GenericCameraManagerEngine => {
|
||||
return new GenericCameraManagerEngine(
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
);
|
||||
return new GenericCameraManagerEngine(createHASSManager());
|
||||
};
|
||||
|
||||
const createGenericCameraConfig = (
|
||||
@@ -35,7 +30,7 @@ describe('GenericCameraManagerEngine', () => {
|
||||
|
||||
it('should initialize camera', async () => {
|
||||
const config = createGenericCameraConfig();
|
||||
const camera = await createEngine().createCamera(createHASS(), config);
|
||||
const camera = await createEngine().createCamera(config);
|
||||
|
||||
expect(camera.getConfig()).toEqual(config);
|
||||
expect(camera.getCapabilities()).toBeTruthy();
|
||||
@@ -50,7 +45,7 @@ describe('GenericCameraManagerEngine', () => {
|
||||
|
||||
it('should get default query parameters', async () => {
|
||||
const config = createGenericCameraConfig();
|
||||
const camera = await createEngine().createCamera(createHASS(), config);
|
||||
const camera = await createEngine().createCamera(config);
|
||||
expect(createEngine().getDefaultQueryParameters(camera, QueryType.Event)).toEqual(
|
||||
{},
|
||||
);
|
||||
@@ -375,16 +370,12 @@ describe('GenericCameraManagerEngine', () => {
|
||||
|
||||
describe('should get camera endpoints', () => {
|
||||
it('default', async () => {
|
||||
const camera = await createEngine().createCamera(
|
||||
createHASS(),
|
||||
createGenericCameraConfig(),
|
||||
);
|
||||
const camera = await createEngine().createCamera(createGenericCameraConfig());
|
||||
expect(camera.getEndpoints()).toBeNull();
|
||||
});
|
||||
|
||||
it('for go2rtc', async () => {
|
||||
const camera = await createEngine().createCamera(
|
||||
createHASS(),
|
||||
createGenericCameraConfig({
|
||||
go2rtc: {
|
||||
stream: 'stream',
|
||||
@@ -403,7 +394,6 @@ describe('GenericCameraManagerEngine', () => {
|
||||
|
||||
it('for webrtc-card', async () => {
|
||||
const camera = await createEngine().createCamera(
|
||||
createHASS(),
|
||||
createGenericCameraConfig({
|
||||
camera_entity: 'camera.office',
|
||||
}),
|
||||
|
||||
@@ -31,7 +31,6 @@ import { StateWatcherSubscriptionInterface } from '../../src/card-controller/has
|
||||
import { sortItems } from '../../src/card-controller/view/sort.js';
|
||||
import { CameraConfig } from '../../src/config/schema/cameras.js';
|
||||
import { advancedCameraCardConfigSchema } from '../../src/config/schema/types.js';
|
||||
import { HomeAssistant } from '../../src/ha/types.js';
|
||||
import { QuerySource } from '../../src/query-source.js';
|
||||
import { Endpoint, PTZMovementType } from '../../src/types.js';
|
||||
import { ViewFolder, ViewItem, ViewMedia } from '../../src/view/item.js';
|
||||
@@ -297,7 +296,7 @@ describe('CameraManager', () => {
|
||||
camera.engineType === undefined ? Engine.Generic : camera.engineType;
|
||||
if (engineType) {
|
||||
vi.mocked(mockEngine.createCamera).mockImplementationOnce(
|
||||
async (_hass: HomeAssistant, cameraConfig: CameraConfig): Promise<Camera> =>
|
||||
async (cameraConfig: CameraConfig): Promise<Camera> =>
|
||||
await createInitializedCamera(
|
||||
cameraConfig,
|
||||
mockEngine,
|
||||
|
||||
@@ -2,10 +2,12 @@ import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { MotionEyeCamera } from '../../../src/camera-manager/motioneye/camera';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import { createCameraConfig, createHASS, createRegistryEntity } from '../../test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
|
||||
const cameraEntity = createRegistryEntity({
|
||||
entity_id: 'camera.motioneye',
|
||||
@@ -47,10 +49,8 @@ describe('MotionEyeCamera', () => {
|
||||
});
|
||||
const camera = new MotionEyeCamera(config, mock<CameraManagerEngine>());
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
const endpoints = camera.getEndpoints();
|
||||
@@ -65,10 +65,8 @@ describe('MotionEyeCamera', () => {
|
||||
});
|
||||
const camera = new MotionEyeCamera(config, mock<CameraManagerEngine>());
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
const endpoints = camera.getEndpoints();
|
||||
@@ -83,10 +81,8 @@ describe('MotionEyeCamera', () => {
|
||||
});
|
||||
const camera = new MotionEyeCamera(config, mock<CameraManagerEngine>());
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
const capabilities = camera.getCapabilities();
|
||||
@@ -109,10 +105,8 @@ describe('MotionEyeCamera', () => {
|
||||
});
|
||||
const camera = new MotionEyeCamera(config, mock<CameraManagerEngine>());
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
const capabilities = camera.getCapabilities();
|
||||
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
QueryResultsType,
|
||||
QueryType,
|
||||
} from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { BrowseMediaMetadata } from '../../../src/ha/browse-media/types';
|
||||
import { BrowseMediaStep, BrowseMediaWalker } from '../../../src/ha/browse-media/walker';
|
||||
import { Entity } from '../../../src/ha/registry/entity/types';
|
||||
@@ -25,6 +23,7 @@ import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
createRichBrowseMedia,
|
||||
} from '../../test-utils';
|
||||
@@ -51,8 +50,7 @@ const createEngine = (options?: {
|
||||
}): MotionEyeCameraManagerEngine => {
|
||||
return new MotionEyeCameraManagerEngine(
|
||||
new EntityRegistryManagerMock(options?.entities ?? [createEntity()]),
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
createHASSManager(),
|
||||
options?.walker ?? new BrowseMediaWalker(),
|
||||
new ResolvedMediaCache(),
|
||||
options?.requestCache ?? new CameraManagerRequestCache(),
|
||||
@@ -73,10 +71,8 @@ const createMotionEyeStore = async (
|
||||
});
|
||||
const camera = new MotionEyeCamera(config, engine);
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([entity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
camera.setID(options?.cameraID ?? 'camera-1');
|
||||
const store = new CameraManagerStore();
|
||||
@@ -136,7 +132,7 @@ describe('MotionEyeCameraManagerEngine', () => {
|
||||
camera_entity: CAMERA_ENTITY_ID,
|
||||
});
|
||||
|
||||
const camera = await engine.createCamera(createHASS(), config);
|
||||
const camera = await engine.createCamera(config);
|
||||
|
||||
expect(camera).toBeInstanceOf(Camera);
|
||||
expect(camera).toBeInstanceOf(MotionEyeCamera);
|
||||
@@ -498,10 +494,8 @@ describe('MotionEyeCameraManagerEngine', () => {
|
||||
const engine = createEngine({ walker });
|
||||
const camera = new MotionEyeCamera(config, engine);
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([createEntity()]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
camera.setID('camera-1');
|
||||
const store = new CameraManagerStore();
|
||||
@@ -547,10 +541,8 @@ describe('MotionEyeCameraManagerEngine', () => {
|
||||
const engine = createEngine({ walker });
|
||||
const camera = new MotionEyeCamera(config, engine);
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([createEntity()]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
camera.setID('camera-1');
|
||||
const store = new CameraManagerStore();
|
||||
@@ -602,10 +594,8 @@ describe('MotionEyeCameraManagerEngine', () => {
|
||||
const engine = createEngine({ walker });
|
||||
const camera = new MotionEyeCamera(config, engine);
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([createEntity()]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
camera.setID('camera-1');
|
||||
const store = new CameraManagerStore();
|
||||
|
||||
@@ -4,14 +4,13 @@ import { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { ReolinkCamera } from '../../../src/camera-manager/reolink/camera';
|
||||
import { CameraProxyConfig } from '../../../src/camera-manager/types';
|
||||
import { ActionsExecutor } from '../../../src/card-controller/actions/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { DeviceRegistryManager } from '../../../src/ha/registry/device';
|
||||
import { EntityRegistryManagerLive } from '../../../src/ha/registry/entity';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
createStateEntity,
|
||||
} from '../../test-utils';
|
||||
@@ -103,11 +102,9 @@ describe('ReolinkCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: mock<EntityRegistryManagerLive>(),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
});
|
||||
@@ -128,11 +125,9 @@ describe('ReolinkCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not initialize Reolink camera');
|
||||
});
|
||||
@@ -153,11 +148,9 @@ describe('ReolinkCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not initialize Reolink camera');
|
||||
});
|
||||
@@ -170,11 +163,9 @@ describe('ReolinkCamera', () => {
|
||||
const entityRegistryManager = new EntityRegistryManagerMock([cameraEntity]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -203,11 +194,9 @@ describe('ReolinkCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(3);
|
||||
@@ -227,11 +216,9 @@ describe('ReolinkCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(7);
|
||||
@@ -251,11 +238,9 @@ describe('ReolinkCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -275,11 +260,9 @@ describe('ReolinkCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(7);
|
||||
@@ -301,11 +284,9 @@ describe('ReolinkCamera', () => {
|
||||
]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -334,11 +315,9 @@ describe('ReolinkCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -367,11 +346,9 @@ describe('ReolinkCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -400,11 +377,9 @@ describe('ReolinkCamera', () => {
|
||||
});
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
deviceRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getChannel()).toBe(0);
|
||||
@@ -420,11 +395,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -444,7 +417,7 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
createRegistryEntity({
|
||||
entity_id: 'camera.office_reolink',
|
||||
@@ -463,8 +436,6 @@ describe('ReolinkCamera', () => {
|
||||
}),
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -480,18 +451,18 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'select.office_reolink_ptz_preset': createStateEntity({
|
||||
state: 'foo',
|
||||
attributes: {
|
||||
options: ['preset-one', 'preset-two'],
|
||||
},
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'select.office_reolink_ptz_preset': createStateEntity({
|
||||
state: 'foo',
|
||||
attributes: {
|
||||
options: ['preset-one', 'preset-two'],
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -521,11 +492,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -709,11 +678,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -739,14 +706,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPTZLeft,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
@@ -770,11 +735,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -812,11 +775,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -832,18 +793,18 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS({
|
||||
'select.office_reolink_ptz_preset': createStateEntity({
|
||||
state: 'foo',
|
||||
attributes: {
|
||||
options: ['preset-one', 'preset-two'],
|
||||
},
|
||||
hassManager: createHASSManager({
|
||||
hass: createHASS({
|
||||
'select.office_reolink_ptz_preset': createStateEntity({
|
||||
state: 'foo',
|
||||
attributes: {
|
||||
options: ['preset-one', 'preset-two'],
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -871,11 +832,9 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -892,14 +851,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -915,7 +872,7 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
createRegistryEntity({
|
||||
@@ -926,8 +883,6 @@ describe('ReolinkCamera', () => {
|
||||
}),
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toBeNull();
|
||||
@@ -940,7 +895,7 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPTZZoomIn,
|
||||
@@ -949,8 +904,6 @@ describe('ReolinkCamera', () => {
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -966,14 +919,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1005,14 +956,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1044,14 +993,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1083,14 +1030,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1122,14 +1067,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1152,14 +1095,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1181,14 +1122,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1204,7 +1143,7 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPTZZoomIn,
|
||||
@@ -1213,8 +1152,6 @@ describe('ReolinkCamera', () => {
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1238,15 +1175,13 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPTZLeft,
|
||||
buttonEntityPTZStop,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -1262,14 +1197,12 @@ describe('ReolinkCamera', () => {
|
||||
const camera = new ReolinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
numberEntityZoom,
|
||||
]),
|
||||
deviceRegistryManager: mock<DeviceRegistryManager>(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ import {
|
||||
QueryReturnType,
|
||||
QueryType,
|
||||
} from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { BrowseMedia, browseMediaSchema } from '../../../src/ha/browse-media/types';
|
||||
import { BrowseMediaWalker } from '../../../src/ha/browse-media/walker';
|
||||
import { DeviceRegistryManager } from '../../../src/ha/registry/device';
|
||||
@@ -36,6 +34,7 @@ import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createInitializedCamera,
|
||||
createRegistryEntity,
|
||||
createStore,
|
||||
@@ -187,8 +186,7 @@ const createEngine = (options?: {
|
||||
return new ReolinkCameraManagerEngine(
|
||||
options?.entityRegistryManager ?? new EntityRegistryManagerMock(),
|
||||
mock<DeviceRegistryManager>(),
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
createHASSManager(),
|
||||
options?.browseMediaManager ?? new BrowseMediaWalker(),
|
||||
new ResolvedMediaCache(),
|
||||
new CameraManagerRequestCache(),
|
||||
@@ -212,7 +210,6 @@ const createStoreWithReolinkCamera = async (
|
||||
): Promise<CameraManagerStore> => {
|
||||
const store = new CameraManagerStore();
|
||||
const camera = await engine.createCamera(
|
||||
createHASS(),
|
||||
createCameraConfig({ camera_entity: 'camera.office', id: 'office' }),
|
||||
);
|
||||
store.addCamera(camera);
|
||||
@@ -252,7 +249,7 @@ describe('ReolinkCameraManagerEngine', () => {
|
||||
unique_id: 'office',
|
||||
});
|
||||
|
||||
const camera = await engine.createCamera(createHASS(), config);
|
||||
const camera = await engine.createCamera(config);
|
||||
|
||||
expect(camera.getConfig()).toBe(config);
|
||||
expect(camera.getEngine()).toBe(engine);
|
||||
@@ -289,7 +286,6 @@ describe('ReolinkCameraManagerEngine', () => {
|
||||
it('should return ui endpoint', async () => {
|
||||
const engine = createPopulatedEngine();
|
||||
const camera = await engine.createCamera(
|
||||
createHASS(),
|
||||
createCameraConfig({
|
||||
camera_entity: 'camera.office',
|
||||
reolink: {
|
||||
@@ -308,7 +304,6 @@ describe('ReolinkCameraManagerEngine', () => {
|
||||
it('should return go2rtc endpoint', async () => {
|
||||
const engine = createPopulatedEngine();
|
||||
const camera = await engine.createCamera(
|
||||
createHASS(),
|
||||
createCameraConfig({
|
||||
camera_entity: 'camera.office',
|
||||
go2rtc: {
|
||||
@@ -497,7 +492,6 @@ describe('ReolinkCameraManagerEngine', () => {
|
||||
it('should request high resolution if configured', async () => {
|
||||
const engine = createPopulatedEngine();
|
||||
const camera = await engine.createCamera(
|
||||
createHASS(),
|
||||
createCameraConfig({
|
||||
camera_entity: 'camera.office',
|
||||
id: 'office',
|
||||
|
||||
@@ -5,14 +5,13 @@ import { Capabilities } from '../../src/camera-manager/capabilities.js';
|
||||
import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js';
|
||||
import { CameraManagerStore } from '../../src/camera-manager/store.js';
|
||||
import { Engine } from '../../src/camera-manager/types.js';
|
||||
import { EventWatcherSubscriptionInterface } from '../../src/card-controller/hass/event-watcher.js';
|
||||
import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
import { DeviceRegistryManager } from '../../src/ha/registry/device/index.js';
|
||||
import { EntityRegistryManager } from '../../src/ha/registry/entity/types.js';
|
||||
import { ResolvedMediaCache } from '../../src/ha/resolved-media.js';
|
||||
import {
|
||||
TestViewMedia,
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createInitializedCamera,
|
||||
} from '../test-utils.js';
|
||||
|
||||
@@ -31,13 +30,11 @@ describe('CameraManagerStore', async () => {
|
||||
);
|
||||
|
||||
const engineGeneric = await engineFactory.createEngine(Engine.Generic, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
});
|
||||
const engineFrigate = await engineFactory.createEngine(Engine.Frigate, {
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
hassManager: createHASSManager(),
|
||||
resolvedMediaCache: mock<ResolvedMediaCache>(),
|
||||
});
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ import { mock } from 'vitest-mock-extended';
|
||||
import { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { TPLinkCamera } from '../../../src/camera-manager/tplink/camera';
|
||||
import { ActionsExecutor } from '../../../src/card-controller/actions/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import { createCameraConfig, createHASS, createRegistryEntity } from '../../test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
|
||||
describe('TPLinkCamera', () => {
|
||||
// Entity patterns from: https://github.com/dermotduffy/advanced-camera-card/issues/2183
|
||||
@@ -77,10 +79,8 @@ describe('TPLinkCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
});
|
||||
@@ -94,10 +94,8 @@ describe('TPLinkCamera', () => {
|
||||
expect(
|
||||
async () =>
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock(),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
}),
|
||||
).rejects.toThrowError('Could not find camera entity');
|
||||
});
|
||||
@@ -113,10 +111,8 @@ describe('TPLinkCamera', () => {
|
||||
const entityRegistryManager = new EntityRegistryManagerMock([cameraEntity]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getEntity()).toBe(cameraEntity);
|
||||
@@ -131,10 +127,8 @@ describe('TPLinkCamera', () => {
|
||||
const entityRegistryManager = new EntityRegistryManagerMock([cameraEntity]);
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getEntity()).toBe(cameraEntity);
|
||||
@@ -149,10 +143,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -179,10 +171,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({
|
||||
@@ -203,10 +193,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([cameraEntity]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -225,10 +213,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -249,10 +235,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -270,10 +254,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -299,10 +281,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -328,10 +308,8 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: ptzPopulatedEntityRegistryManager,
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
@@ -365,13 +343,11 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPanLeft,
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
await camera.executePTZAction(executor, 'left', { phase: 'start' });
|
||||
@@ -404,13 +380,11 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraWithDifferentUniqueId,
|
||||
buttonEntityPanLeft,
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
// Should not find PTZ entities since unique_id doesn't end with _live_view
|
||||
@@ -430,13 +404,11 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraWithoutUniqueId,
|
||||
buttonEntityPanLeft,
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
|
||||
// Should not find PTZ entities since camera has no unique_id
|
||||
@@ -453,13 +425,11 @@ describe('TPLinkCamera', () => {
|
||||
const camera = new TPLinkCamera(config, mock<CameraManagerEngine>());
|
||||
|
||||
await camera.initialize({
|
||||
hass: createHASS(),
|
||||
hassManager: createHASSManager(),
|
||||
entityRegistryManager: new EntityRegistryManagerMock([
|
||||
cameraEntity,
|
||||
buttonEntityPanLeft, // Only left button available
|
||||
]),
|
||||
stateWatcher: mock<StateWatcherSubscriptionInterface>(),
|
||||
eventWatcher: mock<EventWatcherSubscriptionInterface>(),
|
||||
});
|
||||
const executor = mock<ActionsExecutor>();
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { TPLinkCameraManagerEngine } from '../../../src/camera-manager/tplink/engine-tplink';
|
||||
import { Engine } from '../../../src/camera-manager/types';
|
||||
import { EventWatcherSubscriptionInterface } from '../../../src/card-controller/hass/event-watcher';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { EntityRegistryManagerMock } from '../../ha/registry/entity/mock';
|
||||
import { createCameraConfig, createHASS, createRegistryEntity } from '../../test-utils';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createHASS,
|
||||
createHASSManager,
|
||||
createRegistryEntity,
|
||||
} from '../../test-utils';
|
||||
|
||||
const createEngine = (options?: {
|
||||
entityRegistryManager?: EntityRegistryManagerMock;
|
||||
}): TPLinkCameraManagerEngine => {
|
||||
return new TPLinkCameraManagerEngine(
|
||||
options?.entityRegistryManager ?? new EntityRegistryManagerMock(),
|
||||
mock<StateWatcherSubscriptionInterface>(),
|
||||
mock<EventWatcherSubscriptionInterface>(),
|
||||
createHASSManager(),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -42,7 +43,7 @@ describe('TPLinkCameraManagerEngine', () => {
|
||||
id: 'tapo_office',
|
||||
});
|
||||
|
||||
const camera = await engine.createCamera(createHASS(), config);
|
||||
const camera = await engine.createCamera(config);
|
||||
|
||||
expect(camera.getConfig()).toBe(config);
|
||||
expect(camera.getEngine()).toBe(engine);
|
||||
|
||||
Reference in New Issue
Block a user