fix: PTZ actions should reflect camera rotation (#2258)

- Closes: #2210
This commit is contained in:
Dermot Duffy
2025-12-07 21:12:12 -08:00
committed by GitHub
parent 596a37903f
commit c38bf192e0
6 changed files with 172 additions and 9 deletions
+35 -3
View File
@@ -3,8 +3,13 @@ import { cloneDeep, sum } from 'lodash-es';
import PQueue from 'p-queue';
import { CardCameraAPI } from '../card-controller/types.js';
import { sortItems } from '../card-controller/view/sort.js';
import { PTZAction, PTZActionPhase } from '../config/schema/actions/custom/ptz.js';
import { CameraConfig, CamerasConfig } from '../config/schema/cameras.js';
import {
PTZ_PAN_TILT_ACTIONS,
PTZAction,
PTZActionPhase,
PTZPanTiltAction,
} from '../config/schema/actions/custom/ptz.js';
import { CameraConfig, CamerasConfig, Rotation } from '../config/schema/cameras.js';
import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const.js';
import { localize } from '../localize/localize.js';
import { Endpoint } from '../types.js';
@@ -788,6 +793,29 @@ export class CameraManager {
});
}
/**
* Rotate a PTZ action based on camera rotation setting.
* When camera view is rotated, PTZ controls should logically rotate too.
* For example: with 90° rotation, pressing "left" should send "down" to camera.
*/
private _rotatePTZAction(action: PTZAction, rotation?: Rotation): PTZAction {
if (!rotation) {
return action;
}
// Pan/tilt directions in clockwise order for rotation calculation
const index = PTZ_PAN_TILT_ACTIONS.indexOf(action as PTZPanTiltAction);
if (index === -1) {
// Not a directional action (e.g., zoom_in, zoom_out, preset)
return action;
}
// Each 90° rotation shifts the direction index counter-clockwise.
const shift = (4 - rotation / 90) % 4;
return PTZ_PAN_TILT_ACTIONS[(index + shift) % 4];
}
public async executePTZAction(
cameraID: string,
action: PTZAction,
@@ -800,8 +828,12 @@ export class CameraManager {
if (!camera) {
return;
}
const rotatedAction = this._rotatePTZAction(
action,
camera.getConfig().dimensions?.rotation,
);
await this._requestLimit.add(() =>
camera.executePTZAction(this._api.getActionsManager(), action, options),
camera.executePTZAction(this._api.getActionsManager(), rotatedAction, options),
);
}
}
+3 -1
View File
@@ -1,7 +1,9 @@
import { z } from 'zod';
import { advancedCameraCardCustomActionsBaseSchema } from './base';
const PTZ_PAN_TILT_ACTIONS = ['left', 'right', 'up', 'down'] as const;
export const PTZ_PAN_TILT_ACTIONS = ['up', 'right', 'down', 'left'] as const;
export type PTZPanTiltAction = (typeof PTZ_PAN_TILT_ACTIONS)[number];
const PTZ_ZOOM_ACTIONS = ['zoom_in', 'zoom_out'] as const;
const PTZ_BASE_ACTIONS = [...PTZ_PAN_TILT_ACTIONS, ...PTZ_ZOOM_ACTIONS] as const;
export type PTZBaseAction = (typeof PTZ_BASE_ACTIONS)[number];