@camstack/addon-provider-reolink 1.2.35 → 1.2.37

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/addon.js CHANGED
@@ -230966,10 +230966,13 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230966
230966
  const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
230967
230967
  const parent = await this.getParentHub();
230968
230968
  let confirmed = false;
230969
+ let observedAwake = false;
230969
230970
  while (Date.now() < confirmDeadline) {
230970
230971
  if (parent !== null) try {
230971
- if ((await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel())?.sleeping === false) {
230972
+ const entry = (await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel());
230973
+ if (entry !== void 0 && entry.online !== false) {
230972
230974
  confirmed = true;
230975
+ observedAwake = entry.sleeping === false;
230973
230976
  break;
230974
230977
  }
230975
230978
  } catch {}
@@ -230982,13 +230985,14 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230982
230985
  }
230983
230986
  if (state === "awake") {
230984
230987
  confirmed = true;
230988
+ observedAwake = true;
230985
230989
  break;
230986
230990
  }
230987
230991
  }
230988
230992
  await sleep$1(CONFIRM_POLL_MS);
230989
230993
  }
230990
230994
  const confirmSource = parent !== null ? "hub-summary" : "sleep-poll";
230991
- if (confirmed && this.commitSleepState(false, confirmSource)) {
230995
+ if (observedAwake && this.commitSleepState(false, confirmSource)) {
230992
230996
  this.ctx.logger.info("battery wakeForStream: wake confirmed — driving wake transition", {
230993
230997
  tags: { deviceId: this.id },
230994
230998
  meta: {
@@ -231008,6 +231012,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231008
231012
  durationMs: Date.now() - startedAt
231009
231013
  };
231010
231014
  }
231015
+ if (confirmed && !observedAwake && parent !== null) this.watchHubChildAwake(parent).catch(() => {});
231011
231016
  return {
231012
231017
  awoke: true,
231013
231018
  durationMs: Date.now() - startedAt
@@ -231186,6 +231191,29 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231186
231191
  this.lastProactiveWakeAt = Date.now();
231187
231192
  }
231188
231193
  /**
231194
+ * Post-confirm watch for a hub child whose wake lands on the consumer's
231195
+ * relay dial: re-read the parent's channel summary a few times over the
231196
+ * dial's wake window and commit `sleeping: false` the moment the firmware
231197
+ * reports it. Ends EARLY once committed; bounded hard so a dead link can't
231198
+ * leak a timer. Costs the camera nothing — the summary is the hub's own
231199
+ * mains-powered read.
231200
+ */
231201
+ async watchHubChildAwake(parent) {
231202
+ const deadline = Date.now() + 45e3;
231203
+ while (Date.now() < deadline) {
231204
+ await sleep$1(5e3);
231205
+ try {
231206
+ if ((await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel())?.sleeping === false) {
231207
+ if (this.commitSleepState(false, "hub-summary")) {
231208
+ this.ctx.logger.info("battery wakeForStream: hub child observed awake after the dial", { tags: { deviceId: this.id } });
231209
+ this.onWakeTransition("hub-summary").catch(() => {});
231210
+ }
231211
+ return;
231212
+ }
231213
+ } catch {}
231214
+ }
231215
+ }
231216
+ /**
231189
231217
  * Close the transient "waking" window on a wake that did NOT produce a
231190
231218
  * committed transition (ACK with no awake evidence, or a timeout).
231191
231219
  * `BatteryOnWakeStarted` opens it; normally the `sleeping: false` commit
@@ -236647,6 +236675,14 @@ function computeHealthCheckBackoffMs(consecutive) {
236647
236675
  //#endregion
236648
236676
  //#region src/reolink-hub.ts
236649
236677
  var HUB_DISCOVERY_REFRESH_TIMEOUT_MS = 8e3;
236678
+ /**
236679
+ * How often the hub re-reads its own channels summary to reconcile the
236680
+ * adopted children's sleep slices. 60 s: a naturally-waking camera (PIR,
236681
+ * schedule) is caught within a minute, and the play path has its own
236682
+ * faster confirm + post-dial watch, so this only ever carries background
236683
+ * drift. Never wakes a child — the summary is answered by the hub itself.
236684
+ */
236685
+ var HUB_CHILD_SLEEP_RECONCILE_MS = 6e4;
236650
236686
  var HUB_RECONNECT_BASE_MS = 2e3;
236651
236687
  var HUB_RECONNECT_MAX_MS = 3e4;
236652
236688
  /**
@@ -236680,6 +236716,8 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236680
236716
  connectInFlight = null;
236681
236717
  reconnectAttempts = 0;
236682
236718
  reconnectTimer = null;
236719
+ /** Periodic child-sleep reconcile timer (armed in `onActivate`). */
236720
+ sleepReconcileTimer = null;
236683
236721
  shutdownRequested = false;
236684
236722
  /** Diagnostic Sessions snapshot — same shape as the camera's. */
236685
236723
  sessionsSnapshot = null;
@@ -236764,6 +236802,10 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236764
236802
  this.ctx.logger.info("Reolink Hub: child unregistered externally — refreshing discovery", cid !== null ? { tags: { deviceId: cid } } : {});
236765
236803
  this.refreshDiscoveryFromCamera().catch(() => {});
236766
236804
  }));
236805
+ this.sleepReconcileTimer = setInterval(() => {
236806
+ this.refreshDiscoveryFromCamera().catch(() => {});
236807
+ }, HUB_CHILD_SLEEP_RECONCILE_MS);
236808
+ if (typeof this.sleepReconcileTimer.unref === "function") this.sleepReconcileTimer.unref();
236767
236809
  }
236768
236810
  eventUnsubscribers = [];
236769
236811
  /** Per-channel throttle for the unrouted-event warning (see
@@ -236775,6 +236817,10 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236775
236817
  clearTimeout(this.reconnectTimer);
236776
236818
  this.reconnectTimer = null;
236777
236819
  }
236820
+ if (this.sleepReconcileTimer) {
236821
+ clearInterval(this.sleepReconcileTimer);
236822
+ this.sleepReconcileTimer = null;
236823
+ }
236778
236824
  for (const unsub of this.eventUnsubscribers) try {
236779
236825
  unsub();
236780
236826
  } catch {}
package/dist/addon.mjs CHANGED
@@ -230946,10 +230946,13 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230946
230946
  const confirmDeadline = Date.now() + CONFIRM_TIMEOUT_MS;
230947
230947
  const parent = await this.getParentHub();
230948
230948
  let confirmed = false;
230949
+ let observedAwake = false;
230949
230950
  while (Date.now() < confirmDeadline) {
230950
230951
  if (parent !== null) try {
230951
- if ((await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel())?.sleeping === false) {
230952
+ const entry = (await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel());
230953
+ if (entry !== void 0 && entry.online !== false) {
230952
230954
  confirmed = true;
230955
+ observedAwake = entry.sleeping === false;
230953
230956
  break;
230954
230957
  }
230955
230958
  } catch {}
@@ -230962,13 +230965,14 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230962
230965
  }
230963
230966
  if (state === "awake") {
230964
230967
  confirmed = true;
230968
+ observedAwake = true;
230965
230969
  break;
230966
230970
  }
230967
230971
  }
230968
230972
  await sleep$1(CONFIRM_POLL_MS);
230969
230973
  }
230970
230974
  const confirmSource = parent !== null ? "hub-summary" : "sleep-poll";
230971
- if (confirmed && this.commitSleepState(false, confirmSource)) {
230975
+ if (observedAwake && this.commitSleepState(false, confirmSource)) {
230972
230976
  this.ctx.logger.info("battery wakeForStream: wake confirmed — driving wake transition", {
230973
230977
  tags: { deviceId: this.id },
230974
230978
  meta: {
@@ -230988,6 +230992,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230988
230992
  durationMs: Date.now() - startedAt
230989
230993
  };
230990
230994
  }
230995
+ if (confirmed && !observedAwake && parent !== null) this.watchHubChildAwake(parent).catch(() => {});
230991
230996
  return {
230992
230997
  awoke: true,
230993
230998
  durationMs: Date.now() - startedAt
@@ -231166,6 +231171,29 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231166
231171
  this.lastProactiveWakeAt = Date.now();
231167
231172
  }
231168
231173
  /**
231174
+ * Post-confirm watch for a hub child whose wake lands on the consumer's
231175
+ * relay dial: re-read the parent's channel summary a few times over the
231176
+ * dial's wake window and commit `sleeping: false` the moment the firmware
231177
+ * reports it. Ends EARLY once committed; bounded hard so a dead link can't
231178
+ * leak a timer. Costs the camera nothing — the summary is the hub's own
231179
+ * mains-powered read.
231180
+ */
231181
+ async watchHubChildAwake(parent) {
231182
+ const deadline = Date.now() + 45e3;
231183
+ while (Date.now() < deadline) {
231184
+ await sleep$1(5e3);
231185
+ try {
231186
+ if ((await (await parent.getApi()).getNvrChannelsSummary({ channels: [this.getChannel()] })).devices.find((d) => d.channel === this.getChannel())?.sleeping === false) {
231187
+ if (this.commitSleepState(false, "hub-summary")) {
231188
+ this.ctx.logger.info("battery wakeForStream: hub child observed awake after the dial", { tags: { deviceId: this.id } });
231189
+ this.onWakeTransition("hub-summary").catch(() => {});
231190
+ }
231191
+ return;
231192
+ }
231193
+ } catch {}
231194
+ }
231195
+ }
231196
+ /**
231169
231197
  * Close the transient "waking" window on a wake that did NOT produce a
231170
231198
  * committed transition (ACK with no awake evidence, or a timeout).
231171
231199
  * `BatteryOnWakeStarted` opens it; normally the `sleeping: false` commit
@@ -236627,6 +236655,14 @@ function computeHealthCheckBackoffMs(consecutive) {
236627
236655
  //#endregion
236628
236656
  //#region src/reolink-hub.ts
236629
236657
  var HUB_DISCOVERY_REFRESH_TIMEOUT_MS = 8e3;
236658
+ /**
236659
+ * How often the hub re-reads its own channels summary to reconcile the
236660
+ * adopted children's sleep slices. 60 s: a naturally-waking camera (PIR,
236661
+ * schedule) is caught within a minute, and the play path has its own
236662
+ * faster confirm + post-dial watch, so this only ever carries background
236663
+ * drift. Never wakes a child — the summary is answered by the hub itself.
236664
+ */
236665
+ var HUB_CHILD_SLEEP_RECONCILE_MS = 6e4;
236630
236666
  var HUB_RECONNECT_BASE_MS = 2e3;
236631
236667
  var HUB_RECONNECT_MAX_MS = 3e4;
236632
236668
  /**
@@ -236660,6 +236696,8 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236660
236696
  connectInFlight = null;
236661
236697
  reconnectAttempts = 0;
236662
236698
  reconnectTimer = null;
236699
+ /** Periodic child-sleep reconcile timer (armed in `onActivate`). */
236700
+ sleepReconcileTimer = null;
236663
236701
  shutdownRequested = false;
236664
236702
  /** Diagnostic Sessions snapshot — same shape as the camera's. */
236665
236703
  sessionsSnapshot = null;
@@ -236744,6 +236782,10 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236744
236782
  this.ctx.logger.info("Reolink Hub: child unregistered externally — refreshing discovery", cid !== null ? { tags: { deviceId: cid } } : {});
236745
236783
  this.refreshDiscoveryFromCamera().catch(() => {});
236746
236784
  }));
236785
+ this.sleepReconcileTimer = setInterval(() => {
236786
+ this.refreshDiscoveryFromCamera().catch(() => {});
236787
+ }, HUB_CHILD_SLEEP_RECONCILE_MS);
236788
+ if (typeof this.sleepReconcileTimer.unref === "function") this.sleepReconcileTimer.unref();
236747
236789
  }
236748
236790
  eventUnsubscribers = [];
236749
236791
  /** Per-channel throttle for the unrouted-event warning (see
@@ -236755,6 +236797,10 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236755
236797
  clearTimeout(this.reconnectTimer);
236756
236798
  this.reconnectTimer = null;
236757
236799
  }
236800
+ if (this.sleepReconcileTimer) {
236801
+ clearInterval(this.sleepReconcileTimer);
236802
+ this.sleepReconcileTimer = null;
236803
+ }
236758
236804
  for (const unsub of this.eventUnsubscribers) try {
236759
236805
  unsub();
236760
236806
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.35",
3
+ "version": "1.2.37",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",