@apocaliss92/scrypted-reolink-native 0.1.42 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/nvr.ts CHANGED
@@ -1,32 +1,33 @@
1
- import type { EventsResponse, ReolinkBaichuanApi, ReolinkBaichuanDeviceSummary, ReolinkSimpleEvent } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
1
+ import type { ReolinkBaichuanApi, ReolinkBaichuanDeviceSummary, ReolinkSimpleEvent } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
2
2
  import sdk, { AdoptDevice, Device, DeviceDiscovery, DeviceProvider, DiscoveredDevice, Reboot, ScryptedDeviceType, ScryptedInterface, Setting, Settings, SettingValue } from "@scrypted/sdk";
3
3
  import { StorageSettings } from "@scrypted/sdk/storage-settings";
4
4
  import { BaseBaichuanClass, type BaichuanConnectionCallbacks, type BaichuanConnectionConfig } from "./baichuan-base";
5
- import { ReolinkNativeCamera } from "./camera";
6
- import { ReolinkNativeBatteryCamera } from "./camera-battery";
7
- import { normalizeUid } from "./connect";
5
+ import { ReolinkCamera } from "./camera";
8
6
  import { convertDebugLogsToApiOptions, getApiRelevantDebugLogs, getDebugLogChoices } from "./debug-options";
9
7
  import ReolinkNativePlugin from "./main";
10
- import { getDeviceInterfaces, updateDeviceInfo } from "./utils";
8
+ import { ReolinkNativeMultiFocalDevice } from "./multiFocal";
9
+ import { batteryCameraSuffix, batteryMultifocalSuffix, cameraSuffix, getDeviceInterfaces, multifocalSuffix, updateDeviceInfo } from "./utils";
11
10
 
12
11
  export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Settings, DeviceDiscovery, DeviceProvider, Reboot {
12
+ private readonly onSimpleEventBound = (ev: ReolinkSimpleEvent) => this.onSimpleEvent(ev);
13
+
13
14
  storageSettings = new StorageSettings(this, {
14
15
  debugLogs: {
15
16
  title: 'Debug Events',
16
17
  type: 'boolean',
17
18
  immediate: true,
18
19
  },
19
- eventSource: {
20
- title: 'Event Source',
21
- description: 'Select the source for camera events: Native (Baichuan) or CGI (HTTP polling)',
22
- type: 'string',
23
- choices: ['Native', 'CGI'],
24
- defaultValue: 'Native',
25
- immediate: true,
26
- onPut: async () => {
27
- await this.reinitEventSubscriptions();
28
- }
29
- },
20
+ // eventSource: {
21
+ // title: 'Event Source',
22
+ // description: 'Select the source for camera events: Native (Baichuan) or CGI (HTTP polling)',
23
+ // type: 'string',
24
+ // choices: ['Native', 'CGI'],
25
+ // defaultValue: 'Native',
26
+ // immediate: true,
27
+ // onPut: async () => {
28
+ // await this.reinitEventSubscriptions();
29
+ // }
30
+ // },
30
31
  ipAddress: {
31
32
  title: 'IP address',
32
33
  type: 'string',
@@ -79,17 +80,14 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
79
80
  this.debugLogsResetTimeout = undefined;
80
81
  }
81
82
 
82
- // Defer reset by 2 seconds to allow settings to settle
83
83
  this.debugLogsResetTimeout = setTimeout(async () => {
84
84
  this.debugLogsResetTimeout = undefined;
85
85
  try {
86
- // Force reconnection with new debug options
87
86
  this.baichuanApi = undefined;
88
87
  this.ensureClientPromise = undefined;
89
- // Trigger reconnection
90
88
  await this.ensureBaichuanClient();
91
89
  } catch (e) {
92
- logger.warn('Failed to reset client after debug logs change', e);
90
+ logger.warn('Failed to reset client after debug logs change', e?.message || String(e));
93
91
  }
94
92
  }, 2000);
95
93
  }
@@ -103,10 +101,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
103
101
  rtspChannel: number;
104
102
  deviceData: ReolinkBaichuanDeviceSummary;
105
103
  }>();
106
- lastNvrInfoCheck: number | undefined;
107
- lastErrorsCheck: number | undefined;
108
- lastDevicesStatusCheck: number | undefined;
109
- cameraNativeMap = new Map<string, ReolinkNativeCamera | ReolinkNativeBatteryCamera>();
104
+ cameraNativeMap = new Map<string, ReolinkCamera>();
110
105
  private channelToNativeIdMap = new Map<number, string>();
111
106
  private discoverDevicesPromise: Promise<DiscoveredDevice[]> | undefined;
112
107
  processing = false;
@@ -114,7 +109,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
114
109
  private debugLogsResetTimeout: NodeJS.Timeout | undefined;
115
110
 
116
111
  constructor(nativeId: string, plugin: ReolinkNativePlugin) {
117
- super(nativeId);
112
+ super(nativeId, "tcp");
118
113
  this.plugin = plugin;
119
114
 
120
115
  this.scheduleInit();
@@ -142,6 +137,23 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
142
137
  };
143
138
  }
144
139
 
140
+ protected getStreamClientInputs(): BaichuanConnectionConfig {
141
+ const { ipAddress, username, password } = this.storageSettings.values;
142
+ if (!ipAddress || !username || !password) {
143
+ throw new Error('Missing NVR credentials');
144
+ }
145
+
146
+ const debugOptions = this.getBaichuanDebugOptions();
147
+
148
+ return {
149
+ host: ipAddress,
150
+ username,
151
+ password,
152
+ transport: 'tcp',
153
+ debugOptions,
154
+ };
155
+ }
156
+
145
157
  getBaichuanDebugOptions(): any | undefined {
146
158
  const socketDebugLogs = this.storageSettings.values.socketApiDebugLogs || [];
147
159
  return convertDebugLogsToApiOptions(socketDebugLogs);
@@ -152,15 +164,11 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
152
164
  onClose: async () => {
153
165
  await this.reinit();
154
166
  },
155
- onSimpleEvent: (ev) => this.forwardNativeEvent(ev),
156
- getEventSubscriptionEnabled: () => {
157
- const eventSource = this.storageSettings.values.eventSource || 'Native';
158
- return eventSource === 'Native';
159
- },
167
+ onSimpleEvent: this.onSimpleEventBound,
168
+ getEventSubscriptionEnabled: () => true,
160
169
  };
161
170
  }
162
171
 
163
-
164
172
  protected isDebugEnabled(): boolean {
165
173
  return this.storageSettings.values.debugLogs || false;
166
174
  }
@@ -170,7 +178,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
170
178
  }
171
179
 
172
180
  protected async onBeforeCleanup(): Promise<void> {
173
- await this.unsubscribeFromAllEvents();
181
+ await this.unsubscribeFromEvents();
174
182
  }
175
183
 
176
184
  async reinit() {
@@ -179,7 +187,6 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
179
187
  this.initReinitTimeout = undefined;
180
188
  }
181
189
 
182
- // Schedule reinit with debounce
183
190
  this.scheduleInit(true);
184
191
  }
185
192
 
@@ -198,18 +205,12 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
198
205
  }, isReinit ? 500 : 2000);
199
206
  }
200
207
 
201
- private forwardNativeEvent(ev: ReolinkSimpleEvent): void {
208
+ onSimpleEvent(ev: ReolinkSimpleEvent) {
202
209
  const logger = this.getBaichuanLogger();
203
210
 
204
- const eventSource = this.storageSettings.values.eventSource || 'Native';
205
- if (eventSource !== 'Native') {
206
- return;
207
- }
208
-
209
211
  try {
210
- logger.debug(`Baichuan event: ${JSON.stringify(ev)}`);
212
+ logger.debug(`Baichuan event on nvr: ${JSON.stringify(ev)}`);
211
213
 
212
- // Find camera for this channel
213
214
  const channel = ev?.channel;
214
215
  if (channel === undefined) {
215
216
  logger.error('Event has no channel, ignoring');
@@ -217,89 +218,26 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
217
218
  }
218
219
 
219
220
  const nativeId = this.channelToNativeIdMap.get(channel);
220
- const targetCamera = nativeId ? this.cameraNativeMap.get(nativeId) : undefined;
221
+ const targetDevice = nativeId ? this.cameraNativeMap.get(nativeId) : undefined;
221
222
 
222
- if (!targetCamera) {
223
- logger.debug(`No camera found for channel ${channel} (nativeId: ${nativeId}), ignoring event`);
223
+ if (!targetDevice) {
224
+ logger.debug(`No device found for channel ${channel} (nativeId: ${nativeId}), ignoring event`);
224
225
  return;
225
226
  }
226
227
 
227
- // Convert event to camera's processEvents format
228
- const objects: string[] = [];
229
- let motion = false;
230
- let isSleepingEvent = false;
231
- let isOnlineEvent = false;
232
-
233
- switch (ev?.type) {
234
- case 'motion':
235
- motion = true;
236
- break;
237
- case 'doorbell':
238
- // Handle doorbell if camera supports it
239
- try {
240
- targetCamera.handleDoorbellEvent();
241
- }
242
- catch (e) {
243
- logger.warn(`Error handling doorbell event for camera channel ${channel}`, e);
244
- }
245
- motion = true;
246
- break;
247
- case 'people':
248
- case 'vehicle':
249
- case 'animal':
250
- case 'face':
251
- case 'package':
252
- case 'other':
253
- objects.push(ev.type);
254
- motion = true;
255
- break;
256
- case 'awake':
257
- case 'sleeping':
258
- isSleepingEvent = true;
259
- break;
260
- case 'offline':
261
- case 'online':
262
- isOnlineEvent = true;
263
- break;
264
- default:
265
- logger.error(`Unknown event type: ${ev?.type}`);
266
- return;
267
- }
268
-
269
- if (isSleepingEvent) {
270
- (targetCamera as ReolinkNativeBatteryCamera).updateSleepingState({
271
- reason: 'NVR',
272
- state: ev.type === 'sleeping' ? 'sleeping' : 'awake',
273
- }).catch(() => { });
274
- } if (isSleepingEvent) {
275
- (targetCamera as ReolinkNativeBatteryCamera).updateOnlineState(
276
- ev.type === 'online' ? true : false
277
- ).catch(() => { });
278
- } else {
279
- // Process events on the target camera
280
- targetCamera.processEvents({ motion, objects }).catch((e) => {
281
- logger.warn(`Error processing events for camera channel ${channel}`, e);
282
- });
283
- }
228
+ targetDevice.onSimpleEvent(ev);
284
229
  }
285
230
  catch (e) {
286
- logger.warn('Error in NVR Native event forwarder', e);
231
+ logger.warn('Error in NVR Native event forwarder', e?.message || String(e));
287
232
  }
288
233
  }
289
234
 
290
235
  async ensureBaichuanClient(): Promise<ReolinkBaichuanApi> {
291
- // Use base class implementation
292
236
  return await super.ensureBaichuanClient();
293
237
  }
294
238
 
295
- async subscribeToAllEvents(): Promise<void> {
296
- const eventSource = this.storageSettings.values.eventSource || 'Native';
297
-
298
- if (eventSource !== 'Native') {
299
- await this.unsubscribeFromAllEvents();
300
- } else {
301
- await super.subscribeToEvents();
302
- }
239
+ async ensureClient(): Promise<ReolinkBaichuanApi> {
240
+ return await this.ensureBaichuanClient();
303
241
  }
304
242
 
305
243
  private async runNvrDiagnostics(): Promise<void> {
@@ -313,117 +251,17 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
313
251
  logger: this.console,
314
252
  });
315
253
  } catch (e) {
316
- logger.error('Failed to run NVR diagnostics', e);
254
+ logger.error('Failed to run NVR diagnostics', e?.message || String(e));
317
255
  throw e;
318
256
  }
319
257
  }
320
258
 
321
- async unsubscribeFromAllEvents(): Promise<void> {
322
- // Use base class implementation
323
- await super.unsubscribeFromEvents();
324
- }
325
-
326
- /**
327
- * Reinitialize event subscriptions based on selected event source
328
- */
329
- private async reinitEventSubscriptions(): Promise<void> {
330
- const logger = this.getBaichuanLogger();
331
- const { eventSource } = this.storageSettings.values;
332
-
333
- // Unsubscribe from Native events if switching away
334
- if (eventSource !== 'Native') {
335
- await this.unsubscribeFromAllEvents();
336
- } else {
337
- this.subscribeToAllEvents().catch((e) => {
338
- logger.warn('Failed to subscribe to Native events', e);
339
- });
340
- }
341
-
342
- logger.log(`Event source set to: ${eventSource}`);
343
- }
344
-
345
- /**
346
- * Forward events from CGI source to cameras
347
- */
348
- private forwardCgiEvents(eventsRes: Record<number, EventsResponse>): void {
349
- const logger = this.getBaichuanLogger();
350
-
351
- logger.debug(`CGI Events call result: ${JSON.stringify(eventsRes)}`);
352
-
353
- // Use channel map for efficient lookup
354
- for (const [channel, nativeId] of this.channelToNativeIdMap.entries()) {
355
- const targetCamera = nativeId ? this.cameraNativeMap.get(nativeId) : undefined;
356
- const cameraEventsData = eventsRes[channel];
357
- if (cameraEventsData && targetCamera) {
358
- targetCamera.processEvents(cameraEventsData);
359
- }
360
- }
361
- }
362
-
363
259
  async init() {
364
- const logger = this.getBaichuanLogger();
365
260
  await this.ensureBaichuanClient();
261
+ await this.subscribeToEvents();
262
+ await this.discoverDevices(true);
366
263
 
367
264
  await this.updateDeviceInfo();
368
-
369
- await this.reinitEventSubscriptions();
370
-
371
- setInterval(async () => {
372
- if (this.processing) {
373
- return;
374
- }
375
- this.processing = true;
376
- try {
377
- const now = Date.now();
378
-
379
- if (!this.lastErrorsCheck || (now - this.lastErrorsCheck > 60 * 1000)) {
380
- this.lastErrorsCheck = now;
381
- // Note: ReolinkCgiApi doesn't have checkErrors, skip for now
382
- }
383
-
384
- if (!this.lastNvrInfoCheck || now - this.lastNvrInfoCheck > 1000 * 60 * 5) {
385
- this.lastNvrInfoCheck = now;
386
- // const { nvrData } = await api.getNvrInfo();
387
- // const { devicesData, channelsResponse, response } = await api.getDevicesInfo();
388
- // logger.log(`NVR info data fetched`);
389
- // logger.debug(`${JSON.stringify({ nvrData, devicesData, channelsResponse, response })}`);
390
-
391
- await this.discoverDevices(true);
392
- }
393
-
394
- const api = await this.ensureBaichuanClient();
395
-
396
- const { eventSource } = this.storageSettings.values;
397
-
398
- if (eventSource === 'CGI') {
399
- const eventsRes = await api.getAllChannelsEvents();
400
- this.forwardCgiEvents(eventsRes.parsed);
401
-
402
- const { batteryInfoData, response } = await api.getAllChannelsBatteryInfo();
403
-
404
- logger.debug(`Battery info call result: ${JSON.stringify({ batteryInfoData, response })}`);
405
-
406
- this.cameraNativeMap.forEach((camera) => {
407
- if (camera) {
408
- const channel = camera.storageSettings.values.rtspChannel;
409
- const cameraBatteryData = batteryInfoData[channel];
410
- if (cameraBatteryData) {
411
- (camera as ReolinkNativeBatteryCamera).updateSleepingState({
412
- reason: 'NVR',
413
- state: cameraBatteryData.sleeping ? 'sleeping' : 'awake',
414
- idleMs: 0,
415
- lastRxAtMs: 0,
416
- }).catch(() => { });
417
- }
418
- }
419
- });
420
- }
421
- } catch (e) {
422
- logger.error('Error on events flow', e);
423
- } finally {
424
- this.processing = false;
425
- }
426
- }, 1000);
427
265
  }
428
266
 
429
267
  async updateDeviceInfo(): Promise<void> {
@@ -441,7 +279,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
441
279
  logger
442
280
  });
443
281
  } catch (e) {
444
- logger.warn('Failed to fetch device info', e);
282
+ logger.warn('Failed to fetch device info', e?.message || String(e));
445
283
  }
446
284
  }
447
285
 
@@ -458,27 +296,38 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
458
296
  this.cameraNativeMap.delete(nativeId);
459
297
  }
460
298
 
461
- async getDevice(nativeId: string): Promise<ReolinkNativeCamera | ReolinkNativeBatteryCamera> {
299
+ async getDevice(nativeId: string): Promise<ReolinkCamera> {
462
300
  let device = this.cameraNativeMap.get(nativeId);
463
301
 
464
302
  if (!device) {
465
- if (nativeId.endsWith('-battery-cam')) {
466
- device = new ReolinkNativeBatteryCamera(nativeId, this.plugin, this);
303
+ if (nativeId.endsWith(batteryCameraSuffix)) {
304
+ device = new ReolinkCamera(nativeId, this.plugin, { type: 'battery', nvrDevice: this });
305
+ } else if (nativeId.endsWith(batteryMultifocalSuffix)) {
306
+ device = new ReolinkNativeMultiFocalDevice(nativeId, this.plugin, "multi-focal-battery", this);
307
+ } else if (nativeId.endsWith(multifocalSuffix)) {
308
+ device = new ReolinkNativeMultiFocalDevice(nativeId, this.plugin, "multi-focal", this);
467
309
  } else {
468
- device = new ReolinkNativeCamera(nativeId, this.plugin, this);
310
+ device = new ReolinkCamera(nativeId, this.plugin, { type: 'regular', nvrDevice: this });
311
+ }
312
+
313
+ if (device) {
314
+ this.cameraNativeMap.set(nativeId, device);
469
315
  }
470
- this.cameraNativeMap.set(nativeId, device);
471
316
  }
472
317
 
473
318
  return device;
474
319
  }
475
320
 
476
- buildNativeId(channel: number, serialNumber?: string, isBattery?: boolean): string {
477
- const suffix = isBattery ? '-battery-cam' : '-cam';
478
- if (serialNumber) {
479
- return `${this.nativeId}-ch${channel}-${serialNumber}${suffix}`;
480
- }
481
- return `${this.nativeId}-ch${channel}${suffix}`;
321
+ buildNativeId(props: {
322
+ identifier?: string, isBattery?: boolean, isMultifocal?: boolean
323
+ }): string {
324
+ const { identifier, isBattery, isMultifocal } = props;
325
+
326
+ const suffix = isBattery ?
327
+ (isMultifocal ? batteryMultifocalSuffix : batteryCameraSuffix) :
328
+ (isMultifocal ? multifocalSuffix : cameraSuffix)
329
+
330
+ return `${this.nativeId}-${identifier}${suffix}`;
482
331
  }
483
332
 
484
333
  getCameraInterfaces() {
@@ -495,23 +344,31 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
495
344
 
496
345
  async syncEntitiesFromRemote() {
497
346
  const logger = this.getBaichuanLogger();
347
+ // const { ipAddress } = this.storageSettings.values;
498
348
 
499
349
  const api = await this.ensureBaichuanClient();
500
- const { devices, channels } = await api.getDevicesInfo();
501
- logger.log(devices, channels);
350
+ const { devices, channels } = await api.getNvrChannelsSummary({ source: "cgi" });
502
351
 
503
352
  if (!channels.length) {
504
353
  logger.debug(`No channels found, ${JSON.stringify({ channels, devices })}`);
354
+ await new Promise(resolve => setTimeout(resolve, 1000));
355
+ await this.syncEntitiesFromRemote();
505
356
  return;
506
357
  }
507
358
 
508
359
  logger.log(`Sync entities from remote for ${channels.length} channels`);
509
360
 
510
361
  for (const deviceData of devices) {
511
- const { isBattery, serialNumber, name, model, isDoorbell, uid, channel } = deviceData
362
+ const { isBattery, serialNumber, name, model, isDoorbell, uid, channel, isMultifocal } = deviceData;
363
+ const identifier = uid || name || `channel-${channel}`;
364
+ // const identifier = uid || mac || (ip !== ipAddress ? ip : undefined) || name || randomBytes(4).toString('hex');
512
365
 
513
366
  try {
514
- const nativeId = this.buildNativeId(channel, uid, isBattery);
367
+ const nativeId = this.buildNativeId({
368
+ isBattery,
369
+ isMultifocal,
370
+ identifier,
371
+ });
515
372
  const interfaces = [ScryptedInterface.VideoCamera];
516
373
  if (isBattery) {
517
374
  interfaces.push(ScryptedInterface.Battery);
@@ -527,7 +384,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
527
384
  info: {
528
385
  manufacturer: 'Reolink',
529
386
  model,
530
- serialNumber: uid,
387
+ serialNumber,
531
388
  }
532
389
  };
533
390
 
@@ -538,7 +395,10 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
538
395
  if (
539
396
  allNativeIds.some(
540
397
  nid => nid.includes(uid) ||
541
- nid.includes(serialNumber) ||
398
+ nid.includes(`channel-${channel}`) ||
399
+ // nid.includes(mac) ||
400
+ // nid.includes(ip) ||
401
+ nid.includes(name) ||
542
402
  nid === nativeId)
543
403
  ) {
544
404
  continue;
@@ -601,29 +461,28 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
601
461
 
602
462
  await this.onDeviceEvent(ScryptedInterface.DeviceDiscovery, await this.discoverDevices());
603
463
 
604
- const isBattery = entry.device.interfaces.includes(ScryptedInterface.Battery);
605
464
  const { uid } = entry.deviceData;
606
465
 
607
466
  const { ReolinkBaichuanApi } = await import("@apocaliss92/reolink-baichuan-js");
608
467
  const transport = 'tcp';
609
- const normalizedUid = isBattery && uid ? normalizeUid(uid) : undefined;
610
468
  const baichuanApi = new ReolinkBaichuanApi({
611
469
  host: this.storageSettings.values.ipAddress,
612
470
  username: this.storageSettings.values.username,
613
471
  password: this.storageSettings.values.password,
614
472
  transport,
615
473
  channel: entry.rtspChannel,
616
- ...(normalizedUid ? { uid: normalizedUid } : {}),
474
+ uid,
617
475
  });
618
476
  await baichuanApi.login();
619
477
  const { capabilities, objects, presets } = await baichuanApi.getDeviceCapabilities(entry.rtspChannel);
620
478
  const { interfaces, type } = getDeviceInterfaces({
621
479
  capabilities,
622
- logger: this.console,
480
+ logger: this.getBaichuanLogger(),
623
481
  });
624
482
 
625
483
  const actualDevice: Device = {
626
484
  ...entry.device,
485
+ providerNativeId: this.nativeId,
627
486
  interfaces,
628
487
  type
629
488
  };
@@ -632,8 +491,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
632
491
 
633
492
  const device = await this.getDevice(adopt.nativeId);
634
493
  const logger = this.getBaichuanLogger();
635
- logger.log('Adopted device', device?.name);
636
- logger.log(JSON.stringify(entry));
494
+ logger.log('Adopted device', device?.name, JSON.stringify(actualDevice));
637
495
  const { username, password, ipAddress } = this.storageSettings.values;
638
496
 
639
497
  device.storageSettings.values.rtspChannel = entry.rtspChannel;
package/src/presets.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { PtzPreset } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
2
- import type { CommonCameraMixin } from "./common";
2
+ import type { ReolinkCamera } from "./camera";
3
3
 
4
4
  export type PtzCapabilitiesShape = {
5
5
  presets?: Record<string, string>;
@@ -7,7 +7,7 @@ export type PtzCapabilitiesShape = {
7
7
  };
8
8
 
9
9
  export class ReolinkPtzPresets {
10
- constructor(private camera: CommonCameraMixin & { ptzCapabilities?: any }) { }
10
+ constructor(private camera: ReolinkCamera & { ptzCapabilities?: any }) { }
11
11
 
12
12
  private get storageSettings() {
13
13
  return this.camera.storageSettings;