@camstack/addon-provider-reolink 1.2.38 → 1.2.40

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.
Files changed (3) hide show
  1. package/dist/addon.js +132 -11
  2. package/dist/addon.mjs +132 -11
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -19789,7 +19789,14 @@ targets: array(object({
19789
19789
  "sleeping",
19790
19790
  "unreachable",
19791
19791
  "waking"
19792
- ]).nullable()
19792
+ ]).nullable(),
19793
+ /** A battery camera (whatever its current state). An AWAKE battery
19794
+ * camera is deliberately NOT recaptured on the poll cadence — every
19795
+ * capture is a camera hit that would keep it out of sleep — so its
19796
+ * cached frame legitimately ages past the currency ceiling while
19797
+ * nothing is streaming. A surface must keep painting it (a fresh
19798
+ * frame is captured at each wake), not blank to "unavailable". */
19799
+ battery: boolean()
19793
19800
  })))
19794
19801
  },
19795
19802
  status: {
@@ -230188,6 +230195,15 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230188
230195
  static WAKE_HYSTERESIS_MS = 3e4;
230189
230196
  static SLEEP_HYSTERESIS_MS = 5e3;
230190
230197
  /**
230198
+ * How long a freshly committed state is protected from a hub-summary
230199
+ * awake→sleeping flip. The summary's per-channel sleep flag lags real
230200
+ * pushes by over a minute (measured >75 s on 2026-08-16); 3 min covers
230201
+ * two full discovery-refresh cycles of lag without letting a genuinely
230202
+ * stuck "awake" slice stand forever — the reconcile still wins after
230203
+ * the grace, which is exactly its recovery role.
230204
+ */
230205
+ static HUB_SUMMARY_SLEEP_GRACE_MS = 18e4;
230206
+ /**
230191
230207
  * Wall-clock ms of the last PROACTIVE wake — one we issued on our own
230192
230208
  * initiative (background snapshot refresh), not because the operator
230193
230209
  * or a stream consumer asked for the camera. Drives
@@ -231167,15 +231183,35 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231167
231183
  *
231168
231184
  * @param source - `'hub-summary'` is AUTHORITATIVE (the NVR reports
231169
231185
  * per-channel sleep state from its own firmware, not from socket
231170
- * I/O inference) and therefore bypasses the hysteresis. The other
231171
- * two sources are inference-derived and stay gated.
231186
+ * I/O inference) and therefore bypasses the hysteresis with ONE
231187
+ * exception: the summary LAGS real push state (measured >75 s behind
231188
+ * an `awake` push, 2026-08-16), so an awake→sleeping flip from the
231189
+ * summary is refused while a fresher committed state is still inside
231190
+ * `HUB_SUMMARY_SLEEP_GRACE_MS`. Without the guard the 60 s reconcile
231191
+ * clobbered the fresh awake right back to sleeping for a full cycle —
231192
+ * the viewer flashed the live frame, then the sleeping overlay, then
231193
+ * live again. Sleeping→awake from the summary is always honoured
231194
+ * (it strands nothing; the camera wakes regardless).
231172
231195
  * @returns `true` when the slice actually changed.
231173
231196
  */
231174
231197
  commitSleepState(next, source) {
231175
231198
  if (!this.isBattery) return false;
231176
231199
  if (this.sleeping === next) return false;
231177
231200
  if (source !== "hub-summary" && !this.acceptSleepingTransition(next)) return false;
231178
- if (source === "hub-summary") this.sleepStateChangedAt = Date.now();
231201
+ if (source === "hub-summary") {
231202
+ const sinceCommitMs = Date.now() - this.sleepStateChangedAt;
231203
+ if (next === true && this.sleepStateChangedAt > 0 && sinceCommitMs < ReolinkCamera.HUB_SUMMARY_SLEEP_GRACE_MS) {
231204
+ this.ctx.logger.debug("hub-summary sleep flip refused — fresher state inside grace", {
231205
+ tags: { deviceId: this.id },
231206
+ meta: {
231207
+ sinceCommitMs,
231208
+ graceMs: ReolinkCamera.HUB_SUMMARY_SLEEP_GRACE_MS
231209
+ }
231210
+ });
231211
+ return false;
231212
+ }
231213
+ this.sleepStateChangedAt = Date.now();
231214
+ }
231179
231215
  this.state.battery.sleeping = next;
231180
231216
  this.ctx.logger.info("battery sleep state committed", {
231181
231217
  tags: { deviceId: this.id },
@@ -231315,13 +231351,42 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231315
231351
  });
231316
231352
  }
231317
231353
  /**
231354
+ * Hub-fed battery refresh for an adopted child. The parent's
231355
+ * `getAllChannelsBatteryInfo` CGI carries per-channel percent/charge
231356
+ * state over the hub's own mains-powered socket, so it costs the
231357
+ * battery channel nothing — this is how a hub child's
231358
+ * percentage/charging ever moves (a sleeping child answers no poll of
231359
+ * its own, and its pushes only arrive on firmware transitions).
231360
+ *
231361
+ * Deliberately does NOT stamp `lastContactAt`: the value is the HUB's
231362
+ * cached read of the channel, not proof the camera itself answered —
231363
+ * folding it into contact would mask a genuinely gone camera from the
231364
+ * unreachable derivation (that is what pushes and streams are for).
231365
+ * `sleeping` is likewise untouched — sleep state has its own writers
231366
+ * (pushes + the guarded hub-summary reconcile).
231367
+ */
231368
+ applyHubBatteryInfo(info) {
231369
+ if (!this.isBattery) return;
231370
+ const mapped = this.mapBatteryInfo({
231371
+ ...info.batteryPercent !== void 0 ? { batteryPercent: info.batteryPercent } : {},
231372
+ ...info.chargeStatus !== void 0 ? { chargeStatus: info.chargeStatus } : {},
231373
+ ...info.adapterStatus !== void 0 ? { adapterStatus: info.adapterStatus } : {}
231374
+ });
231375
+ this.setCapSlice(batteryCapability, {
231376
+ ...this.state.battery,
231377
+ percentage: mapped.percentage,
231378
+ charging: mapped.charging,
231379
+ lastUpdated: Date.now()
231380
+ });
231381
+ }
231382
+ /**
231318
231383
  * Battery cams require an explicit wake before cmd_id 109 will
231319
231384
  * answer reliably. The lib documents this pattern in
231320
- * `predownloadRecordingMp4` (`ensureAwake` → `wakeUp` →
231321
- * operation → retry with longer wait on failure). `getSnapshot`
231322
- * itself only re-`login()`s, which over BCUDP can complete before
231323
- * the camera firmware is fully up — the snapshot then times out
231324
- * because the video subsystem isn't ready yet.
231385
+ * `predownloadRecordingMp3`/`predownloadRecordingMp4` (`ensureAwake`
231386
+ * → `wakeUp` → operation → retry with longer wait on failure).
231387
+ * `getSnapshot` itself only re-`login()`s, which over BCUDP can
231388
+ * complete before the camera firmware is fully up — the snapshot then
231389
+ * times out because the video subsystem isn't ready yet.
231325
231390
  *
231326
231391
  * Probe live testing (scripts/probe-reolink-snapshot.mts) confirmed:
231327
231392
  * awake state: getSnapshot in ~1s
@@ -236775,6 +236840,12 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236775
236840
  * keeps the slice + map in sync after every change).
236776
236841
  */
236777
236842
  channelToDeviceId = /* @__PURE__ */ new Map();
236843
+ /** One-shot: the raw per-channel battery payload is logged once per
236844
+ * process so the firmware's charge-field naming is on record. */
236845
+ batteryShapeLogged = false;
236846
+ /** Channels the last successful discovery refresh listed as present but
236847
+ * NOT adopted — their pushes are expected drops (debug), not faults. */
236848
+ knownUnadoptedChannels = /* @__PURE__ */ new Set();
236778
236849
  /** Wall-clock ms of the last discovery refresh that included this
236779
236850
  * child's channel. Drives the offline marker — a child that hasn't
236780
236851
  * appeared in the firmware's channel list for `MISSING_OFFLINE_MS`
@@ -237188,6 +237259,11 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237188
237259
  };
237189
237260
  this.runtimeState.setCapState(deviceDiscoveryCapability.name, slice);
237190
237261
  if (lastError === null) {
237262
+ this.knownUnadoptedChannels.clear();
237263
+ for (const d of discovered) {
237264
+ const ch = d.metadata.rtspChannel;
237265
+ if (!d.alreadyAdopted && typeof ch === "number") this.knownUnadoptedChannels.add(ch);
237266
+ }
237191
237267
  const adoptedCount = discovered.filter((d) => d.alreadyAdopted).length;
237192
237268
  const availableCount = discovered.length - adoptedCount;
237193
237269
  const onlineCount = discovered.filter((d) => d.status === "online").length;
@@ -237211,6 +237287,49 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237211
237287
  if (lastError === null) {
237212
237288
  await this.reconcileAdoptedChildOnline(discovered);
237213
237289
  await this.reconcileAdoptedChildSleepState(discovered);
237290
+ await this.reconcileAdoptedChildBattery();
237291
+ }
237292
+ }
237293
+ /**
237294
+ * Push the hub's per-channel battery read into each adopted battery
237295
+ * child. `getAllChannelsBatteryInfo` is one CGI on the hub's own
237296
+ * mains-powered socket — it never touches a battery camera — and it is
237297
+ * the ONLY way a sleeping hub child's percentage/charging ever moves:
237298
+ * the child answers no poll of its own while asleep, and its battery
237299
+ * pushes arrive only on firmware transitions (measured live: 3628 sat
237300
+ * at 80% / charging:none for 3 h while plugged in, 2026-08-16).
237301
+ *
237302
+ * Independent of the discovery call's success path: a battery-read
237303
+ * failure must not fail discovery, so it is caught and logged here.
237304
+ */
237305
+ async reconcileAdoptedChildBattery() {
237306
+ if (this.channelToDeviceId.size === 0) return;
237307
+ try {
237308
+ const data = await (await this.ensureApi()).getAllChannelsBatteryInfo();
237309
+ const entries = Object.entries(data.batteryInfoData);
237310
+ if (entries.length === 0) return;
237311
+ if (!this.batteryShapeLogged) {
237312
+ this.batteryShapeLogged = true;
237313
+ this.ctx.logger.info("Reolink Hub: per-channel battery payload (first read)", { meta: { raw: entries.map(([ch, v]) => ({
237314
+ channel: Number(ch),
237315
+ ...v
237316
+ })) } });
237317
+ }
237318
+ const all = await this.ctx.devices.getAll();
237319
+ for (const [chKey, info] of entries) {
237320
+ const deviceId = this.channelToDeviceId.get(Number(chKey));
237321
+ if (deviceId === void 0) continue;
237322
+ const child = all.find((d) => d.id === deviceId);
237323
+ if (!(child instanceof ReolinkCamera)) continue;
237324
+ const cgi = info.entries[0];
237325
+ child.applyHubBatteryInfo({
237326
+ batteryPercent: info.batteryLevel,
237327
+ ...typeof cgi?.["chargeStatus"] === "string" ? { chargeStatus: cgi["chargeStatus"] } : {},
237328
+ ...typeof cgi?.["adapterStatus"] === "string" ? { adapterStatus: cgi["adapterStatus"] } : {}
237329
+ });
237330
+ }
237331
+ } catch (err) {
237332
+ this.ctx.logger.debug("Reolink Hub: per-channel battery refresh failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
237214
237333
  }
237215
237334
  }
237216
237335
  /**
@@ -237420,9 +237539,11 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237420
237539
  const now = Date.now();
237421
237540
  if (now - last > 6e4) {
237422
237541
  this.unroutedChannelLoggedAt.set(channel, now);
237423
- this.ctx.logger.warn("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
237542
+ const knownUnadopted = this.knownUnadoptedChannels.has(channel);
237543
+ this.ctx.logger[knownUnadopted ? "debug" : "warn"]("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
237424
237544
  channel,
237425
- type: ev?.type ?? "unknown"
237545
+ type: ev?.type ?? "unknown",
237546
+ knownUnadopted
237426
237547
  } });
237427
237548
  }
237428
237549
  return;
package/dist/addon.mjs CHANGED
@@ -19784,7 +19784,14 @@ targets: array(object({
19784
19784
  "sleeping",
19785
19785
  "unreachable",
19786
19786
  "waking"
19787
- ]).nullable()
19787
+ ]).nullable(),
19788
+ /** A battery camera (whatever its current state). An AWAKE battery
19789
+ * camera is deliberately NOT recaptured on the poll cadence — every
19790
+ * capture is a camera hit that would keep it out of sleep — so its
19791
+ * cached frame legitimately ages past the currency ceiling while
19792
+ * nothing is streaming. A surface must keep painting it (a fresh
19793
+ * frame is captured at each wake), not blank to "unavailable". */
19794
+ battery: boolean()
19788
19795
  })))
19789
19796
  },
19790
19797
  status: {
@@ -230168,6 +230175,15 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
230168
230175
  static WAKE_HYSTERESIS_MS = 3e4;
230169
230176
  static SLEEP_HYSTERESIS_MS = 5e3;
230170
230177
  /**
230178
+ * How long a freshly committed state is protected from a hub-summary
230179
+ * awake→sleeping flip. The summary's per-channel sleep flag lags real
230180
+ * pushes by over a minute (measured >75 s on 2026-08-16); 3 min covers
230181
+ * two full discovery-refresh cycles of lag without letting a genuinely
230182
+ * stuck "awake" slice stand forever — the reconcile still wins after
230183
+ * the grace, which is exactly its recovery role.
230184
+ */
230185
+ static HUB_SUMMARY_SLEEP_GRACE_MS = 18e4;
230186
+ /**
230171
230187
  * Wall-clock ms of the last PROACTIVE wake — one we issued on our own
230172
230188
  * initiative (background snapshot refresh), not because the operator
230173
230189
  * or a stream consumer asked for the camera. Drives
@@ -231147,15 +231163,35 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231147
231163
  *
231148
231164
  * @param source - `'hub-summary'` is AUTHORITATIVE (the NVR reports
231149
231165
  * per-channel sleep state from its own firmware, not from socket
231150
- * I/O inference) and therefore bypasses the hysteresis. The other
231151
- * two sources are inference-derived and stay gated.
231166
+ * I/O inference) and therefore bypasses the hysteresis with ONE
231167
+ * exception: the summary LAGS real push state (measured >75 s behind
231168
+ * an `awake` push, 2026-08-16), so an awake→sleeping flip from the
231169
+ * summary is refused while a fresher committed state is still inside
231170
+ * `HUB_SUMMARY_SLEEP_GRACE_MS`. Without the guard the 60 s reconcile
231171
+ * clobbered the fresh awake right back to sleeping for a full cycle —
231172
+ * the viewer flashed the live frame, then the sleeping overlay, then
231173
+ * live again. Sleeping→awake from the summary is always honoured
231174
+ * (it strands nothing; the camera wakes regardless).
231152
231175
  * @returns `true` when the slice actually changed.
231153
231176
  */
231154
231177
  commitSleepState(next, source) {
231155
231178
  if (!this.isBattery) return false;
231156
231179
  if (this.sleeping === next) return false;
231157
231180
  if (source !== "hub-summary" && !this.acceptSleepingTransition(next)) return false;
231158
- if (source === "hub-summary") this.sleepStateChangedAt = Date.now();
231181
+ if (source === "hub-summary") {
231182
+ const sinceCommitMs = Date.now() - this.sleepStateChangedAt;
231183
+ if (next === true && this.sleepStateChangedAt > 0 && sinceCommitMs < ReolinkCamera.HUB_SUMMARY_SLEEP_GRACE_MS) {
231184
+ this.ctx.logger.debug("hub-summary sleep flip refused — fresher state inside grace", {
231185
+ tags: { deviceId: this.id },
231186
+ meta: {
231187
+ sinceCommitMs,
231188
+ graceMs: ReolinkCamera.HUB_SUMMARY_SLEEP_GRACE_MS
231189
+ }
231190
+ });
231191
+ return false;
231192
+ }
231193
+ this.sleepStateChangedAt = Date.now();
231194
+ }
231159
231195
  this.state.battery.sleeping = next;
231160
231196
  this.ctx.logger.info("battery sleep state committed", {
231161
231197
  tags: { deviceId: this.id },
@@ -231295,13 +231331,42 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
231295
231331
  });
231296
231332
  }
231297
231333
  /**
231334
+ * Hub-fed battery refresh for an adopted child. The parent's
231335
+ * `getAllChannelsBatteryInfo` CGI carries per-channel percent/charge
231336
+ * state over the hub's own mains-powered socket, so it costs the
231337
+ * battery channel nothing — this is how a hub child's
231338
+ * percentage/charging ever moves (a sleeping child answers no poll of
231339
+ * its own, and its pushes only arrive on firmware transitions).
231340
+ *
231341
+ * Deliberately does NOT stamp `lastContactAt`: the value is the HUB's
231342
+ * cached read of the channel, not proof the camera itself answered —
231343
+ * folding it into contact would mask a genuinely gone camera from the
231344
+ * unreachable derivation (that is what pushes and streams are for).
231345
+ * `sleeping` is likewise untouched — sleep state has its own writers
231346
+ * (pushes + the guarded hub-summary reconcile).
231347
+ */
231348
+ applyHubBatteryInfo(info) {
231349
+ if (!this.isBattery) return;
231350
+ const mapped = this.mapBatteryInfo({
231351
+ ...info.batteryPercent !== void 0 ? { batteryPercent: info.batteryPercent } : {},
231352
+ ...info.chargeStatus !== void 0 ? { chargeStatus: info.chargeStatus } : {},
231353
+ ...info.adapterStatus !== void 0 ? { adapterStatus: info.adapterStatus } : {}
231354
+ });
231355
+ this.setCapSlice(batteryCapability, {
231356
+ ...this.state.battery,
231357
+ percentage: mapped.percentage,
231358
+ charging: mapped.charging,
231359
+ lastUpdated: Date.now()
231360
+ });
231361
+ }
231362
+ /**
231298
231363
  * Battery cams require an explicit wake before cmd_id 109 will
231299
231364
  * answer reliably. The lib documents this pattern in
231300
- * `predownloadRecordingMp4` (`ensureAwake` → `wakeUp` →
231301
- * operation → retry with longer wait on failure). `getSnapshot`
231302
- * itself only re-`login()`s, which over BCUDP can complete before
231303
- * the camera firmware is fully up — the snapshot then times out
231304
- * because the video subsystem isn't ready yet.
231365
+ * `predownloadRecordingMp3`/`predownloadRecordingMp4` (`ensureAwake`
231366
+ * → `wakeUp` → operation → retry with longer wait on failure).
231367
+ * `getSnapshot` itself only re-`login()`s, which over BCUDP can
231368
+ * complete before the camera firmware is fully up — the snapshot then
231369
+ * times out because the video subsystem isn't ready yet.
231305
231370
  *
231306
231371
  * Probe live testing (scripts/probe-reolink-snapshot.mts) confirmed:
231307
231372
  * awake state: getSnapshot in ~1s
@@ -236755,6 +236820,12 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
236755
236820
  * keeps the slice + map in sync after every change).
236756
236821
  */
236757
236822
  channelToDeviceId = /* @__PURE__ */ new Map();
236823
+ /** One-shot: the raw per-channel battery payload is logged once per
236824
+ * process so the firmware's charge-field naming is on record. */
236825
+ batteryShapeLogged = false;
236826
+ /** Channels the last successful discovery refresh listed as present but
236827
+ * NOT adopted — their pushes are expected drops (debug), not faults. */
236828
+ knownUnadoptedChannels = /* @__PURE__ */ new Set();
236758
236829
  /** Wall-clock ms of the last discovery refresh that included this
236759
236830
  * child's channel. Drives the offline marker — a child that hasn't
236760
236831
  * appeared in the firmware's channel list for `MISSING_OFFLINE_MS`
@@ -237168,6 +237239,11 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237168
237239
  };
237169
237240
  this.runtimeState.setCapState(deviceDiscoveryCapability.name, slice);
237170
237241
  if (lastError === null) {
237242
+ this.knownUnadoptedChannels.clear();
237243
+ for (const d of discovered) {
237244
+ const ch = d.metadata.rtspChannel;
237245
+ if (!d.alreadyAdopted && typeof ch === "number") this.knownUnadoptedChannels.add(ch);
237246
+ }
237171
237247
  const adoptedCount = discovered.filter((d) => d.alreadyAdopted).length;
237172
237248
  const availableCount = discovered.length - adoptedCount;
237173
237249
  const onlineCount = discovered.filter((d) => d.status === "online").length;
@@ -237191,6 +237267,49 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237191
237267
  if (lastError === null) {
237192
237268
  await this.reconcileAdoptedChildOnline(discovered);
237193
237269
  await this.reconcileAdoptedChildSleepState(discovered);
237270
+ await this.reconcileAdoptedChildBattery();
237271
+ }
237272
+ }
237273
+ /**
237274
+ * Push the hub's per-channel battery read into each adopted battery
237275
+ * child. `getAllChannelsBatteryInfo` is one CGI on the hub's own
237276
+ * mains-powered socket — it never touches a battery camera — and it is
237277
+ * the ONLY way a sleeping hub child's percentage/charging ever moves:
237278
+ * the child answers no poll of its own while asleep, and its battery
237279
+ * pushes arrive only on firmware transitions (measured live: 3628 sat
237280
+ * at 80% / charging:none for 3 h while plugged in, 2026-08-16).
237281
+ *
237282
+ * Independent of the discovery call's success path: a battery-read
237283
+ * failure must not fail discovery, so it is caught and logged here.
237284
+ */
237285
+ async reconcileAdoptedChildBattery() {
237286
+ if (this.channelToDeviceId.size === 0) return;
237287
+ try {
237288
+ const data = await (await this.ensureApi()).getAllChannelsBatteryInfo();
237289
+ const entries = Object.entries(data.batteryInfoData);
237290
+ if (entries.length === 0) return;
237291
+ if (!this.batteryShapeLogged) {
237292
+ this.batteryShapeLogged = true;
237293
+ this.ctx.logger.info("Reolink Hub: per-channel battery payload (first read)", { meta: { raw: entries.map(([ch, v]) => ({
237294
+ channel: Number(ch),
237295
+ ...v
237296
+ })) } });
237297
+ }
237298
+ const all = await this.ctx.devices.getAll();
237299
+ for (const [chKey, info] of entries) {
237300
+ const deviceId = this.channelToDeviceId.get(Number(chKey));
237301
+ if (deviceId === void 0) continue;
237302
+ const child = all.find((d) => d.id === deviceId);
237303
+ if (!(child instanceof ReolinkCamera)) continue;
237304
+ const cgi = info.entries[0];
237305
+ child.applyHubBatteryInfo({
237306
+ batteryPercent: info.batteryLevel,
237307
+ ...typeof cgi?.["chargeStatus"] === "string" ? { chargeStatus: cgi["chargeStatus"] } : {},
237308
+ ...typeof cgi?.["adapterStatus"] === "string" ? { adapterStatus: cgi["adapterStatus"] } : {}
237309
+ });
237310
+ }
237311
+ } catch (err) {
237312
+ this.ctx.logger.debug("Reolink Hub: per-channel battery refresh failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
237194
237313
  }
237195
237314
  }
237196
237315
  /**
@@ -237400,9 +237519,11 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
237400
237519
  const now = Date.now();
237401
237520
  if (now - last > 6e4) {
237402
237521
  this.unroutedChannelLoggedAt.set(channel, now);
237403
- this.ctx.logger.warn("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
237522
+ const knownUnadopted = this.knownUnadoptedChannels.has(channel);
237523
+ this.ctx.logger[knownUnadopted ? "debug" : "warn"]("Reolink Hub: simpleEvent for an unmapped channel dropped", { meta: {
237404
237524
  channel,
237405
- type: ev?.type ?? "unknown"
237525
+ type: ev?.type ?? "unknown",
237526
+ knownUnadopted
237406
237527
  } });
237407
237528
  }
237408
237529
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.38",
3
+ "version": "1.2.40",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",