@apocaliss92/scrypted-reolink-native 0.1.21 → 0.1.23

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.1.21",
3
+ "version": "0.1.23",
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/multifocal.ts CHANGED
@@ -61,6 +61,8 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
61
61
  cameraNativeMap = new Map<string, ReolinkNativeCamera | ReolinkNativeBatteryCamera>();
62
62
  private channelToNativeIdMap = new Map<number, string>();
63
63
  processing = false;
64
+ private syncInProgress = false;
65
+ private syncPromise: Promise<void> | undefined;
64
66
  private initReinitTimeout: NodeJS.Timeout | undefined;
65
67
 
66
68
  constructor(nativeId: string, plugin: ReolinkNativePlugin, transport: BaichuanTransport = 'tcp') {
@@ -197,85 +199,102 @@ export class ReolinkNativeMultiFocalDevice extends BaseBaichuanClass implements
197
199
  }
198
200
 
199
201
  async syncEntitiesFromRemote() {
200
- const api = await this.ensureBaichuanClient();
201
- const logger = this.getBaichuanLogger();
202
+ // If sync is already in progress, wait for it to complete
203
+ if (this.syncInProgress && this.syncPromise) {
204
+ const logger = this.getBaichuanLogger();
205
+ logger.debug('Sync already in progress, waiting for completion...');
206
+ await this.syncPromise;
207
+ return;
208
+ }
202
209
 
203
- try {
204
- // const channelsInfo = await api.getNvrChannelsInfo();
205
- // const deviceInfo = await api.getInfo();
206
- const { support } = await api.getDeviceCapabilities();
207
- const channelNum = support?.channelNum ?? 1;
208
- logger.log(`Sync entities from remote for ${channelNum} channels`);
209
- const channels = Array.from({ length: channelNum }, (_, i) => i + 1);
210
-
211
- const multifocalInfo = await api.getDualLensChannelInfo();
212
-
213
- logger.log(`Multichannel info: ${JSON.stringify(multifocalInfo)}`);
214
-
215
- // if (channelNum === 2) {
216
-
217
- // }
218
-
219
- for (const channel of channels) {
220
- // try {
221
- // const name = deviceInfo?.name || `Channel ${channel}`;
222
- // const uid = deviceInfo?.uid;
223
- // const isBattery = !!(abilities?.battery?.ver ?? 0);
224
-
225
- // const nativeId = this.buildNativeId(channel, uid, isBattery);
226
- // const interfaces = [ScryptedInterface.VideoCamera];
227
- // if (isBattery) {
228
- // interfaces.push(ScryptedInterface.Battery);
229
- // }
230
- // const type = abilities.supportDoorbellLight ? ScryptedDeviceType.Doorbell : ScryptedDeviceType.Camera;
231
-
232
- // const device: Device = {
233
- // nativeId,
234
- // name,
235
- // providerNativeId: this.nativeId,
236
- // interfaces,
237
- // type,
238
- // info: {
239
- // manufacturer: 'Reolink',
240
- // model: channelInfo?.typeInfo,
241
- // serialNumber: uid,
242
- // }
243
- // };
244
-
245
- // this.channelToNativeIdMap.set(channel, nativeId);
246
-
247
- // if (sdk.deviceManager.getNativeIds().includes(nativeId)) {
248
- // continue;
249
- // }
250
-
251
- // if (this.discoveredDevices.has(nativeId)) {
252
- // continue;
253
- // }
254
-
255
- // this.discoveredDevices.set(nativeId, {
256
- // device,
257
- // description: `${name} (Channel ${channel})`,
258
- // rtspChannel: channel,
259
- // deviceData: devicesData[channel],
260
- // });
261
-
262
- // logger.debug(`Discovered channel ${channel}: ${name}`);
263
- // } catch (e: any) {
264
- // logger.debug(`Error processing channel ${channel}: ${e?.message || String(e)}`);
265
- // }
266
- }
210
+ // Start new sync
211
+ this.syncInProgress = true;
212
+ this.syncPromise = (async () => {
213
+ const api = await this.ensureBaichuanClient();
214
+ const logger = this.getBaichuanLogger();
267
215
 
268
- // logger.log(`Channel discovery completed. ${JSON.stringify({ devicesData, channels })}`);
269
- } catch (e) {
270
- logger.error('Failed to sync entities from remote', e);
271
- if (e instanceof Error) {
272
- logger.error(`Error in syncEntitiesFromRemote: ${e.message}`);
273
- logger.error(`Stack: ${e.stack}`);
274
- } else {
275
- logger.error(`Error details: ${JSON.stringify(e)}`);
216
+ try {
217
+ // const channelsInfo = await api.getNvrChannelsInfo();
218
+ // const deviceInfo = await api.getInfo();
219
+ const { support, abilities, features, capabilities } = await api.getDeviceCapabilities();
220
+ const channelNum = support?.channelNum ?? 1;
221
+ logger.log(`Sync entities from remote for ${channelNum} channels`);
222
+ const channels = Array.from({ length: channelNum }, (_, i) => i + 1);
223
+
224
+ const multifocalInfo = await api.getDualLensChannelInfo();
225
+
226
+ logger.log(`Multichannel info: ${JSON.stringify({ multifocalInfo, abilities, features, capabilities })}`);
227
+
228
+ // if (channelNum === 2) {
229
+
230
+ // }
231
+
232
+ for (const channel of channels) {
233
+ // try {
234
+ // const name = deviceInfo?.name || `Channel ${channel}`;
235
+ // const uid = deviceInfo?.uid;
236
+ // const isBattery = !!(abilities?.battery?.ver ?? 0);
237
+
238
+ // const nativeId = this.buildNativeId(channel, uid, isBattery);
239
+ // const interfaces = [ScryptedInterface.VideoCamera];
240
+ // if (isBattery) {
241
+ // interfaces.push(ScryptedInterface.Battery);
242
+ // }
243
+ // const type = abilities.supportDoorbellLight ? ScryptedDeviceType.Doorbell : ScryptedDeviceType.Camera;
244
+
245
+ // const device: Device = {
246
+ // nativeId,
247
+ // name,
248
+ // providerNativeId: this.nativeId,
249
+ // interfaces,
250
+ // type,
251
+ // info: {
252
+ // manufacturer: 'Reolink',
253
+ // model: channelInfo?.typeInfo,
254
+ // serialNumber: uid,
255
+ // }
256
+ // };
257
+
258
+ // this.channelToNativeIdMap.set(channel, nativeId);
259
+
260
+ // if (sdk.deviceManager.getNativeIds().includes(nativeId)) {
261
+ // continue;
262
+ // }
263
+
264
+ // if (this.discoveredDevices.has(nativeId)) {
265
+ // continue;
266
+ // }
267
+
268
+ // this.discoveredDevices.set(nativeId, {
269
+ // device,
270
+ // description: `${name} (Channel ${channel})`,
271
+ // rtspChannel: channel,
272
+ // deviceData: devicesData[channel],
273
+ // });
274
+
275
+ // logger.debug(`Discovered channel ${channel}: ${name}`);
276
+ // } catch (e: any) {
277
+ // logger.debug(`Error processing channel ${channel}: ${e?.message || String(e)}`);
278
+ // }
279
+ }
280
+
281
+ // logger.log(`Channel discovery completed. ${JSON.stringify({ devicesData, channels })}`);
282
+ } catch (e) {
283
+ logger.error('Failed to sync entities from remote', e);
284
+ if (e instanceof Error) {
285
+ logger.error(`Error in syncEntitiesFromRemote: ${e.message}`);
286
+ logger.error(`Stack: ${e.stack}`);
287
+ } else {
288
+ logger.error(`Error details: ${JSON.stringify(e)}`);
289
+ }
290
+ throw e;
291
+ } finally {
292
+ this.syncInProgress = false;
293
+ this.syncPromise = undefined;
276
294
  }
277
- throw e;
278
- }
295
+ })();
296
+
297
+ await this.syncPromise;
279
298
  }
280
299
 
281
300
  async discoverDevices(scan?: boolean): Promise<DiscoveredDevice[]> {