@apocaliss92/scrypted-reolink-native 0.1.14 → 0.1.16

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.14",
3
+ "version": "0.1.16",
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/common.ts CHANGED
@@ -263,6 +263,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
263
263
  defaultValue: [],
264
264
  choices: getDebugLogChoices(),
265
265
  onPut: async (ov, value) => {
266
+ const logger = this.getBaichuanLogger();
266
267
  const oldApiOptions = getApiRelevantDebugLogs(ov || []);
267
268
  const newApiOptions = getApiRelevantDebugLogs(value || []);
268
269
 
@@ -288,7 +289,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
288
289
  // Trigger reconnection
289
290
  await this.ensureClient();
290
291
  } catch (e) {
291
- this.getBaichuanLogger().warn('Failed to reset client after debug logs change', e);
292
+ logger.warn('Failed to reset client after debug logs change', e);
292
293
  }
293
294
  }, 2000);
294
295
  }
@@ -566,16 +567,21 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
566
567
  onClose: async () => {
567
568
  // Reset client state on close
568
569
  // The base class already handles cleanup
569
- // Resubscribe to events after reconnection
570
- // Use setTimeout to allow the connection to be re-established first
571
- setTimeout(async () => {
572
- try {
573
- await this.subscribeToEvents();
574
- } catch (e) {
575
- const logger = this.getBaichuanLogger();
576
- logger.warn('Failed to resubscribe to events after reconnection', e);
577
- }
578
- }, 1000);
570
+ // For battery cameras, don't auto-resubscribe after idle disconnects
571
+ // (idle disconnects are normal for battery cameras to save power)
572
+ // Events will be resubscribed when ensureClient() is called for actual operations
573
+ const isBattery = this.options.type === 'battery';
574
+ if (!isBattery) {
575
+ // For non-battery cameras, resubscribe to events after reconnection
576
+ setTimeout(async () => {
577
+ try {
578
+ await this.subscribeToEvents();
579
+ } catch (e) {
580
+ const logger = this.getBaichuanLogger();
581
+ logger.warn('Failed to resubscribe to events after reconnection', e);
582
+ }
583
+ }, 1000);
584
+ }
579
585
  },
580
586
  onSimpleEvent: this.onSimpleEvent,
581
587
  getEventSubscriptionEnabled: () => this.isEventDispatchEnabled?.() ?? false,
@@ -686,6 +692,8 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
686
692
  }
687
693
 
688
694
  onSimpleEvent = (ev: ReolinkSimpleEvent) => {
695
+ const logger = this.getBaichuanLogger();
696
+
689
697
  try {
690
698
  const logger = this.getBaichuanLogger();
691
699
 
@@ -732,7 +740,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
732
740
  });
733
741
  }
734
742
  catch (e) {
735
- this.getBaichuanLogger().warn('Error in onSimpleEvent handler', e);
743
+ logger.warn('Error in onSimpleEvent handler', e);
736
744
  }
737
745
  }
738
746
 
@@ -827,6 +835,8 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
827
835
 
828
836
  // PanTiltZoom interface implementation
829
837
  async ptzCommand(command: PanTiltZoomCommand): Promise<void> {
838
+ const logger = this.getBaichuanLogger();
839
+
830
840
  const client = await this.ensureClient();
831
841
  if (!client) {
832
842
  return;
@@ -839,13 +849,13 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
839
849
  if (preset !== undefined && preset !== null) {
840
850
  const presetId = Number(preset);
841
851
  if (!Number.isFinite(presetId)) {
842
- this.getBaichuanLogger().warn(`Invalid PTZ preset id: ${preset}`);
852
+ logger.warn(`Invalid PTZ preset id: ${preset}`);
843
853
  return;
844
854
  }
845
855
  if (this.ptzPresets) {
846
856
  await this.ptzPresets.moveToPreset(presetId);
847
857
  } else {
848
- this.getBaichuanLogger().warn('PTZ presets not available');
858
+ logger.warn('PTZ presets not available');
849
859
  }
850
860
  return;
851
861
  }
@@ -880,14 +890,14 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
880
890
 
881
891
  const step = Number(this.storageSettings.values.ptzZoomStep);
882
892
  if (!Number.isFinite(step) || step <= 0) {
883
- this.getBaichuanLogger().warn('Invalid PTZ zoom step, using default 0.1');
893
+ logger.warn('Invalid PTZ zoom step, using default 0.1');
884
894
  return;
885
895
  }
886
896
 
887
897
  // Get current zoom factor and apply step
888
898
  const info = await client.getZoomFocus(channel);
889
899
  if (!info?.zoom) {
890
- this.getBaichuanLogger().warn('Zoom command requested but camera did not report zoom support.');
900
+ logger.warn('Zoom command requested but camera did not report zoom support.');
891
901
  return;
892
902
  }
893
903
 
@@ -1095,6 +1105,8 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1095
1105
  }
1096
1106
 
1097
1107
  async updateDeviceInfo(): Promise<void> {
1108
+ const logger = this.getBaichuanLogger();
1109
+
1098
1110
  const { ipAddress, rtspChannel } = this.storageSettings.values;
1099
1111
  try {
1100
1112
  const api = await this.ensureClient();
@@ -1105,8 +1117,10 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1105
1117
  ipAddress,
1106
1118
  deviceData,
1107
1119
  });
1120
+
1121
+ logger.log(`Device info updated: ${JSON.stringify(deviceData)}`);
1108
1122
  } catch (e) {
1109
- this.getBaichuanLogger().warn('Failed to fetch device info', e);
1123
+ logger.warn('Failed to fetch device info', e);
1110
1124
  }
1111
1125
  }
1112
1126
 
@@ -1182,6 +1196,8 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1182
1196
  * This should be called periodically for regular cameras and once when battery cameras wake up.
1183
1197
  */
1184
1198
  async alignAuxDevicesState(): Promise<void> {
1199
+ const logger = this.getBaichuanLogger();
1200
+
1185
1201
  const api = this.baichuanApi;
1186
1202
  if (!api) return;
1187
1203
 
@@ -1195,7 +1211,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1195
1211
  const sirenState = await api.getSiren(channel);
1196
1212
  this.siren.on = sirenState.enabled;
1197
1213
  } catch (e) {
1198
- this.getBaichuanLogger().debug('Failed to align siren state', e);
1214
+ logger.debug('Failed to align siren state', e);
1199
1215
  }
1200
1216
  }
1201
1217
 
@@ -1208,7 +1224,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1208
1224
  this.floodlight.brightness = wl.brightness;
1209
1225
  }
1210
1226
  } catch (e) {
1211
- this.getBaichuanLogger().debug('Failed to align floodlight state', e);
1227
+ logger.debug('Failed to align floodlight state', e);
1212
1228
  }
1213
1229
  }
1214
1230
 
@@ -1232,16 +1248,18 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1232
1248
  }
1233
1249
  }
1234
1250
  } catch (e) {
1235
- this.getBaichuanLogger().debug('Failed to align PIR state', e);
1251
+ logger.debug('Failed to align PIR state', e);
1236
1252
  }
1237
1253
  }
1238
1254
  } catch (e) {
1239
- this.getBaichuanLogger().debug('Failed to align auxiliary devices state', e);
1255
+ logger.debug('Failed to align auxiliary devices state', e);
1240
1256
  }
1241
1257
  }
1242
1258
 
1243
1259
  // Video stream helper methods
1244
1260
  protected addRtspCredentials(rtspUrl: string): string {
1261
+ const logger = this.getBaichuanLogger();
1262
+
1245
1263
  const { username, password } = this.storageSettings.values;
1246
1264
  if (!username) {
1247
1265
  return rtspUrl;
@@ -1266,7 +1284,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1266
1284
  return url.toString();
1267
1285
  } catch (e) {
1268
1286
  // If URL parsing fails, return original URL
1269
- this.getBaichuanLogger().warn('Failed to parse URL for credentials', e);
1287
+ logger.warn('Failed to parse URL for credentials', e);
1270
1288
  return rtspUrl;
1271
1289
  }
1272
1290
  }
@@ -1284,6 +1302,8 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1284
1302
  }
1285
1303
 
1286
1304
  protected async ensureNetPortCache(): Promise<void> {
1305
+ const logger = this.getBaichuanLogger();
1306
+
1287
1307
  if (this.cachedNetPort) {
1288
1308
  return;
1289
1309
  }
@@ -1307,7 +1327,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1307
1327
  } catch (e) {
1308
1328
  // Only log if it's not a recoverable error to avoid spam
1309
1329
  if (!this.isRecoverableBaichuanError?.(e)) {
1310
- this.getBaichuanLogger().warn('Failed to get net port, using defaults', e);
1330
+ logger.warn('Failed to get net port, using defaults', e);
1311
1331
  }
1312
1332
  // Use defaults if we can't get the ports
1313
1333
  this.cachedNetPort = {
@@ -1363,7 +1383,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1363
1383
  }
1364
1384
 
1365
1385
  if (streams.length) {
1366
- this.getBaichuanLogger().log('Fetched video stream options', { streams, netPort: this.cachedNetPort });
1386
+ logger.log('Fetched video stream options', { streams, netPort: this.cachedNetPort });
1367
1387
  this.cachedVideoStreamOptions = streams;
1368
1388
  return streams;
1369
1389
  }
@@ -1492,14 +1512,14 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1492
1512
  info: this.info,
1493
1513
  };
1494
1514
 
1495
- this.getBaichuanLogger().log(`Updating device interfaces: ${JSON.stringify(device)}`);
1515
+ logger.log(`Updating device interfaces: ${JSON.stringify(device)}`);
1496
1516
 
1497
1517
  await sdk.deviceManager.onDeviceDiscovered(device);
1498
1518
  } catch (e) {
1499
- this.getBaichuanLogger().error('Failed to update device interfaces', e);
1519
+ logger.error('Failed to update device interfaces', e);
1500
1520
  }
1501
1521
 
1502
- this.getBaichuanLogger().log(`Refreshed device capabilities: ${JSON.stringify({ capabilities, abilities, support, presets })}`);
1522
+ logger.log(`Refreshed device capabilities: ${JSON.stringify({ capabilities, abilities, support, presets })}`);
1503
1523
  }
1504
1524
  catch (e) {
1505
1525
  logger.error('Failed to refresh abilities', e);
@@ -1561,7 +1581,7 @@ export abstract class CommonCameraMixin extends BaseBaichuanClass implements Vid
1561
1581
 
1562
1582
  this.streamManager = new StreamManager({
1563
1583
  createStreamClient: () => this.createStreamClient(),
1564
- getLogger: () => this.getBaichuanLogger() as Console,
1584
+ getLogger: () => logger as Console,
1565
1585
  credentials: {
1566
1586
  username,
1567
1587
  password
package/src/nvr.ts CHANGED
@@ -53,7 +53,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
53
53
  rtspChannel: number;
54
54
  deviceData: DeviceInfoResponse;
55
55
  }>();
56
- lastHubInfoCheck: number | undefined;
56
+ lastNvrInfoCheck: number | undefined;
57
57
  lastErrorsCheck: number | undefined;
58
58
  lastDevicesStatusCheck: number | undefined;
59
59
  cameraNativeMap = new Map<string, ReolinkNativeCamera | ReolinkNativeBatteryCamera>();
@@ -169,7 +169,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
169
169
  // Find camera for this channel
170
170
  const channel = ev?.channel;
171
171
  if (channel === undefined) {
172
- logger.debug('Event has no channel, ignoring');
172
+ logger.error('Event has no channel, ignoring');
173
173
  return;
174
174
  }
175
175
 
@@ -177,7 +177,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
177
177
  const targetCamera = nativeId ? this.cameraNativeMap.get(nativeId) : undefined;
178
178
 
179
179
  if (!targetCamera) {
180
- logger.debug(`No camera found for channel ${channel}, ignoring event`);
180
+ logger.error(`No camera found for channel ${channel}, ignoring event`);
181
181
  return;
182
182
  }
183
183
 
@@ -211,7 +211,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
211
211
  motion = true;
212
212
  break;
213
213
  default:
214
- logger.debug(`Unknown event type: ${ev?.type}`);
214
+ logger.error(`Unknown event type: ${ev?.type}`);
215
215
  return;
216
216
  }
217
217
 
@@ -309,13 +309,12 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
309
309
  // Note: ReolinkCgiApi doesn't have checkErrors, skip for now
310
310
  }
311
311
 
312
- if (!this.lastHubInfoCheck || now - this.lastHubInfoCheck > 1000 * 60 * 5) {
313
- logger.log('Starting Hub info data fetch');
314
- this.lastHubInfoCheck = now;
315
- const { hubData } = await api.getHubInfo();
312
+ if (!this.lastNvrInfoCheck || now - this.lastNvrInfoCheck > 1000 * 60 * 5) {
313
+ logger.log('Starting NVR info data fetch');
314
+ this.lastNvrInfoCheck = now;
315
+ const { nvrData } = await api.getNvrInfo();
316
316
  const { devicesData, channelsResponse, response } = await api.getDevicesInfo();
317
- logger.log('Hub info data fetched');
318
- logger.debug(`${JSON.stringify({ hubData, devicesData, channelsResponse, response })}`);
317
+ logger.log(`NVR info data fetched: ${JSON.stringify({ nvrData, devicesData, channelsResponse, response })}`);
319
318
 
320
319
  await this.discoverDevices(true);
321
320
  }
@@ -355,6 +354,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
355
354
  }
356
355
 
357
356
  async updateDeviceInfo(): Promise<void> {
357
+ const logger = this.getBaichuanLogger();
358
+
358
359
  const { ipAddress } = this.storageSettings.values;
359
360
  try {
360
361
  const api = await this.ensureClient();
@@ -365,8 +366,10 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
365
366
  ipAddress,
366
367
  deviceData,
367
368
  });
369
+
370
+ logger.log(`Device info updated: ${JSON.stringify(deviceData)}`);
368
371
  } catch (e) {
369
- this.getBaichuanLogger().warn('Failed to fetch device info', e);
372
+ logger.warn('Failed to fetch device info', e);
370
373
  }
371
374
  }
372
375
 
@@ -422,12 +425,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
422
425
  const api = await this.ensureClient();
423
426
  const logger = this.getBaichuanLogger();
424
427
 
425
- logger.log('Starting channels discovery using getDevicesInfo...');
426
-
427
428
  const { devicesData, channels } = await api.getDevicesInfo();
428
-
429
- logger.log(`getDevicesInfo completed. Found ${channels.length} channels.`);
430
-
429
+ logger.log(`Sync entities from remote for ${channels.length} channels`);
431
430
  // Process each channel that was successfully discovered
432
431
  for (const channel of channels) {
433
432
  try {
@@ -479,7 +478,7 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
479
478
  }
480
479
  }
481
480
 
482
- logger.log(`Channel discovery completed. Found ${this.discoveredDevices.size} devices.`);
481
+ logger.log(`Channel discovery completed. ${JSON.stringify({ devicesData, channels })}`);
483
482
  }
484
483
 
485
484
  async discoverDevices(scan?: boolean): Promise<DiscoveredDevice[]> {
@@ -532,7 +531,8 @@ export class ReolinkNativeNvrDevice extends BaseBaichuanClass implements Setting
532
531
  await sdk.deviceManager.onDeviceDiscovered(actualDevice);
533
532
 
534
533
  const device = await this.getDevice(adopt.nativeId);
535
- this.getBaichuanLogger().debug('Adopted device', entry, device?.name);
534
+ const logger = this.getBaichuanLogger();
535
+ logger.log('Adopted device', entry, device?.name);
536
536
  const { username, password, ipAddress } = this.storageSettings.values;
537
537
 
538
538
  device.storageSettings.values.rtspChannel = entry.rtspChannel;