diff --git a/src/card.ts b/src/card.ts index d0dec3a9..4b1efcd3 100644 --- a/src/card.ts +++ b/src/card.ts @@ -403,13 +403,8 @@ export class FrigateCard extends LitElement { protected async _loadCameras(): Promise { const cameras: Map = new Map(); - const addCameraConfig = async (id: string, config: CameraConfig) => { - if (!config.camera_name && (config.camera_entity || id.startsWith('camera.'))) { - if (!config.camera_entity) { - // If the camera_entity isn't explicitly set and the id looks like - // one, use that. - config.camera_entity = id; - } + const addCameraConfig = async (config: CameraConfig) => { + if (!config.camera_name && config.camera_entity) { const resolvedName = await this._getFrigateCameraNameFromEntity( config.camera_entity, ); @@ -417,17 +412,26 @@ export class FrigateCard extends LitElement { config.camera_name = resolvedName; } } - if (!config.camera_name) { - config.camera_name = id; + + if (config.camera_name) { + const id = config.card_id || config.camera_entity || config.camera_name; + if (cameras.has(id)) { + this._setMessageAndUpdate( + { + message: localize('error.duplicate_frigate_camera_name'), + type: 'error', + }, + true, + ); + } else { + cameras.set(id, config); + } } - cameras.set(id, config); }; - await Promise.all( - Object.keys(this.config.cameras).map((key) => - addCameraConfig(key, this.config.cameras[key]), - ), - ); + if (this.config.camera && Array.isArray(this.config.camera)) { + await Promise.all(this.config.camera.map(addCameraConfig.bind(this))); + } if (!cameras.size) { return this._setMessageAndUpdate( diff --git a/src/common.ts b/src/common.ts index fb69a3c9..81127e73 100644 --- a/src/common.ts +++ b/src/common.ts @@ -287,8 +287,7 @@ export function convertActionToFrigateCardCustomAction( */ export function createFrigateCardCustomAction( action: FrigateCardAction, - camera?: string, -): FrigateCardCustomAction | undefined { + camera?: string): FrigateCardCustomAction | undefined { if (action == 'camera_select') { if (!camera) { return undefined; @@ -297,12 +296,12 @@ export function createFrigateCardCustomAction( action: 'fire-dom-event', frigate_card_action: action, camera: camera, - }; + } } return { action: 'fire-dom-event', frigate_card_action: action, - }; + } } /** diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 84c65829..e598d2e7 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -154,6 +154,7 @@ "upgrade_available": "An automated card configuration upgrade is available, please visit the visual card editor", "missing_webrtc": "WebRTC component not found", "no_cameras": "No cameras found, you must configure at least one camera configured with a camera_entity or camera_name", + "duplicate_frigate_camera_name": "Duplicate Frigate camera name, use the 'id' parameter to uniquely identify them", "could_not_render_elements": "Could not render picture elements", "invalid_elements_config": "Invalid picture elements configuration", "jsmpeg_no_sign": "Could not retrieve or sign JSMPEG websocket path", diff --git a/src/types.ts b/src/types.ts index 3834ccb1..98501ec0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -368,12 +368,12 @@ const cameraConfigDefaultSchema = z // specified). icon: z.string().optional(), title: z.string().optional(), + + card_id: z.string().optional(), }) .default(cameraConfigDefault); export type CameraConfig = z.infer; -const camerasConfigDefaultSchema = z.record(cameraConfigDefaultSchema); - /** * View configuration section. */ @@ -650,7 +650,7 @@ const dimensionsConfigSchema = z */ export const frigateCardConfigSchema = z.object({ // Main configuration sections. - cameras: camerasConfigDefaultSchema, + camera: cameraConfigDefaultSchema.array().nonempty(), view: viewConfigSchema, menu: menuConfigSchema, live: liveConfigSchema,