Skip to content

Pan/Tilt/Zoom Button

This script creates a button that can move to a preset position on a PTZ camera. This button can then be synced to platforms like HomeKit, which do not natively support PTZ commands.

ts
class PTZButton extends ScryptedDeviceBase implements OnOff, Settings {
    timeout: any;
    storageSettings = new StorageSettings(this, {
        ptzCamera: {
            immediate: true,
            title: 'PTZ Camera',
            type: 'device',
            deviceFilter: `interfaces.includes("${ScryptedInterface.PanTiltZoom}")`,
        },
        preset: {
            title: 'Preset',
        },
    })

    constructor(nativeId: string) {
        super(nativeId);
        // make this device a switch so it can be synced.
        setTimeout(() => {
            systemManager.getDeviceById(this.id).setType(ScryptedDeviceType.Switch);
        });

        this.storageSettings.settings.preset.onGet = async () => {
            const ptzCamera: ScryptedDevice & PanTiltZoom = this.storageSettings.values.ptzCamera;
            const choices = Object.values(ptzCamera?.ptzCapabilities?.presets || {});
            return {
                choices,
            }
        };
    }

    async turnOn() {
        this.on = true;
        clearTimeout(this.timeout);
        // reset the switch after a second so you can press it again!
        this.timeout = setTimeout(() => this.on = false, 1000);

        const ptzCamera: ScryptedDevice & PanTiltZoom = this.storageSettings.values.ptzCamera;
        const found = Object.entries(ptzCamera.ptzCapabilities?.presets || {}).find(([k, v]) => v === this.storageSettings.values.preset);

        await ptzCamera.ptzCommand({
            movement: PanTiltZoomMovement.Preset,
            preset: found[0],
        });
    }

    async turnOff() {
        this.on = false;
    }

    async getSettings(): Promise<Setting[]> {
        return this.storageSettings.getSettings();
    }

    async putSetting(key: string, value: SettingValue) {
        return this.storageSettings.putSetting(key, value);
    }
}

export default PTZButton;