@apocaliss92/scrypted-reolink-native 0.2.17 → 0.3.0

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/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apocaliss92/scrypted-reolink-native",
3
- "version": "0.2.17",
3
+ "version": "0.3.0",
4
4
  "description": "Use any reolink camera with Scrypted, even older/unsupported models without HTTP protocol support",
5
5
  "author": "@apocaliss92",
6
6
  "license": "Apache",
package/src/camera.ts CHANGED
@@ -5,8 +5,6 @@ import path from 'path';
5
5
  import fs from 'fs';
6
6
  import crypto from 'crypto';
7
7
  import { spawn } from 'node:child_process';
8
- import http from 'http';
9
- import https from 'https';
10
8
  import type { UrlMediaStreamOptions } from "../../scrypted/plugins/rtsp/src/rtsp";
11
9
  import { BaseBaichuanClass, type BaichuanConnectionCallbacks, type BaichuanConnectionConfig } from "./baichuan-base";
12
10
  import { createBaichuanApi, normalizeUid, type BaichuanTransport } from "./connect";
@@ -237,10 +235,10 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
237
235
  defaultValue: 'default',
238
236
  choices: ['default', 'autotrack', 'telephoto'] as NativeVideoStreamVariant[],
239
237
  },
240
- capabilities: {
241
- json: true,
242
- hide: true,
243
- },
238
+ // capabilities: {
239
+ // json: true,
240
+ // hide: true,
241
+ // },
244
242
  multifocalInfo: {
245
243
  json: true,
246
244
  hide: true,
@@ -672,6 +670,8 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
672
670
  private takePictureInFlight: Promise<MediaObject> | undefined;
673
671
  forceNewSnapshot: boolean = false;
674
672
 
673
+ public cachedCapabilities: DeviceCapabilities | undefined;
674
+
675
675
  // Video stream properties
676
676
  protected cachedVideoStreamOptions?: UrlMediaStreamOptions[];
677
677
  protected fetchingStreamsPromise: Promise<UrlMediaStreamOptions[]> | undefined;
@@ -915,8 +915,8 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
915
915
  await fs.promises.mkdir(cacheDir, { recursive: true });
916
916
  }
917
917
 
918
- const { clipsSource } = this.storageSettings.values;
919
- const useNvr = clipsSource === "NVR" && this.nvrDevice;
918
+ // const { clipsSource } = this.storageSettings.values;
919
+ // const useNvr = clipsSource === "NVR" && this.nvrDevice;
920
920
 
921
921
  // Both standalone and NVR now use a URL-based playback path.
922
922
  // In NVR mode, `videoId` is expected to be a full recording path (e.g. /mnt/sda/...).
@@ -1046,8 +1046,8 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
1046
1046
  // Ensure cache directory exists
1047
1047
  await fs.promises.mkdir(cacheDir, { recursive: true });
1048
1048
 
1049
- const { clipsSource } = this.storageSettings.values;
1050
- const useNvr = clipsSource === "NVR" && this.nvrDevice;
1049
+ // const { clipsSource } = this.storageSettings.values;
1050
+ // const useNvr = clipsSource === "NVR" && this.nvrDevice;
1051
1051
 
1052
1052
  // NVR mode: `thumbnailId` is expected to be a full recording path (e.g. /mnt/sda/...).
1053
1053
  // Use the same ffmpeg-based thumbnail extraction flow as other sources.
@@ -1468,32 +1468,40 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
1468
1468
  return await super.createStreamClient(streamKey);
1469
1469
  }
1470
1470
 
1471
- public getAbilities(): DeviceCapabilities {
1472
- if (this.multiFocalDevice) {
1473
- const variantType = this.storageSettings.values.variantType;
1474
- const ifaces = this.multiFocalDevice.getInterfaces(variantType);
1475
- if (ifaces?.capabilities) return ifaces.capabilities;
1476
- } else {
1477
- const caps = this.storageSettings.values.capabilities;
1478
- if (caps) return caps;
1479
- }
1471
+ public async getAbilities(): Promise<DeviceCapabilities> {
1472
+ const logger = this.getBaichuanLogger();
1480
1473
 
1481
- // Safe fallback to avoid crashes during init when connection hasn't succeeded yet.
1482
- return {
1483
- channel: this.storageSettings.values.rtspChannel ?? 0,
1484
- ptzMode: 'none',
1485
- hasPan: false,
1486
- hasTilt: false,
1487
- hasZoom: false,
1488
- hasPresets: false,
1489
- hasPtz: false,
1490
- hasBattery: !!this.isBattery,
1491
- hasIntercom: false,
1492
- hasSiren: false,
1493
- hasFloodlight: false,
1494
- hasPir: false,
1495
- isDoorbell: false,
1496
- };
1474
+ try {
1475
+ if (this.multiFocalDevice) {
1476
+ const variantType = this.storageSettings.values.variantType;
1477
+ const ifaces = await this.multiFocalDevice.getInterfaces(variantType);
1478
+ if (ifaces?.capabilities) return ifaces.capabilities;
1479
+ } else {
1480
+ if (this.cachedCapabilities) return this.cachedCapabilities;
1481
+
1482
+ const client = await this.ensureClient();
1483
+ const { capabilities } = await client.getDeviceCapabilities(this.storageSettings.values.rtspChannel ?? 0);
1484
+ this.cachedCapabilities = capabilities;
1485
+ return capabilities;
1486
+ }
1487
+ } catch (e) {
1488
+ logger.error('Failed to get abilities', e);
1489
+ return {
1490
+ channel: this.storageSettings.values.rtspChannel ?? 0,
1491
+ ptzMode: 'none',
1492
+ hasPan: false,
1493
+ hasTilt: false,
1494
+ hasZoom: false,
1495
+ hasPresets: false,
1496
+ hasPtz: false,
1497
+ hasBattery: !!this.isBattery,
1498
+ hasIntercom: false,
1499
+ hasSiren: false,
1500
+ hasFloodlight: false,
1501
+ hasPir: false,
1502
+ isDoorbell: false,
1503
+ };
1504
+ }
1497
1505
  }
1498
1506
 
1499
1507
  getBaichuanDebugOptions(): any | undefined {
@@ -1620,8 +1628,8 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
1620
1628
  );
1621
1629
  }
1622
1630
 
1623
- updatePtzCaps() {
1624
- const { hasPan, hasTilt, hasZoom } = this.getAbilities();
1631
+ async updatePtzCaps() {
1632
+ const { hasPan, hasTilt, hasZoom } = await this.getAbilities();
1625
1633
  this.ptzCapabilities = {
1626
1634
  ...this.ptzCapabilities,
1627
1635
  pan: hasPan,
@@ -1994,7 +2002,9 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
1994
2002
  }
1995
2003
 
1996
2004
  async reportDevices(): Promise<void> {
1997
- const abilities = this.getAbilities();
2005
+ const abilities = await this.getAbilities();
2006
+ const logger = this.getBaichuanLogger();
2007
+ logger.debug(`Reporting devices: ${JSON.stringify(abilities)}`);
1998
2008
 
1999
2009
  const { hasSiren, hasFloodlight, hasPir } = abilities;
2000
2010
 
@@ -2269,7 +2279,7 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2269
2279
  const api = await this.ensureClient();
2270
2280
 
2271
2281
  const channel = this.storageSettings.values.rtspChannel;
2272
- const { hasSiren, hasFloodlight, hasPir } = this.getAbilities();
2282
+ const { hasSiren, hasFloodlight, hasPir } = await this.getAbilities();
2273
2283
 
2274
2284
  try {
2275
2285
  // Align siren state
@@ -2691,7 +2701,7 @@ export class ReolinkCamera extends BaseBaichuanClass implements VideoCamera, Cam
2691
2701
  logger.error('Failed to initialize StreamManager', e?.message || String(e));
2692
2702
  }
2693
2703
 
2694
- const { hasIntercom, hasPtz } = this.getAbilities();
2704
+ const { hasIntercom, hasPtz } = await this.getAbilities();
2695
2705
 
2696
2706
  if (hasIntercom) {
2697
2707
  this.intercom = new ReolinkBaichuanIntercom(this);
package/src/main.ts CHANGED
@@ -119,7 +119,7 @@ class ReolinkNativePlugin extends ScryptedDeviceBase implements DeviceProvider,
119
119
  device.storageSettings.values.username = username;
120
120
  device.storageSettings.values.password = password;
121
121
  device.storageSettings.values.uid = uid;
122
- device.storageSettings.values.capabilities = capabilities;
122
+ device.cachedCapabilities = capabilities;
123
123
 
124
124
  return nativeId;
125
125
  }
@@ -190,10 +190,11 @@ class ReolinkNativePlugin extends ScryptedDeviceBase implements DeviceProvider,
190
190
  device.storageSettings.values.password = password;
191
191
  device.storageSettings.values.rtspChannel = rtspChannel;
192
192
  device.storageSettings.values.ipAddress = ipAddress;
193
- device.storageSettings.values.capabilities = capabilities;
194
193
  device.storageSettings.values.uid = uid;
195
194
  device.storageSettings.values.discoveryMethod = detection.udpDiscoveryMethod;
196
195
 
196
+ device.cachedCapabilities = capabilities;
197
+
197
198
  return nativeId;
198
199
  }
199
200
  catch (e) {
package/src/multiFocal.ts CHANGED
@@ -25,9 +25,10 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
25
25
  return this.name || 'Multi-Focal Device';
26
26
  }
27
27
 
28
- getInterfaces(lensType?: NativeVideoStreamVariant) {
28
+ async getInterfaces(lensType?: NativeVideoStreamVariant) {
29
29
  const logger = this.getBaichuanLogger();
30
- const { capabilities: caps, multifocalInfo } = this.storageSettings.values;
30
+ const { multifocalInfo } = this.storageSettings.values;
31
+ const caps = await this.getAbilities();
31
32
 
32
33
  let capabilities: DeviceCapabilities = { ...caps };
33
34
 
@@ -77,7 +78,6 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
77
78
  logger.debug({ multifocalInfo, capabilities });
78
79
 
79
80
  this.storageSettings.values.multifocalInfo = multifocalInfo;
80
- this.storageSettings.values.capabilities = capabilities;
81
81
 
82
82
  for (const channelInfo of multifocalInfo?.channels ?? []) {
83
83
  const { channel, lensType, variantType } = channelInfo;
@@ -86,7 +86,7 @@ export class ReolinkNativeMultiFocalDevice extends ReolinkCamera implements Sett
86
86
  const nativeId = `${this.nativeId}-${lensType}${this.isBattery ? batteryCameraSuffix : cameraSuffix}`;
87
87
 
88
88
  this.channelToNativeIdMap.set(channel, nativeId);
89
- const { interfaces, capabilities: deviceCapabilities } = this.getInterfaces();
89
+ const { interfaces, capabilities: deviceCapabilities } = await this.getInterfaces();
90
90
 
91
91
  const device: Device = {
92
92
  providerNativeId: this.nativeId,
package/src/nvr.ts CHANGED
@@ -501,9 +501,10 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
501
501
  device.storageSettings.values.password = password;
502
502
  device.storageSettings.values.rtspChannel = entry.rtspChannel;
503
503
  device.storageSettings.values.ipAddress = ipAddress;
504
- device.storageSettings.values.capabilities = capabilities;
505
504
  device.storageSettings.values.uid = uid;
506
505
 
506
+ device.cachedCapabilities = capabilities;
507
+
507
508
  this.discoveredDevices.delete(adopt.nativeId);
508
509
  return device?.id;
509
510
  }