Merge pull request #1293 from dermotduffy/engine-detection
Improve engine identification and id generation
This commit is contained in:
@@ -96,6 +96,11 @@ export class CameraManagerEngineFactory {
|
|||||||
// Frigate technically does not need an entity, if the camera name is
|
// Frigate technically does not need an entity, if the camera name is
|
||||||
// manually set the camera is assumed to be Frigate.
|
// manually set the camera is assumed to be Frigate.
|
||||||
engine = Engine.Frigate;
|
engine = Engine.Frigate;
|
||||||
|
} else if (
|
||||||
|
cameraConfig.webrtc_card?.url ||
|
||||||
|
(cameraConfig.go2rtc?.url && cameraConfig.go2rtc?.stream)
|
||||||
|
) {
|
||||||
|
engine = Engine.Generic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
RecordingSegmentsQuery,
|
RecordingSegmentsQuery,
|
||||||
RecordingSegmentsQueryResultsMap,
|
RecordingSegmentsQueryResultsMap,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { getDefaultGo2RTCEndpoint } from '../utils.js';
|
import { getCameraEntityFromConfig, getDefaultGo2RTCEndpoint } from '../utils.js';
|
||||||
|
|
||||||
export class GenericCameraManagerEngine implements CameraManagerEngine {
|
export class GenericCameraManagerEngine implements CameraManagerEngine {
|
||||||
public getEngineType(): Engine {
|
public getEngineType(): Engine {
|
||||||
@@ -159,6 +159,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
cameraConfig: CameraConfig,
|
cameraConfig: CameraConfig,
|
||||||
): CameraManagerCameraMetadata {
|
): CameraManagerCameraMetadata {
|
||||||
|
const cameraEntity = getCameraEntityFromConfig(cameraConfig);
|
||||||
return {
|
return {
|
||||||
title:
|
title:
|
||||||
cameraConfig.title ??
|
cameraConfig.title ??
|
||||||
@@ -166,7 +167,9 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
|
|||||||
getEntityTitle(hass, cameraConfig.webrtc_card?.entity) ??
|
getEntityTitle(hass, cameraConfig.webrtc_card?.entity) ??
|
||||||
cameraConfig.id ??
|
cameraConfig.id ??
|
||||||
'',
|
'',
|
||||||
icon: cameraConfig?.icon ?? getEntityIcon(hass, cameraConfig.camera_entity),
|
icon:
|
||||||
|
cameraConfig?.icon ??
|
||||||
|
(cameraEntity ? getEntityIcon(hass, cameraEntity, 'mdi:video') : 'mdi:video'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,9 @@ export class CameraManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always ensure the actual ID used in the card is in the configuration itself.
|
||||||
|
result.initializedConfig.id = id;
|
||||||
|
|
||||||
this._store.addCamera(id, result.initializedConfig, result.engine);
|
this._store.addCamera(id, result.initializedConfig, result.engine);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export class MenuButtonController {
|
|||||||
const action = createFrigateCardCustomAction('camera_select', {
|
const action = createFrigateCardCustomAction('camera_select', {
|
||||||
camera: cameraID,
|
camera: cameraID,
|
||||||
});
|
});
|
||||||
const metadata = cameraManager.getCameraMetadata(cameraID) ?? undefined;
|
const metadata = cameraManager.getCameraMetadata(cameraID);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
+9
-2
@@ -14,8 +14,15 @@ export function getCameraID(
|
|||||||
(typeof config?.camera_entity === 'string' && config.camera_entity) ||
|
(typeof config?.camera_entity === 'string' && config.camera_entity) ||
|
||||||
(typeof config?.webrtc_card === 'object' &&
|
(typeof config?.webrtc_card === 'object' &&
|
||||||
config.webrtc_card &&
|
config.webrtc_card &&
|
||||||
typeof config.webrtc_card['entity'] === 'string' &&
|
((typeof config.webrtc_card['entity'] === 'string' &&
|
||||||
config.webrtc_card['entity']) ||
|
config.webrtc_card['entity']) ||
|
||||||
|
(typeof config.webrtc_card['url'] === 'string' && config.webrtc_card['url']))) ||
|
||||||
|
(typeof config?.go2rtc === 'object' &&
|
||||||
|
config.go2rtc &&
|
||||||
|
typeof config.go2rtc['url'] === 'string' &&
|
||||||
|
typeof config.go2rtc['stream'] === 'string' &&
|
||||||
|
// Artifical identifier that includes both url / stream.
|
||||||
|
`${config.go2rtc['url']}#${config.go2rtc['stream']}`) ||
|
||||||
(typeof config?.frigate === 'object' &&
|
(typeof config?.frigate === 'object' &&
|
||||||
config.frigate &&
|
config.frigate &&
|
||||||
typeof config?.frigate['camera_name'] === 'string' &&
|
typeof config?.frigate['camera_name'] === 'string' &&
|
||||||
|
|||||||
+19
-6
@@ -1,4 +1,4 @@
|
|||||||
import { computeStateDomain, HomeAssistant } from 'custom-card-helpers';
|
import { computeDomain, computeStateDomain, HomeAssistant } from 'custom-card-helpers';
|
||||||
import { HassEntity, MessageBase } from 'home-assistant-js-websocket';
|
import { HassEntity, MessageBase } from 'home-assistant-js-websocket';
|
||||||
import { StyleInfo } from 'lit/directives/style-map.js';
|
import { StyleInfo } from 'lit/directives/style-map.js';
|
||||||
import { ZodSchema } from 'zod';
|
import { ZodSchema } from 'zod';
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
signedPathSchema,
|
signedPathSchema,
|
||||||
StateParameters,
|
StateParameters,
|
||||||
} from '../../types.js';
|
} from '../../types.js';
|
||||||
import { stateIcon } from '../icons/state-icon.js';
|
import { domainIcon } from '../icons/domain-icon.js';
|
||||||
import { getParseErrorKeys } from '../zod.js';
|
import { getParseErrorKeys } from '../zod.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -234,7 +234,7 @@ export function refreshDynamicStateParameters(
|
|||||||
params.style = { ...computeStyle(state), ...params.style };
|
params.style = { ...computeStyle(state), ...params.style };
|
||||||
}
|
}
|
||||||
params.title = params.title ?? (state?.attributes?.friendly_name || params.entity);
|
params.title = params.title ?? (state?.attributes?.friendly_name || params.entity);
|
||||||
params.icon = params.icon ?? stateIcon(state);
|
params.icon = params.icon ?? getEntityIcon(hass, params.entity);
|
||||||
|
|
||||||
const domain = state ? computeStateDomain(state) : undefined;
|
const domain = state ? computeStateDomain(state) : undefined;
|
||||||
params.data_domain =
|
params.data_domain =
|
||||||
@@ -262,12 +262,25 @@ export function getEntityTitle(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the icon of an entity.
|
* Get the icon of an entity.
|
||||||
* @param entity The entity id.
|
* @param entityID The entity id.
|
||||||
* @param hass The Home Assistant object.
|
* @param hass The Home Assistant object.
|
||||||
* @returns The icon or undefined.
|
* @returns The icon or undefined.
|
||||||
*/
|
*/
|
||||||
export function getEntityIcon(hass?: HomeAssistant, entity?: string): string {
|
export function getEntityIcon(
|
||||||
return stateIcon(entity ? hass?.states[entity] : null);
|
hass: HomeAssistant,
|
||||||
|
entityID: string,
|
||||||
|
defaultIcon?: string,
|
||||||
|
): string {
|
||||||
|
const entityState = hass.states[entityID];
|
||||||
|
if (entityState && entityState.attributes.icon) {
|
||||||
|
return entityState.attributes.icon;
|
||||||
|
}
|
||||||
|
return domainIcon(
|
||||||
|
computeDomain(entityID),
|
||||||
|
entityState,
|
||||||
|
entityState?.state,
|
||||||
|
defaultIcon,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const FIXED_DOMAIN_ICONS = {
|
|||||||
zone: 'mdi:map-marker-radius',
|
zone: 'mdi:map-marker-radius',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function domainIcon(domain: string, entity?: HassEntity, state?: string): string {
|
export function domainIcon(domain: string, entity?: HassEntity, state?: string, defaultIcon?: string): string {
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
case 'alarm_control_panel':
|
case 'alarm_control_panel':
|
||||||
return alarmPanelIcon(state);
|
return alarmPanelIcon(state);
|
||||||
@@ -195,6 +195,5 @@ export function domainIcon(domain: string, entity?: HassEntity, state?: string):
|
|||||||
return FIXED_DOMAIN_ICONS[domain];
|
return FIXED_DOMAIN_ICONS[domain];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn(`Unable to find icon for domain: ${domain}`);
|
return defaultIcon ?? DEFAULT_DOMAIN_ICON;
|
||||||
return DEFAULT_DOMAIN_ICON;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import { computeDomain } from 'custom-card-helpers';
|
|
||||||
import { HassEntity } from 'home-assistant-js-websocket';
|
|
||||||
import { DEFAULT_DOMAIN_ICON, domainIcon } from './domain-icon';
|
|
||||||
|
|
||||||
export function stateIcon(entity?: HassEntity | null): string {
|
|
||||||
if (!entity) {
|
|
||||||
return DEFAULT_DOMAIN_ICON;
|
|
||||||
}
|
|
||||||
if (entity.attributes.icon) {
|
|
||||||
return entity.attributes.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
const domain = computeDomain(entity.entity_id);
|
|
||||||
|
|
||||||
const state = entity.state;
|
|
||||||
|
|
||||||
return domainIcon(domain, entity, state);
|
|
||||||
}
|
|
||||||
@@ -29,81 +29,137 @@ const createFactory = (options?: {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('CameraManagerEngineFactory.getEngineForCamera()', () => {
|
describe('getEngineForCamera()', () => {
|
||||||
it('should get frigate engine from config', async () => {
|
describe('should get a frigate camera', () => {
|
||||||
const config = createCameraConfig({ engine: 'frigate' });
|
it('from manually set engine', async () => {
|
||||||
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
const config = createCameraConfig({ engine: 'frigate' });
|
||||||
Engine.Frigate,
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
);
|
Engine.Frigate,
|
||||||
});
|
);
|
||||||
it('should get motionEye engine from config', async () => {
|
});
|
||||||
const config = createCameraConfig({ engine: 'motioneye' });
|
|
||||||
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
|
||||||
Engine.MotionEye,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('should get generic engine from config', async () => {
|
|
||||||
const config = createCameraConfig({ engine: 'generic' });
|
|
||||||
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
|
||||||
Engine.Generic,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('should get frigate engine from auto config', async () => {
|
|
||||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
|
||||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
|
||||||
|
|
||||||
entityRegistryManager.getEntity = vi
|
it('from auto detection', async () => {
|
||||||
.fn()
|
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||||
.mockResolvedValue(
|
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||||
createRegistryEntity({ entity_id: 'camera.foo', platform: 'frigate' }),
|
|
||||||
|
entityRegistryManager.getEntity = vi
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(
|
||||||
|
createRegistryEntity({ entity_id: 'camera.foo', platform: 'frigate' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await createFactory({
|
||||||
|
entityRegistryManager: entityRegistryManager,
|
||||||
|
}).getEngineForCamera(createHASS(), config),
|
||||||
|
).toBe(Engine.Frigate);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from config with camera_name', async () => {
|
||||||
|
const config = createCameraConfig({
|
||||||
|
frigate: { client_id: 'bar', camera_name: 'foo' },
|
||||||
|
});
|
||||||
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
|
Engine.Frigate,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
|
||||||
await createFactory({
|
|
||||||
entityRegistryManager: entityRegistryManager,
|
|
||||||
}).getEngineForCamera(createHASS(), config),
|
|
||||||
).toBe(Engine.Frigate);
|
|
||||||
});
|
|
||||||
it('should get motioneye engine from auto config', async () => {
|
|
||||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
|
||||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
|
||||||
|
|
||||||
entityRegistryManager.getEntity = vi
|
|
||||||
.fn()
|
|
||||||
.mockResolvedValue(
|
|
||||||
createRegistryEntity({ entity_id: 'camera.foo', platform: 'motioneye' }),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await createFactory({
|
|
||||||
entityRegistryManager: entityRegistryManager,
|
|
||||||
}).getEngineForCamera(createHASS(), config),
|
|
||||||
).toBe(Engine.MotionEye);
|
|
||||||
});
|
|
||||||
it('should get generic engine from auto config', async () => {
|
|
||||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
|
||||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
|
||||||
|
|
||||||
entityRegistryManager.getEntity = vi
|
|
||||||
.fn()
|
|
||||||
.mockResolvedValue(
|
|
||||||
createRegistryEntity({ entity_id: 'camera.foo', platform: 'generic' }),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await createFactory({
|
|
||||||
entityRegistryManager: entityRegistryManager,
|
|
||||||
}).getEngineForCamera(createHASS(), config),
|
|
||||||
).toBe(Engine.Generic);
|
|
||||||
});
|
|
||||||
it('should get frigate engine from config with camera_name', async () => {
|
|
||||||
const config = createCameraConfig({
|
|
||||||
frigate: { client_id: 'bar', camera_name: 'foo' },
|
|
||||||
});
|
});
|
||||||
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
|
||||||
Engine.Frigate,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('should get a motionEye camera', () => {
|
||||||
|
it('from manually set engine', async () => {
|
||||||
|
const config = createCameraConfig({ engine: 'motioneye' });
|
||||||
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
|
Engine.MotionEye,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from auto detection', async () => {
|
||||||
|
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||||
|
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||||
|
|
||||||
|
entityRegistryManager.getEntity = vi
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(
|
||||||
|
createRegistryEntity({ entity_id: 'camera.foo', platform: 'motioneye' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await createFactory({
|
||||||
|
entityRegistryManager: entityRegistryManager,
|
||||||
|
}).getEngineForCamera(createHASS(), config),
|
||||||
|
).toBe(Engine.MotionEye);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('should get a generic camera', () => {
|
||||||
|
it('from manually set engine', async () => {
|
||||||
|
const config = createCameraConfig({ engine: 'generic' });
|
||||||
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
|
Engine.Generic,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from auto detection', async () => {
|
||||||
|
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||||
|
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||||
|
|
||||||
|
entityRegistryManager.getEntity = vi
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(
|
||||||
|
createRegistryEntity({ entity_id: 'camera.foo', platform: 'generic' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await createFactory({
|
||||||
|
entityRegistryManager: entityRegistryManager,
|
||||||
|
}).getEngineForCamera(createHASS(), config),
|
||||||
|
).toBe(Engine.Generic);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from entity not in registry but with state', async () => {
|
||||||
|
const config = createCameraConfig({
|
||||||
|
engine: 'auto',
|
||||||
|
webrtc_card: { entity: 'camera.foo' },
|
||||||
|
});
|
||||||
|
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||||
|
|
||||||
|
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await createFactory({
|
||||||
|
entityRegistryManager: entityRegistryManager,
|
||||||
|
}).getEngineForCamera(
|
||||||
|
createHASS({
|
||||||
|
'camera.foo': createStateEntity(),
|
||||||
|
}),
|
||||||
|
config,
|
||||||
|
),
|
||||||
|
).toBe(Engine.Generic);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from webrtc-card url', async () => {
|
||||||
|
const config = createCameraConfig({
|
||||||
|
engine: 'auto',
|
||||||
|
webrtc_card: { url: 'camera.foo' },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
|
Engine.Generic,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('from go2rtc url and stream', async () => {
|
||||||
|
const config = createCameraConfig({
|
||||||
|
engine: 'auto',
|
||||||
|
go2rtc: { url: 'https://my-go2rtc', stream: 'office' },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBe(
|
||||||
|
Engine.Generic,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should get no engine from config with insufficient details', async () => {
|
it('should get no engine from config with insufficient details', async () => {
|
||||||
const config = createCameraConfig({});
|
const config = createCameraConfig({});
|
||||||
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBeNull();
|
expect(await createFactory().getEngineForCamera(createHASS(), config)).toBeNull();
|
||||||
@@ -115,38 +171,6 @@ describe('CameraManagerEngineFactory.getEngineForCamera()', () => {
|
|||||||
|
|
||||||
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
||||||
|
|
||||||
await expect(
|
|
||||||
createFactory({
|
|
||||||
entityRegistryManager: entityRegistryManager,
|
|
||||||
}).getEngineForCamera(createHASS(), config),
|
|
||||||
).rejects.toThrow();
|
|
||||||
});
|
|
||||||
it('should treat entity not in registry but with state as generic', async () => {
|
|
||||||
const config = createCameraConfig({
|
|
||||||
engine: 'auto',
|
|
||||||
webrtc_card: { entity: 'camera.foo' },
|
|
||||||
});
|
|
||||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
|
||||||
|
|
||||||
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await createFactory({
|
|
||||||
entityRegistryManager: entityRegistryManager,
|
|
||||||
}).getEngineForCamera(
|
|
||||||
createHASS({
|
|
||||||
'camera.foo': createStateEntity(),
|
|
||||||
}),
|
|
||||||
config,
|
|
||||||
),
|
|
||||||
).toBe(Engine.Generic);
|
|
||||||
});
|
|
||||||
it('should get engine from webrtc-card configuration', async () => {
|
|
||||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
|
||||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
|
||||||
|
|
||||||
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
createFactory({
|
createFactory({
|
||||||
entityRegistryManager: entityRegistryManager,
|
entityRegistryManager: entityRegistryManager,
|
||||||
@@ -155,7 +179,7 @@ describe('CameraManagerEngineFactory.getEngineForCamera()', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('CameraManagerEngineFactory.createEngine()', () => {
|
describe('createEngine()', () => {
|
||||||
it('should create generic engine', async () => {
|
it('should create generic engine', async () => {
|
||||||
expect(await createFactory().createEngine(Engine.Generic)).toBeInstanceOf(
|
expect(await createFactory().createEngine(Engine.Generic)).toBeInstanceOf(
|
||||||
GenericCameraManagerEngine,
|
GenericCameraManagerEngine,
|
||||||
|
|||||||
@@ -192,11 +192,23 @@ describe('GenericCameraManagerEngine', () => {
|
|||||||
expect(
|
expect(
|
||||||
createEngine().getCameraMetadata(createHASS(), createGenericCameraConfig()),
|
createEngine().getCameraMetadata(createHASS(), createGenericCameraConfig()),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
icon: 'mdi:bookmark',
|
icon: 'mdi:video',
|
||||||
title: '',
|
title: '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with id', async () => {
|
||||||
|
expect(
|
||||||
|
createEngine().getCameraMetadata(
|
||||||
|
createHASS(),
|
||||||
|
createGenericCameraConfig({ id: 'https://go2rtc#stream' }),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
icon: 'mdi:video',
|
||||||
|
title: 'https://go2rtc#stream',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('with configured title', async () => {
|
it('with configured title', async () => {
|
||||||
expect(
|
expect(
|
||||||
createEngine().getCameraMetadata(
|
createEngine().getCameraMetadata(
|
||||||
@@ -206,7 +218,7 @@ describe('GenericCameraManagerEngine', () => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
icon: 'mdi:bookmark',
|
icon: 'mdi:video',
|
||||||
title: 'My Camera',
|
title: 'My Camera',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -225,7 +237,7 @@ describe('GenericCameraManagerEngine', () => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
icon: 'mdi:bookmark',
|
icon: 'mdi:video',
|
||||||
title: 'My Entity Camera',
|
title: 'My Entity Camera',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -245,7 +257,7 @@ describe('GenericCameraManagerEngine', () => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
icon: 'mdi:bookmark',
|
icon: 'mdi:video',
|
||||||
title: 'My Entity Camera',
|
title: 'My Entity Camera',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ describe('getCameraID', () => {
|
|||||||
const config = createCameraConfig({ webrtc_card: { entity: 'foo' } });
|
const config = createCameraConfig({ webrtc_card: { entity: 'foo' } });
|
||||||
expect(getCameraID(config)).toBe('foo');
|
expect(getCameraID(config)).toBe('foo');
|
||||||
});
|
});
|
||||||
|
it('should get camera id with webrtc url', () => {
|
||||||
|
const config = createCameraConfig({ webrtc_card: { url: 'foo' } });
|
||||||
|
expect(getCameraID(config)).toBe('foo');
|
||||||
|
});
|
||||||
|
it('should get camera id with go2rtc url and stream', () => {
|
||||||
|
const config = createCameraConfig({ go2rtc: { url: 'https://foo', stream: 'office' } });
|
||||||
|
expect(getCameraID(config)).toBe('https://foo#office');
|
||||||
|
});
|
||||||
it('should get camera id with frigate camera_name', () => {
|
it('should get camera id with frigate camera_name', () => {
|
||||||
const config = createCameraConfig({
|
const config = createCameraConfig({
|
||||||
frigate: { client_id: 'bar', camera_name: 'foo' },
|
frigate: { client_id: 'bar', camera_name: 'foo' },
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { HomeAssistant } from 'custom-card-helpers';
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { hasHAConnectionStateChanged } from '../../../src/utils/ha/index.js';
|
import {
|
||||||
import { createHASS } from '../../test-utils.js';
|
getEntityIcon,
|
||||||
|
hasHAConnectionStateChanged,
|
||||||
|
} from '../../../src/utils/ha/index.js';
|
||||||
|
import { createHASS, createStateEntity } from '../../test-utils.js';
|
||||||
|
|
||||||
const createConnected = (connected: boolean): HomeAssistant => {
|
const createConnected = (connected: boolean): HomeAssistant => {
|
||||||
const hass = createHASS();
|
const hass = createHASS();
|
||||||
@@ -43,3 +46,24 @@ describe('hasHAConnectionStateChanged', () => {
|
|||||||
expect(hasHAConnectionStateChanged(null, null)).toBeFalsy();
|
expect(hasHAConnectionStateChanged(null, null)).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getEntityIcon', () => {
|
||||||
|
it('should get icon from attributes', () => {
|
||||||
|
expect(
|
||||||
|
getEntityIcon(
|
||||||
|
createHASS({
|
||||||
|
'camera.test': createStateEntity({
|
||||||
|
attributes: {
|
||||||
|
icon: 'mdi:cow',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
'camera.test',
|
||||||
|
),
|
||||||
|
).toBe('mdi:cow');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get icon from domain', () => {
|
||||||
|
expect(getEntityIcon(createHASS(), 'camera.test')).toBe('mdi:video');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user