@apocaliss92/scrypted-reolink-native 0.1.24 → 0.1.26

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/multiFocal.ts CHANGED
@@ -1,110 +1,50 @@
1
1
  import type { DeviceCapabilities, DualLensChannelAnalysis, ReolinkSimpleEvent } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
2
- import sdk, { Device, DeviceProvider, Reboot, ScryptedDeviceType, Setting, Settings, SettingValue } from "@scrypted/sdk";
3
- import { StorageSettings } from "@scrypted/sdk/storage-settings";
4
- import { BaseBaichuanClass, type BaichuanConnectionCallbacks, type BaichuanConnectionConfig } from "./baichuan-base";
2
+ import sdk, { Device, DeviceProvider, MediaObject, Reboot, ScryptedDeviceType, Setting, Settings, SettingValue } from "@scrypted/sdk";
3
+ import { type BaichuanConnectionCallbacks } from "./baichuan-base";
5
4
  import { ReolinkNativeCamera } from "./camera";
6
5
  import { ReolinkNativeBatteryCamera } from "./camera-battery";
7
- import { normalizeUid } from "./connect";
6
+ import { CameraType, CommonCameraMixin } from "./common";
8
7
  import ReolinkNativePlugin from "./main";
9
8
  import { batteryCameraSuffix, cameraSuffix, getDeviceInterfaces, updateDeviceInfo } from "./utils";
10
9
 
11
- export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements Settings, DeviceProvider, Reboot {
12
- storageSettings = new StorageSettings(this, {
13
- debugEvents: {
14
- title: 'Debug Events',
15
- type: 'boolean',
16
- immediate: true,
17
- },
18
- ipAddress: {
19
- title: 'IP address',
20
- type: 'string',
21
- onPut: async () => await this.reinit()
22
- },
23
- username: {
24
- title: 'Username',
25
- placeholder: 'admin',
26
- defaultValue: 'admin',
27
- type: 'string',
28
- onPut: async () => await this.reinit()
29
- },
30
- password: {
31
- title: 'Password',
32
- type: 'password',
33
- onPut: async () => await this.reinit()
34
- },
35
- uid: {
36
- title: 'UID',
37
- description: 'Reolink UID (required for UDP/battery multi-focal devices)',
38
- type: 'string',
39
- hide: true,
40
- onPut: async () => await this.reinit()
41
- },
42
- protocol: {
43
- type: 'string',
44
- hide: true,
45
- },
46
- diagnosticsRun: {
47
- subgroup: 'Diagnostics',
48
- title: 'Run Diagnostics',
49
- description: 'Collect diagnostics and display results in logs.',
50
- type: 'button',
51
- immediate: true,
52
- onPut: async () => {
53
- await this.runDiagnostics();
54
- },
55
- },
56
- multifocalInfo: {
57
- json: true,
58
- hide: true,
59
- },
60
- capabilities: {
61
- json: true,
62
- hide: true,
63
- }
64
- });
65
-
10
+ export class ReolinkNativeMultiFocalDevice extends CommonCameraMixin implements Settings, DeviceProvider, Reboot {
66
11
  plugin: ReolinkNativePlugin;
67
12
  cameraNativeMap = new Map<string, ReolinkNativeCamera | ReolinkNativeBatteryCamera>();
68
13
  private channelToNativeIdMap = new Map<number, string>();
69
14
  private initReinitTimeout: NodeJS.Timeout | undefined;
70
15
  isBattery: boolean;
71
16
 
72
- constructor(nativeId: string, plugin: ReolinkNativePlugin) {
73
- super(nativeId);
17
+ constructor(nativeId: string, plugin: ReolinkNativePlugin, type: CameraType) {
18
+ super(nativeId, plugin, { type });
74
19
  this.plugin = plugin;
75
20
 
76
- this.isBattery = this.storageSettings.values.protocol === 'udp';
77
-
78
21
  this.scheduleInit();
79
22
  }
80
23
 
24
+ getAbilities(): DeviceCapabilities {
25
+ const { capabilities } = this.storageSettings.values;
26
+
27
+ return {
28
+ ...capabilities,
29
+ hasPan: false,
30
+ hasTilt: false,
31
+ hasZoom: false,
32
+ hasPresets: false,
33
+ hasIntercom: false,
34
+ }
35
+ }
36
+
81
37
  async reboot(): Promise<void> {
82
38
  const api = await this.ensureBaichuanClient();
83
39
  await api.reboot();
84
40
  }
85
41
 
86
- protected getConnectionConfig(): BaichuanConnectionConfig {
87
- const { ipAddress, username, password, uid } = this.storageSettings.values;
88
- if (!ipAddress || !username || !password) {
89
- throw new Error('Missing device credentials');
90
- }
91
-
92
- const { protocol } = this.storageSettings.values;
93
-
94
- const normalizedUid = this.isBattery ? normalizeUid(uid) : undefined;
95
-
96
- if (protocol === 'udp' && !normalizedUid) {
97
- throw new Error('UID is required for UDP multi-focal devices (BCUDP)');
98
- }
42
+ takePicture(options?: any): Promise<MediaObject> {
43
+ throw new Error("Method not implemented.");
44
+ }
99
45
 
100
- return {
101
- host: ipAddress,
102
- username,
103
- password,
104
- uid: normalizedUid,
105
- transport: protocol,
106
- logger: this.console,
107
- };
46
+ getPictureOptions(): Promise<any[]> {
47
+ throw new Error("Method not implemented.");
108
48
  }
109
49
 
110
50
  protected getConnectionCallbacks(): BaichuanConnectionCallbacks {
@@ -134,7 +74,7 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
134
74
  }
135
75
 
136
76
  protected isDebugEnabled(): boolean {
137
- return this.storageSettings.values.debugEvents;
77
+ return this.storageSettings.values.debugEvents || false;
138
78
  }
139
79
 
140
80
  protected getDeviceName(): string {
@@ -199,9 +139,8 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
199
139
  device: this,
200
140
  deviceData,
201
141
  ipAddress: this.storageSettings.values.ipAddress,
142
+ logger,
202
143
  });
203
-
204
- logger.log(`Device info updated: ${JSON.stringify(deviceData)}`);
205
144
  } catch (e) {
206
145
  logger.warn('Failed to fetch device info', e);
207
146
  }
@@ -232,7 +171,7 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
232
171
  async reportDevices(): Promise<void> {
233
172
  const api = await this.ensureBaichuanClient();
234
173
  const logger = this.getBaichuanLogger();
235
- const { protocol, username, password, ipAddress, uid } = this.storageSettings.values;
174
+ const { username, password, ipAddress, uid } = this.storageSettings.values;
236
175
 
237
176
  const { capabilities, support, abilities, features, objects, presets } = await api.getDeviceCapabilities();
238
177
 
@@ -286,16 +225,19 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
286
225
  }
287
226
 
288
227
  async getDevice(nativeId: string) {
289
- let device = this.cameraNativeMap.get(nativeId);
290
- if (!device) {
291
- if (nativeId.endsWith(batteryCameraSuffix)) {
292
- device = new ReolinkNativeBatteryCamera(nativeId, this.plugin, undefined, this);
293
- } else {
294
- device = new ReolinkNativeCamera(nativeId, this.plugin, undefined, this);
228
+ if (nativeId.endsWith(cameraSuffix) || nativeId.endsWith(batteryCameraSuffix)) {
229
+ let device = this.cameraNativeMap.get(nativeId);
230
+ if (!device) {
231
+ if (nativeId.endsWith(batteryCameraSuffix)) {
232
+ device = new ReolinkNativeBatteryCamera(nativeId, this.plugin, undefined, this);
233
+ } else {
234
+ device = new ReolinkNativeCamera(nativeId, this.plugin, undefined, this);
235
+ }
295
236
  }
237
+ return device;
238
+ } else {
239
+ return super.getDevice(nativeId);
296
240
  }
297
-
298
- return device;
299
241
  }
300
242
 
301
243
  async getSettings(): Promise<Setting[]> {
@@ -309,11 +251,11 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
309
251
 
310
252
  async releaseDevice(id: string, nativeId: string) {
311
253
  this.cameraNativeMap.delete(nativeId);
254
+ super.releaseDevice(id, nativeId);
312
255
  }
313
256
 
314
257
  buildNativeId(channel: number): string {
315
- const { protocol } = this.storageSettings.values;
316
- return `${this.nativeId}-channel${channel}${protocol === "udp" ? batteryCameraSuffix : cameraSuffix}`;
258
+ return `${this.nativeId}-channel${channel}`;
317
259
  }
318
260
 
319
261
  forwardNativeEvent(ev: ReolinkSimpleEvent): void {
@@ -337,16 +279,14 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
337
279
  return;
338
280
  }
339
281
 
340
- // Forward event to camera
341
- if (camera.onSimpleEvent) {
342
- camera.onSimpleEvent(ev);
343
- }
282
+ camera.onSimpleEvent(ev);
344
283
  }
284
+
345
285
  async unsubscribeFromAllEvents(): Promise<void> {
346
286
  await super.unsubscribeFromEvents();
347
287
  }
348
288
 
349
- private async runDiagnostics(): Promise<void> {
289
+ public async runDiagnostics(): Promise<void> {
350
290
  const logger = this.getBaichuanLogger();
351
291
  logger.log(`Starting Multifocal diagnostics...`);
352
292
 
package/src/nvr.ts CHANGED
@@ -360,7 +360,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
360
360
  this.lastNvrInfoCheck = now;
361
361
  const { nvrData } = await api.getNvrInfo();
362
362
  const { devicesData, channelsResponse, response } = await api.getDevicesInfo();
363
- logger.log(`NVR info data fetched: ${JSON.stringify({ nvrData, devicesData, channelsResponse, response })}`);
363
+ logger.log(`NVR info data fetched`);
364
+ logger.debug(`${JSON.stringify({ nvrData, devicesData, channelsResponse, response })}`);
364
365
 
365
366
  await this.discoverDevices(true);
366
367
  }
@@ -372,7 +373,6 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
372
373
  this.forwardCgiEvents(eventsRes.parsed);
373
374
  }
374
375
 
375
- // Always fetch battery info (not event-related)
376
376
  const { batteryInfoData, response } = await api.getAllChannelsBatteryInfo();
377
377
 
378
378
  logger.debug(`Battery info call result: ${JSON.stringify({ batteryInfoData, response })}`);
@@ -411,9 +411,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
411
411
  device: this,
412
412
  ipAddress,
413
413
  deviceData,
414
+ logger
414
415
  });
415
-
416
- logger.log(`Device info updated: ${JSON.stringify(deviceData)}`);
417
416
  } catch (e) {
418
417
  logger.warn('Failed to fetch device info', e);
419
418
  }
@@ -552,7 +551,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
552
551
  }
553
552
  }
554
553
 
555
- logger.log(`Channel discovery completed. ${JSON.stringify({ devicesData, channels })}`);
554
+ logger.debug(`Channel discovery completed. ${JSON.stringify({ devicesData, channels })}`);
556
555
  }
557
556
 
558
557
  async discoverDevices(scan?: boolean): Promise<DiscoveredDevice[]> {
@@ -606,7 +605,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
606
605
 
607
606
  const device = await this.getDevice(adopt.nativeId);
608
607
  const logger = this.getBaichuanLogger();
609
- logger.log('Adopted device', entry, device?.name);
608
+ logger.log('Adopted device', device?.name);
609
+ logger.log(JSON.stringify(entry));
610
610
  const { username, password, ipAddress } = this.storageSettings.values;
611
611
 
612
612
  device.storageSettings.values.rtspChannel = entry.rtspChannel;
package/src/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { DeviceCapabilities, ReolinkDeviceInfo } from "@apocaliss92/reolink-baichuan-js" with { "resolution-mode": "import" };
2
- import { DeviceBase, ScryptedDeviceType, ScryptedInterface } from "@scrypted/sdk";
2
+ import sdk, { Device, DeviceBase, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface } from "@scrypted/sdk";
3
3
 
4
4
  /**
5
5
  * Enumeration of operation types that may require specific channel assignments
@@ -23,7 +23,11 @@ export type OperationChannelMap = Partial<Record<OperationChannelType, number>>;
23
23
  export const nvrSuffix = `-nvr`;
24
24
  export const batteryCameraSuffix = `-battery-cam`;
25
25
  export const multifocalSuffix = `-multifocal`;
26
+ export const batteryMultifocalSuffix = `-battery-multifocal`;
26
27
  export const cameraSuffix = `-cam`;
28
+ export const sirenSuffix = `-siren`;
29
+ export const floodlightSuffix = `-floodlight`;
30
+ export const pirSuffix = `-pir`;
27
31
 
28
32
  export const getDeviceInterfaces = (props: {
29
33
  capabilities: DeviceCapabilities,
@@ -78,9 +82,10 @@ export const getDeviceInterfaces = (props: {
78
82
  export const updateDeviceInfo = async (props: {
79
83
  device: DeviceBase,
80
84
  ipAddress: string,
81
- deviceData: ReolinkDeviceInfo
85
+ deviceData: ReolinkDeviceInfo,
86
+ logger: Console
82
87
  }) => {
83
- const { device, ipAddress, deviceData } = props;
88
+ const { device, ipAddress, deviceData, logger } = props;
84
89
  try {
85
90
  const info = device.info || {};
86
91
 
@@ -101,5 +106,9 @@ export const updateDeviceInfo = async (props: {
101
106
  device.info = info;
102
107
 
103
108
  throw e;
109
+ } finally {
110
+
111
+ logger.log(`Device info updated`);
112
+ logger.debug(`${JSON.stringify({ newInfo: device.info, deviceData })}`);
104
113
  }
105
114
  }