165 lines
5.1 KiB
TypeScript
165 lines
5.1 KiB
TypeScript
import { CameraManager } from '../../camera-manager/manager.js';
|
|
import { dispatchActionExecutionRequest } from '../../card-controller/actions/utils/execution-request.js';
|
|
import { SubmenuInteraction } from '../../components/submenu/types.js';
|
|
import { PTZAction } from '../../config/schema/actions/custom/ptz.js';
|
|
import { Actions, ActionsConfig } from '../../config/schema/actions/types.js';
|
|
import { PTZControlsConfig } from '../../config/schema/common/controls/ptz.js';
|
|
import { HomeAssistant } from '../../ha/types.js';
|
|
import { Interaction } from '../../types.js';
|
|
import { createPTZMultiAction, getActionConfigGivenAction } from '../../utils/action.js';
|
|
import { PTZControllerActions } from './types';
|
|
|
|
export class PTZController {
|
|
private _host: HTMLElement;
|
|
|
|
private _config: PTZControlsConfig | null = null;
|
|
private _hass: HomeAssistant | null = null;
|
|
private _cameraManager: CameraManager | null = null;
|
|
private _cameraID: string | null = null;
|
|
|
|
private _forceVisibility?: boolean;
|
|
|
|
constructor(host: HTMLElement) {
|
|
this._host = host;
|
|
}
|
|
|
|
public setConfig(config?: PTZControlsConfig) {
|
|
this._config = config ?? null;
|
|
|
|
this._host.setAttribute('data-orientation', config?.orientation ?? 'horizontal');
|
|
this._host.setAttribute('data-position', config?.position ?? 'bottom-right');
|
|
this._host.setAttribute(
|
|
'style',
|
|
Object.entries(config?.style ?? {})
|
|
.map(([k, v]) => `${k}:${v}`)
|
|
.join(';'),
|
|
);
|
|
}
|
|
|
|
public getConfig(): PTZControlsConfig | null {
|
|
return this._config;
|
|
}
|
|
|
|
public setCamera(cameraManager?: CameraManager, cameraID?: string): void {
|
|
this._cameraManager = cameraManager ?? null;
|
|
this._cameraID = cameraID ?? null;
|
|
}
|
|
|
|
public setForceVisibility(forceVisibility?: boolean): void {
|
|
this._forceVisibility = forceVisibility;
|
|
}
|
|
|
|
public handleAction(
|
|
ev: CustomEvent<Interaction & Partial<SubmenuInteraction>>,
|
|
buttonConfig?: ActionsConfig | null,
|
|
): void {
|
|
const config: ActionsConfig | null = buttonConfig ?? ev.detail.item ?? null;
|
|
|
|
// Nothing else has the configuration for this action, so don't let it
|
|
// propagate further.
|
|
ev.stopPropagation();
|
|
|
|
const interaction: string = ev.detail.action;
|
|
const action = getActionConfigGivenAction(interaction, config);
|
|
if (action) {
|
|
dispatchActionExecutionRequest(this._host, {
|
|
actions: action,
|
|
...(config && { config: config }),
|
|
});
|
|
}
|
|
}
|
|
|
|
public shouldDisplay(): boolean {
|
|
return this._forceVisibility !== undefined
|
|
? this._forceVisibility
|
|
: this._config?.mode === 'auto'
|
|
? !!this._cameraID &&
|
|
!!this._cameraManager
|
|
?.getCameraCapabilities(this._cameraID)
|
|
?.hasPTZCapability()
|
|
: this._config?.mode === 'on';
|
|
}
|
|
|
|
public getPTZActions(): PTZControllerActions {
|
|
const cameraCapabilities = this._cameraID
|
|
? this._cameraManager?.getCameraCapabilities(this._cameraID)
|
|
: null;
|
|
const hasRealPTZCapability =
|
|
cameraCapabilities && cameraCapabilities.hasPTZCapability();
|
|
const ptzCapabilities = cameraCapabilities?.getPTZCapabilities();
|
|
|
|
const getContinuousActions = (options?: {
|
|
ptzAction?: PTZAction;
|
|
preset?: string;
|
|
}): Actions => ({
|
|
start_tap_action: createPTZMultiAction({
|
|
ptzAction: options?.ptzAction,
|
|
ptzPhase: 'start',
|
|
ptzPreset: options?.preset,
|
|
}),
|
|
end_tap_action: createPTZMultiAction({
|
|
ptzAction: options?.ptzAction,
|
|
ptzPhase: 'stop',
|
|
ptzPreset: options?.preset,
|
|
}),
|
|
});
|
|
|
|
const getDiscreteAction = (options?: {
|
|
ptzAction?: PTZAction;
|
|
preset?: string;
|
|
}): Actions => ({
|
|
tap_action: createPTZMultiAction({
|
|
ptzAction: options?.ptzAction,
|
|
ptzPreset: options?.preset,
|
|
}),
|
|
});
|
|
|
|
const actions: PTZControllerActions = {};
|
|
if (!hasRealPTZCapability || ptzCapabilities?.up) {
|
|
actions.up = getContinuousActions({
|
|
ptzAction: 'up',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.down) {
|
|
actions.down = getContinuousActions({
|
|
ptzAction: 'down',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.left) {
|
|
actions.left = getContinuousActions({
|
|
ptzAction: 'left',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.right) {
|
|
actions.right = getContinuousActions({
|
|
ptzAction: 'right',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.zoomIn) {
|
|
actions.zoom_in = getContinuousActions({
|
|
ptzAction: 'zoom_in',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.zoomOut) {
|
|
actions.zoom_out = getContinuousActions({
|
|
ptzAction: 'zoom_out',
|
|
});
|
|
}
|
|
if (!hasRealPTZCapability || ptzCapabilities?.presets?.length) {
|
|
actions.home = getDiscreteAction();
|
|
}
|
|
for (const preset of ptzCapabilities?.presets ?? []) {
|
|
actions.presets ??= [];
|
|
actions.presets.push({
|
|
preset: preset,
|
|
actions: getDiscreteAction({
|
|
preset: preset,
|
|
ptzAction: 'preset',
|
|
}),
|
|
});
|
|
}
|
|
|
|
return actions;
|
|
}
|
|
}
|