import { HASSManagerReadonlyInterface } from '../card-controller/hass/types'; import { CameraConfig } from '../config/schema/cameras'; import { BrowseMediaWalker } from '../ha/browse-media/walker'; import { DeviceRegistryManager } from '../ha/registry/device'; import { EntityRegistryManager } from '../ha/registry/entity/types'; import { ResolvedMediaCache } from '../ha/resolved-media'; import { HomeAssistant } from '../ha/types'; import { RecordingSegmentsCache } from './cache'; import { CameraManagerEngine } from './engine'; import { CameraNoEntityError } from './error'; import { CameraEventCallback, CameraManagerRequestCache, Engine } from './types'; import { getCameraEntityFromConfig } from './utils/camera-entity-from-config'; interface CameraManagerEngineFactoryOptions { hassManager: HASSManagerReadonlyInterface; resolvedMediaCache: ResolvedMediaCache; eventCallback?: CameraEventCallback; } export class CameraManagerEngineFactory { private _entityRegistryManager: EntityRegistryManager; private _deviceRegistryManager: DeviceRegistryManager; constructor( entityRegistryManager: EntityRegistryManager, deviceRegistryManager: DeviceRegistryManager, ) { this._entityRegistryManager = entityRegistryManager; this._deviceRegistryManager = deviceRegistryManager; } public async createEngine( engine: Engine, options: CameraManagerEngineFactoryOptions, ): Promise { let cameraManagerEngine: CameraManagerEngine; switch (engine) { case Engine.Generic: const { GenericCameraManagerEngine } = await import('./generic/engine-generic'); cameraManagerEngine = new GenericCameraManagerEngine( options.hassManager, this._entityRegistryManager, options.eventCallback, ); break; case Engine.Frigate: const { FrigateCameraManagerEngine } = await import('./frigate/engine-frigate'); cameraManagerEngine = new FrigateCameraManagerEngine( this._entityRegistryManager, options.hassManager, new RecordingSegmentsCache(), new CameraManagerRequestCache(), options.eventCallback, ); break; case Engine.MotionEye: const { MotionEyeCameraManagerEngine } = await import( './motioneye/engine-motioneye' ); cameraManagerEngine = new MotionEyeCameraManagerEngine( this._entityRegistryManager, options.hassManager, new BrowseMediaWalker(), options.resolvedMediaCache, new CameraManagerRequestCache(), options.eventCallback, ); break; case Engine.Reolink: const { ReolinkCameraManagerEngine } = await import('./reolink/engine-reolink'); cameraManagerEngine = new ReolinkCameraManagerEngine( this._entityRegistryManager, this._deviceRegistryManager, options.hassManager, new BrowseMediaWalker(), options.resolvedMediaCache, new CameraManagerRequestCache(), options.eventCallback, ); break; case Engine.TPLink: const { TPLinkCameraManagerEngine } = await import('./tplink/engine-tplink'); cameraManagerEngine = new TPLinkCameraManagerEngine( this._entityRegistryManager, options.hassManager, options.eventCallback, ); break; } return cameraManagerEngine; } public async getEngineForCamera( hass: HomeAssistant, cameraConfig: CameraConfig, ): Promise { let engine: Engine | null = null; if (cameraConfig.engine === 'frigate') { engine = Engine.Frigate; } else if (cameraConfig.engine === 'motioneye') { engine = Engine.MotionEye; } else if (cameraConfig.engine === 'generic') { engine = Engine.Generic; } else if (cameraConfig.engine === 'reolink') { engine = Engine.Reolink; } else if (cameraConfig.engine === 'tplink') { engine = Engine.TPLink; } else { const cameraEntity = getCameraEntityFromConfig(cameraConfig); if (cameraEntity) { const entity = await this._entityRegistryManager.getEntity(hass, cameraEntity); if (!entity) { // If the camera is not in the registry, but is in the HA states it is // assumed to be a generic camera. if (hass.states[cameraEntity]) { return Engine.Generic; } // Otherwise, it's probably a typo so throw an exception. throw new CameraNoEntityError(cameraConfig); } switch (entity?.platform) { case 'frigate': engine = Engine.Frigate; break; case 'motioneye': engine = Engine.MotionEye; break; case 'reolink': engine = Engine.Reolink; break; case 'tplink': engine = Engine.TPLink; break; default: engine = Engine.Generic; } } else if (cameraConfig.frigate.camera_name) { // Frigate technically does not need an entity, if the camera name is // manually set the camera is assumed to be Frigate. engine = Engine.Frigate; } else if ( cameraConfig.webrtc_card?.url || (cameraConfig.go2rtc?.url && cameraConfig.go2rtc?.stream) ) { engine = Engine.Generic; } } return engine; } }