/* Copyright(C) 2019-2026, HJD (https://github.com/hjdhjd). All rights reserved. * * camera.ts: The UniFi Protect camera configuration types, including the camera-specific PTZ axis range and channel, LCD-message, recording-path, and talkback shapes. */ import type { DeepPartial, Nullable, ProtectKnownJsonValue } from "./common.ts"; import type { ProtectDeviceBaseInterface } from "./base.ts"; import type { ProtectSmartZoneInterface } from "./shapes.ts"; /** * The UniFi Protect camera configuration types: the camera record itself and the camera-scoped value-shapes it composes - the PTZ axis range (a camera mechanism), the * per-channel stream config, the LCD message, the recording-path settings, and the talkback settings. * * @module ProtectTypesCamera */ /** * A description of a PTZ axis range for UniFi Protect camera feature flags. */ export interface ProtectPtzAxisRangeInterface { degrees: { max: Nullable; min: Nullable; step: Nullable; }; steps: { max: Nullable; min: Nullable; step: Nullable; }; [key: string]: ProtectKnownJsonValue; } /** * A semi-complete description of the UniFi Protect camera JSON. */ export interface ProtectCameraConfigInterface extends ProtectDeviceBaseInterface { accessDeviceMetadata?: { channels: { bitrate: number; fps: number; fpsValues: number[]; height: number; id: number; localStreamName: string; quality: string; width: number; }[]; connectedSince: number; disableRecordingByDefault: boolean; doorInfo: { canLock: boolean; lockState: string; }; featureFlags: { supportLivestream: boolean; supportMicManagement: boolean; supportUnlock: boolean; }; ledSettings: { isEnabled: boolean; }; micVolume: number; pairedInfo: { guid: Nullable; name: string; uri: string; }; speakerSettings: { areSystemSoundsEnabled: boolean; }; // The Access integration's talkback channels (an array under accessDeviceMetadata), distinct from the camera's own single top-level `talkbackSettings` object below. talkbackSettings: ProtectCameraTalkbackConfigInterface[]; }; accessMethodSettings: { methods: string[]; }; activePatrolSlot: Nullable; aiPortCapacityPoints: number; aiPortCompatibleResolutions: string[]; aiPortCompatibleResolutionsInHallway: string[]; alarms: { autoTrackingThermalThresholdReached: boolean; lensThermal: number; lensThermalThresholdReached: boolean; motorOverheated: boolean; panTiltMotorFaults: string[]; tiltThermal: number; }; apMac: string; apMgmtIp: Nullable; apRssi: Nullable; audioBitrate: number; audioSettings: { style: string[]; }; autoRetentionLqMs: Nullable; autoRetentionMs: Nullable; brightnessSettings: { autoBrightness: boolean; brightness: number; }; canCreateAccessEvent: boolean; canManage: boolean; channels: ProtectCameraChannelConfigInterface[]; chimeDuration: number; clarityZones: ProtectKnownJsonValue[]; currentResolution: string; doorbellSession: { sessionId: Nullable; status: Nullable; }; downScaleMode: number; elementInfo: Nullable; enableNfc: boolean; excludeZones: ProtectKnownJsonValue[]; extendedAiFeatures: { smartDetectTypes: string[]; }; faceUnlockSettings: { faceDetectionSensitive: string; lastUpdateTime: number; licenseConfigured: boolean; }; featureFlags: { audio: string[]; audioCodecs: string[]; audioStyle: string[]; canAdjustIrLedLevel: boolean; canAdjustIspSettings: boolean; canAdjustSpeakerVolume: boolean; canMagicZoom: boolean; canOpticalZoom: boolean; canTouchFocus: boolean; clarityZones: Nullable<{ maxZones: number; rectangleOnly: boolean; }>; downScaleResolutions: number[][]; excludeZones: { maxZones: number; rectangleOnly: boolean; }; flashRange: Nullable; focus: ProtectPtzAxisRangeInterface; hallwayModeWarningRequired: boolean; hasAccelerometer: boolean; hasAec: boolean; hasAutoICROnly: boolean; hasBluetooth: boolean; hasChime: boolean; hasColorLcdScreen: boolean; hasEdgeRecording: boolean; hasExternalIr: boolean; hasFingerprintSensor: boolean; hasFisheye: boolean; hasFlash: boolean; hasHallwayMode: boolean; hasHallwayModeHdrOnRequired: boolean; hasHdr: boolean; hasHorizontalFlip: boolean; hasIcrSensitivity: boolean; hasInfrared: boolean; hasLcdScreen: boolean; hasLdc: boolean; hasLedIr: boolean; hasLedStatus: boolean; hasLineCrossing: boolean; hasLineCrossingCounting: boolean; hasLineIn: boolean; hasLiveviewTracking: boolean; hasLprReflex: boolean; hasLuxCheck: boolean; hasManualPersonOfInterest: boolean; hasMic: boolean; hasMotionZones: boolean; hasOptimizeIr: boolean; hasPackageCamera: boolean; hasPackageZoneSupportForPrimaryLens: boolean; hasPackageZoneSupportForSecondaryLens: boolean; hasPrivacyMask: boolean; hasRtc: boolean; hasSdCard: boolean; hasSmartDetect: boolean; hasSmartZoom: boolean; hasSmokeCover: boolean; hasSpeaker: boolean; hasSquareEventThumbnail: boolean; hasTamperDetection: boolean; hasVerticalFlip: boolean; hasWdr: boolean; hasWifi: boolean; hotplug: { audio: Nullable; extender: { flashRange: Nullable; hasFlash: boolean; hasIR: boolean; hasRadar: boolean; isAttached: boolean; radarRangeMax: Nullable; radarRangeMin: Nullable; }; sdCardAttached: boolean; standaloneAdoption: boolean; video: Nullable; }; isDoorbell: boolean; isPtz: boolean; lensModel: Nullable; lensType: Nullable; maxScaleDownLevel: number; motionAlgorithms: string[]; mountPositions: string[]; pan: ProtectPtzAxisRangeInterface; presetMinDuration: Nullable; presetTour: boolean; privacyMaskCapability: { maxMasks: number; rectangleOnly: boolean; }; reader: { canAdjustBrightness: boolean; support2fa: boolean; supportAccessMethods: string[]; supportAdjustSpeakerVolume: boolean; supportAudioCodecs: string[]; supportAutoBrightness: boolean; supportAutoTurnOffDisplay: boolean; supportCallerManager: boolean; supportDoorDirection: boolean; supportDoorbellTriggerMethod: boolean; supportFloodLed: boolean; supportGateStop: boolean; supportGreetings: boolean; supportInterfaceDesigner: boolean; supportInterfaceDirectory: boolean; supportInterfaceLayout: boolean; supportLocate: boolean; supportManualDownloadSupportFile: boolean; supportManualFirmwareUpdate: boolean; supportMic: boolean; supportShowHeading: boolean; supportShowInterfaceImage: boolean; supportShowStatusBar: boolean; supportShowUnlockSchedule: boolean; supportSpeaker: boolean; supportSsh: boolean; supportStatusLed: boolean; supportStreamEncryption: boolean; supportTwilioSip: boolean; supportWelcomeLed: boolean; }; smartDetectAudioTypes: string[]; smartDetectTypes: string[]; stitchDistance: { support: boolean; }; storage: { sdSlotCount: number; ssdSlotCount: number; }; streamEncryptable: boolean; supportCustomRingtone: boolean; supportDoorAccessConfig: boolean; supportFullHdSnapshot: boolean; supportLocate: boolean; supportLpDetectionWithoutVehicle: boolean; supportMinMotionAdaptiveBitrate: boolean; supportNfc: boolean; supportPtzTrackingTimeout: boolean; tilt: ProtectPtzAxisRangeInterface; verticalFlipWarning: boolean; videoCodecs: string[]; videoDeviceCount: Nullable; videoInputModes: string[]; videoModeMaxFps: number[]; videoModes: string[]; zoom: ProtectPtzAxisRangeInterface & { ratio: number }; }; fingerprintSettings: { enable: boolean; enablePrintLatency: boolean; mode: string; reportCaptureComplete: boolean; reportFingerTouch: boolean; }; fingerprintState: { fingerprintId: string; free: number; progress: string; status: string; total: number; }; greetingSettings: { greetingBroadcastName: string; greetingText: string; }; hallwayMode: string; hasPackageCamera: boolean; hasRecordingStarted: boolean; hasRecordings: boolean; hasSpeaker: boolean; hasWifi: boolean; hdrMode: boolean; hdrType: string; homekitAccessoryId: Nullable; homekitSettings: { doorbellMuted: Nullable; microphoneMuted: boolean; recordingActive: boolean; speakerMuted: boolean; streamInProgress: boolean; talkbackSettingsActive: boolean; }; host: string; hqBytesPerDay: number; hubMac: string; interfaceSettings: { bgImageId: Nullable; callMethod: string; heading: Nullable; layout: string; logoImageId: Nullable; showLogo: boolean; showTime: boolean; showWeather: boolean; subHeading: Nullable; }; is2K: boolean; is4K: boolean; isAccessDevice: boolean; isAccessFloodlightTriggerEnabled: boolean; isAdoptedByAccessApp: boolean; isConnected: boolean; isDark: boolean; isDeleting: boolean; isExtenderInstalledEver: boolean; isIntercom: boolean; isLiveHeatmapEnabled: boolean; isManaged: boolean; isMicEnabled: boolean; isMissingRecordingDetected: boolean; isMotionDetected: boolean; isPairedWithAiPort: boolean; isPoorNetwork: boolean; isProbingForWifi: boolean; isReaderPro: boolean; isRecording: boolean; isRecordingsPaused: boolean; isRecordingsPausedChangedAt: Nullable; isSmartDetected: boolean; isThirdPartyCamera: boolean; isWaterproofCaseAttached: boolean; isWirelessUplinkEnabled: boolean; ispSettings: { aeMode: string; brightness: number; contrast: number; dZoomCenterX: number; dZoomCenterY: number; dZoomScale: number; dZoomStreamId: number; denoise: number; focusMode: string; focusPosition: number; hdrMode: string; hue: number; icrCustomValue: number; icrSensitivity: number; icrSwitchMode: string; irLedLevel: number; irLedMode: string; is3dnrEnabled: boolean; isAggressiveAntiFlickerEnabled: boolean; isAutoRotateEnabled: boolean; isColorNightVisionEnabled: boolean; isExternalIrEnabled: boolean; isFlippedHorizontal: boolean; isFlippedVertical: boolean; isLdcEnabled: boolean; isPauseMotionEnabled: boolean; isSmokeCoverModeEnabled: boolean; mountPosition: string; saturation: number; sceneMode: string; sharpness: number; spotlightDuration: number; touchFocusX: number; touchFocusY: number; wdr: number; zoomPosition: number; }; lastMotion: number; lastRing: Nullable; lcdMessage?: DeepPartial; ledSettings: { floodLed: boolean; isEnabled: boolean; welcomeLed: boolean; }; lenses: { id: number; video: { recordingEnd: Nullable; recordingEndLQ: Nullable; recordingStart: Nullable; recordingStartLQ: Nullable; timelapseEnd: Nullable; timelapseEndLQ: Nullable; timelapseStart: Nullable; timelapseStartLQ: Nullable; }; }[]; // Inferred `string[]` element type from the field name; `null` on all current cameras. lowMemoryDisabledProcesses: Nullable; lqBytesPerDay: number; micVolume: number; modelKey: "camera"; motionZones: ProtectSmartZoneInterface[]; needUpdateBeforeAdoption: boolean; nfcSettings: { enableNfc: boolean; supportThirdPartyCard: boolean; }; nfcState: { cardId: string; isUACard: boolean; lastSeen: number; mode: string; }; optimizeIrSettings: { irZones: ProtectKnownJsonValue[]; mode: string; }; osdSettings: { isDateEnabled: boolean; isDebugEnabled: boolean; isLogoEnabled: boolean; isNameEnabled: boolean; overlayLocation: string; }; parentCameraGroupId: Nullable; phyRate: number; pinCodeSettings: { pinCodeLengthRange: string; pinCodeShuffle: boolean; }; privacyZones: ProtectKnownJsonValue[]; ptz: { pauseAutoTrackingUntilTs: Nullable; recentAutoHomeReturnAt: Nullable; recentMoveAutoTrackResumeAtTs: Nullable; returnHomeAfterInactivityMs: Nullable; }; ptzControlEnabled: boolean; readerSettings: { allowThirdPartyNfcCards: boolean; doorEntryMethod: string; doorId: Nullable; doorName: Nullable; language: string; screenOffTimeout: string; unlockDuration: number; }; receiverGroups: ProtectKnownJsonValue[]; recordingPath: Nullable; recordingPathFailedAt: Nullable; recordingPathSettings: ProtectCameraRecordingPathSettingsInterface; recordingSchedulesV2: ProtectKnownJsonValue[]; recordingSettings: { accessEventPostPaddingSecs: number; accessEventPrePaddingSecs: number; createAccessEvent: boolean; enableMotionDetection: boolean; endMotionEventDelay: number; geofencing: string; inScheduleMode: string; minMotionEventTrigger: number; mode: string; motionAlgorithm: string; outScheduleMode: string; postPaddingSecs: number; prePaddingSecs: number; recordAudio: boolean; recordVideo: boolean; retentionDurationLQMs: Nullable; retentionDurationMs: Nullable; smartDetectPostPaddingSecs: number; smartDetectPrePaddingSecs: number; suppressIlluminationSurge: boolean; useNewMotionAlgorithm: boolean; }; recordingsPausedReason: Nullable; rtspClient: Nullable; secondLensSmartDetectZones: ProtectKnownJsonValue[]; shortcuts: ProtectKnownJsonValue[]; skipCameraUpdateDecalListener: boolean; smartDetectLines: ProtectKnownJsonValue[]; smartDetectLoiterZones: (ProtectSmartZoneInterface & { loiterTriggers: { loiterTriggerTime: number; objectType: string }[]; triggerAccessTypes: string[] })[]; smartDetectSettings: { audioTypes: string[]; autoTrackingObjectTypes: string[]; autoTrackingTimeoutSec: number; autoTrackingWithZoom: boolean; detectionRange: { max: Nullable; min: Nullable }; enableTamperDetection: boolean; objectTypes: string[]; }; smartDetectZones: (ProtectSmartZoneInterface & { objectTypes: string[] })[]; speakerSettings: { areSystemSoundsEnabled: boolean; isEnabled: boolean; repeatTimes: number; ringtoneId: Nullable; ringVolume: number; speakerVolume: number; volume: number; }; stats: { edgeRecording: { deviceMac: Nullable; recordMode: string; recordStreamNumber: Nullable; }; sdCard: { health: Nullable; healthStatus: string; hotPlugCapable: Nullable; mounts: ProtectKnownJsonValue[]; sdRecordingSupported: Nullable; serial: Nullable; size: Nullable; slotId: string; slotIdx: Nullable; state: string; type: Nullable; usedSize: number; }; sdCardStorageCapacityMs: Nullable; storage: { rate: number; used: number; }; storageSlots: ProtectKnownJsonValue[]; totalStorageCapacityMs: Nullable; video: { recordingEnd: number; recordingEndLQ: number; recordingStart: number; recordingStartLQ: number; timelapseEnd: number; timelapseEndLQ: number; timelapseStart: number; timelapseStartLQ: number; }; wifi: { channel: Nullable; frequency: Nullable; linkSpeedMbps: Nullable; signalQuality: number; signalStrength: number; }; wifiQuality: number; wifiStrength: number; }; stitchDistance: Nullable; stopStreamLevel: Nullable; streamSharing: { enabled: boolean; expires: Nullable; maxStreams: Nullable; shareLink: Nullable; sharedByUser: Nullable; sharedByUserId: Nullable; token: Nullable; }; streamingChannels: ProtectKnownJsonValue[]; supportAiPortResolution: boolean; supportAiPortResolutionInHallway: boolean; supportUcp4: boolean; supportedScalingResolutions: string[]; // The camera's own talkback settings (a single object), distinct from the Access-integration talkback channel array nested under `accessDeviceMetadata` above. talkbackSettings: ProtectCameraTalkbackConfigInterface; template: Nullable; thirdPartyCameraInfo: { enableRtspAudio: Nullable; errors: ProtectKnownJsonValue[]; forceTcp: Nullable; hasAudio: Nullable; port: number; rtspUrl: string; rtspUrlLQ: string; snapshotUrl: string; }; tiltLimitsOfPrivacyZones: { limit: number; side: string; }; userConfiguredAp: boolean; videoCodec: string; videoCodecLastSwitchAt: Nullable; videoCodecState: number; videoCodecSwitchingSince: number; videoInputMode: Nullable; videoMode: string; videoReconfigurationInProgress: boolean; voltage: number; } /** * A semi-complete description of the UniFi Protect camera channel JSON. */ export interface ProtectCameraChannelConfigInterface { autoBitrate: boolean; autoFps: boolean; bitrate: number; enabled: boolean; fps: number; fpsValues: number[]; height: number; id: number; idrInterval: number; internalRtspAlias: Nullable; isInternalRtspEnabled: boolean; isRtspEnabled: boolean; maxBitrate: number; minBitrate: number; minClientAdaptiveBitRate: number; minMotionAdaptiveBitRate: number; name: string; rtspAlias: string; validBitrateRangeMargin: Nullable; videoId: string; width: number; [key: string]: ProtectKnownJsonValue; } /** * A semi-complete description of the UniFi Protect LCD message JSON. */ export interface ProtectCameraLcdMessageConfigInterface { duration: number; resetAt: Nullable; text: string; type: string; [key: string]: ProtectKnownJsonValue; } /** * A description of the UniFi Protect camera recording-path settings JSON: the storage console the camera records to, whether it automatically fails over to another, and * the failover timeout. */ export interface ProtectCameraRecordingPathSettingsInterface { failoverTimeoutMs: Nullable; isAutoFailoverEnabled: boolean; storageConsoleIndex: number; [key: string]: ProtectKnownJsonValue; } /** * A semi-complete description of the UniFi Protect talkback settings JSON. */ export interface ProtectCameraTalkbackConfigInterface { bindAddr: string; bindPort: number; bitsPerSample: number; channels: number; filterAddr: string; filterPort: number; quality: number; samplingRate: number; typeFmt: string; typeIn: string; url: string; [key: string]: ProtectKnownJsonValue; } /** @see {@link ProtectPtzAxisRangeInterface} */ export type ProtectPtzAxisRange = ProtectPtzAxisRangeInterface; /** @see {@link ProtectCameraConfigInterface} */ export type ProtectCameraConfig = ProtectCameraConfigInterface; /** @see {@link ProtectCameraChannelConfigInterface} */ export type ProtectCameraChannelConfig = ProtectCameraChannelConfigInterface; /** @see {@link ProtectCameraLcdMessageConfigInterface} */ export type ProtectCameraLcdMessageConfig = ProtectCameraLcdMessageConfigInterface; /** @see {@link ProtectCameraRecordingPathSettingsInterface} */ export type ProtectCameraRecordingPathSettings = ProtectCameraRecordingPathSettingsInterface; /** @see {@link ProtectCameraTalkbackConfigInterface} */ export type ProtectCameraTalkbackConfig = ProtectCameraTalkbackConfigInterface;