diff --git a/packages/client/package-lock.json b/packages/client/package-lock.json index 3b7a7db706..6fda01695b 100644 --- a/packages/client/package-lock.json +++ b/packages/client/package-lock.json @@ -9,7 +9,7 @@ "version": "1.3.6", "license": "ISC", "dependencies": { - "@scrypted/types": "^0.3.59", + "@scrypted/types": "^0.3.60", "engine.io-client": "^6.6.1", "follow-redirects": "^1.15.9", "rimraf": "^6.0.1" @@ -75,9 +75,9 @@ } }, "node_modules/@scrypted/types": { - "version": "0.3.59", - "resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.59.tgz", - "integrity": "sha512-eX8HKYD/r47FbYHuAOzBOjtDFhqiw3DAkyanb1M+8RHNDk8kum3KPYerYafMUKg88sIybw+UeYSrdBq5D6m2+g==" + "version": "0.3.60", + "resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.3.60.tgz", + "integrity": "sha512-oapFYQvyHLp0odCSx//USNnGNegS9ZL6a1HFIZzjDdMj2MNszTqiucAcu/wAlBwqjgURlP4/8xeLGVHEa4S2uQ==" }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", diff --git a/packages/client/package.json b/packages/client/package.json index 814fb4ac26..f28893f066 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -18,7 +18,7 @@ "typescript": "^5.6.2" }, "dependencies": { - "@scrypted/types": "^0.3.59", + "@scrypted/types": "^0.3.60", "engine.io-client": "^6.6.1", "follow-redirects": "^1.15.9", "rimraf": "^6.0.1" diff --git a/plugins/onvif/package-lock.json b/plugins/onvif/package-lock.json index 4a3b2bb907..419fdd36cb 100644 --- a/plugins/onvif/package-lock.json +++ b/plugins/onvif/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/onvif", - "version": "0.1.27", + "version": "0.1.28", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@scrypted/onvif", - "version": "0.1.27", + "version": "0.1.28", "license": "Apache", "dependencies": { "@scrypted/common": "file:../../common", diff --git a/plugins/onvif/package.json b/plugins/onvif/package.json index 6c884ecd32..60bc9d2439 100644 --- a/plugins/onvif/package.json +++ b/plugins/onvif/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/onvif", - "version": "0.1.27", + "version": "0.1.28", "description": "ONVIF Camera Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/onvif/src/onvif-ptz.ts b/plugins/onvif/src/onvif-ptz.ts index af11b20a72..1b168235c4 100644 --- a/plugins/onvif/src/onvif-ptz.ts +++ b/plugins/onvif/src/onvif-ptz.ts @@ -20,6 +20,7 @@ export class OnvifPtzMixin extends SettingsMixinDeviceBase implements ], onPut: (ov, ptz: string[]) => { this.ptzCapabilities = { + ...this.ptzCapabilities, pan: ptz.includes('Pan'), tilt: ptz.includes('Tilt'), zoom: ptz.includes('Zoom'), @@ -38,6 +39,34 @@ export class OnvifPtzMixin extends SettingsMixinDeviceBase implements ], defaultValue: 'Default', }, + presets: { + title: 'Presets', + description: 'PTZ Presets in the format "key=name". Where key is the PTZ Preset identifier and name is a friendly name.', + multiple: true, + defaultValue: [], + combobox: true, + onPut: async (ov, presets: string[]) => { + const caps = { + ...this.ptzCapabilities, + presets: {}, + }; + for (const preset of presets) { + const [key, name] = preset.split('='); + caps.presets[key] = name; + } + this.ptzCapabilities = caps; + }, + mapGet: () => { + const presets = this.ptzCapabilities?.presets || {}; + return Object.entries(presets).map(([key, name]) => key + '=' + name); + }, + }, + cachedPresets: { + multiple: true, + hide: true, + json: true, + defaultValue: {}, + }, }); constructor(options: SettingsMixinDeviceOptions) { @@ -45,6 +74,30 @@ export class OnvifPtzMixin extends SettingsMixinDeviceBase implements // force a read to set the state. this.storageSettings.values.ptz; + + this.refreshPresets(); + + this.storageSettings.settings.presets.onGet = async () => { + // getPresets is where the key is the name of the preset, and the value is the id. + // kind of weird and backwards. + const choices = Object.entries(this.storageSettings.values.cachedPresets).map(([name, key]) => key + '=' + name); + return { + choices, + }; + }; + } + + async refreshPresets() { + const client = await this.getClient(); + client.cam.getPresets({}, (e, result, xml) => { + if (e) { + this.console.error('failed to get presets', e); + } + else { + this.console.log('presets', result); + this.storageSettings.values.cachedPresets = result; + } + }); } getMixinSettings(): Promise { @@ -83,7 +136,7 @@ export class OnvifPtzMixin extends SettingsMixinDeviceBase implements }) } else if (movement === PanTiltZoomMovement.Continuous) { - let x= command.pan; + let x = command.pan; let y = command.tilt; let zoom = command.zoom; if (command.speed?.pan) diff --git a/sdk/package-lock.json b/sdk/package-lock.json index db1fdd55ba..3dc8a27361 100644 --- a/sdk/package-lock.json +++ b/sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/sdk", - "version": "0.3.63", + "version": "0.3.65", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/sdk", - "version": "0.3.63", + "version": "0.3.65", "license": "ISC", "dependencies": { "@babel/preset-typescript": "^7.24.7", diff --git a/sdk/package.json b/sdk/package.json index 501f11b65a..4c472b8c81 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/sdk", - "version": "0.3.63", + "version": "0.3.65", "description": "", "main": "dist/src/index.js", "exports": { diff --git a/sdk/types/package-lock.json b/sdk/types/package-lock.json index 38aecca6e5..f458ca55d5 100644 --- a/sdk/types/package-lock.json +++ b/sdk/types/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/types", - "version": "0.3.59", + "version": "0.3.60", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/types", - "version": "0.3.59", + "version": "0.3.60", "license": "ISC", "devDependencies": { "@types/node": "^22.1.0", diff --git a/sdk/types/package.json b/sdk/types/package.json index aebd4e2d55..4f5043059e 100644 --- a/sdk/types/package.json +++ b/sdk/types/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/types", - "version": "0.3.59", + "version": "0.3.60", "description": "", "main": "dist/index.js", "author": "", diff --git a/sdk/types/scrypted_python/scrypted_sdk/types.py b/sdk/types/scrypted_python/scrypted_sdk/types.py index 180242daed..613535f67d 100644 --- a/sdk/types/scrypted_python/scrypted_sdk/types.py +++ b/sdk/types/scrypted_python/scrypted_sdk/types.py @@ -706,6 +706,7 @@ class ObjectsDetected(TypedDict): class PanTiltZoomCapabilities(TypedDict): pan: bool + presets: Any # Preset id mapped to friendly name. tilt: bool zoom: bool diff --git a/sdk/types/src/types.input.ts b/sdk/types/src/types.input.ts index 760ec2e738..afb7c97575 100644 --- a/sdk/types/src/types.input.ts +++ b/sdk/types/src/types.input.ts @@ -1003,6 +1003,12 @@ export interface PanTiltZoomCapabilities { pan?: boolean; tilt?: boolean; zoom?: boolean; + /** + * Preset id mapped to friendly name. + */ + presets?: { + [key: string]: string; + }; } export interface PanTiltZoom { ptzCapabilities?: PanTiltZoomCapabilities;