@apocaliss92/scrypted-reolink-native 0.4.53 → 0.5.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.4.53",
3
+ "version": "0.5.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",
@@ -728,10 +728,20 @@ export abstract class BaseBaichuanClass extends ScryptedDeviceBase {
728
728
  return; // Connection changed, stop this interval
729
729
  }
730
730
 
731
- // If event subscription is not active, skip the library's
732
- // built-in event watchdog handles auto-recovery with exponential
733
- // backoff (including after reconnection / camera reboot).
731
+ // If event subscription is not active but the connection is live,
732
+ // attempt to re-subscribe. This handles the case where the camera
733
+ // rebooted and the onClose retries exhausted before it came back up,
734
+ // leaving a live socket with no active event subscription.
734
735
  if (!this.eventSubscriptionActive) {
736
+ if (this.baichuanApi?.client.isSocketConnected()) {
737
+ try {
738
+ await this.subscribeToEvents();
739
+ } catch (e) {
740
+ logger.debug(
741
+ `Event check: auto-subscribe attempt failed: ${e?.message || String(e)}`,
742
+ );
743
+ }
744
+ }
735
745
  return;
736
746
  }
737
747
 
package/src/camera.ts CHANGED
@@ -601,6 +601,19 @@ export class ReolinkCamera
601
601
  await this.runDiagnostics();
602
602
  },
603
603
  },
604
+ dumpModelFixtures: {
605
+ subgroup: "Diagnostics",
606
+ title: "Dump Model Fixtures",
607
+ description:
608
+ "Capture all API responses for this device and save as fixture files. " +
609
+ "Useful for regression testing and debugging capability detection.",
610
+ type: "button",
611
+ hide: true,
612
+ immediate: true,
613
+ onPut: async () => {
614
+ await this.dumpModelFixtures();
615
+ },
616
+ },
604
617
  // Multifocal composite stream PIP settings
605
618
  pipPosition: {
606
619
  title: "PIP Position",
@@ -1611,6 +1624,42 @@ export class ReolinkCamera
1611
1624
  }
1612
1625
  }
1613
1626
 
1627
+ async dumpModelFixtures(): Promise<void> {
1628
+ const logger = this.getBaichuanLogger();
1629
+ const channel = this.storageSettings.values.rtspChannel || 0;
1630
+ const basePath =
1631
+ this.storageSettings.values.diagnosticsOutputPath ||
1632
+ path.join(process.env.SCRYPTED_PLUGIN_VOLUME, "diagnostics", this.name);
1633
+ const outDir = path.join(basePath, "model-fixtures", `ch${channel}`);
1634
+
1635
+ logger.log(`Dumping model fixtures: channel=${channel}, outDir=${outDir}`);
1636
+
1637
+ try {
1638
+ const api = await this.ensureClient();
1639
+ const { captureModelFixtures: capture } =
1640
+ await import("@apocaliss92/reolink-baichuan-js");
1641
+ const result = await capture({
1642
+ api,
1643
+ channel,
1644
+ outDir,
1645
+ log: (...args: unknown[]) => logger.log(String(args.join(" "))),
1646
+ });
1647
+
1648
+ logger.log(
1649
+ `Model fixtures captured: ${result.summary.ok}/${result.summary.total} ok, ${result.summary.failed} failed`,
1650
+ );
1651
+ if (result.summary.errors.length) {
1652
+ logger.warn(
1653
+ `Failed calls:\n${result.summary.errors.map((e) => ` - ${e}`).join("\n")}`,
1654
+ );
1655
+ }
1656
+ logger.log(`Output: ${outDir}`);
1657
+ } catch (e) {
1658
+ logger.error("Failed to dump model fixtures", e?.message || String(e));
1659
+ throw e;
1660
+ }
1661
+ }
1662
+
1614
1663
  protected async onBeforeCleanup(): Promise<void> {
1615
1664
  // Unsubscribe from events if needed
1616
1665
  if (this.baichuanApi) {