@apocaliss92/nodelink-js 0.4.18 → 0.4.20

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.
@@ -16237,6 +16237,9 @@ function computeDeviceCapabilities(params) {
16237
16237
  const isDoorbellFromModel = typeof params.model === "string" && /doorbell/i.test(params.model);
16238
16238
  const lightTypeRaw = supportItem ? supportItem.lightType : void 0;
16239
16239
  const lightType = typeof lightTypeRaw === "number" ? lightTypeRaw : typeof lightTypeRaw === "string" ? Number(lightTypeRaw) : void 0;
16240
+ const ledCtrlRaw = supportItem ? supportItem.ledCtrl : void 0;
16241
+ const ledCtrl = typeof ledCtrlRaw === "number" ? ledCtrlRaw : typeof ledCtrlRaw === "string" ? Number(ledCtrlRaw) : void 0;
16242
+ const hasFloodlightFromLedCtrl = typeof ledCtrl === "number" && Number.isFinite(ledCtrl) && ledCtrl > 1;
16240
16243
  const hasPtzFromSupport = hasPtzFromSupportItem || (ptzMode ? ptzMode !== "none" && ptzMode !== "0" : false);
16241
16244
  const hasPanTiltFromSupport = ptzMode ? ptzMode.includes("pt") || ptzMode === "pt" || ptzMode === "ptz" : false;
16242
16245
  const hasZoomFromSupport = ptzMode ? ptzMode.includes("z") : false;
@@ -16279,8 +16282,10 @@ function computeDeviceCapabilities(params) {
16279
16282
  hasBattery,
16280
16283
  hasIntercom: hasIntercomFromSupport,
16281
16284
  hasSiren: hasSirenFromSupport || hasSirenFromAbilities,
16282
- // lightType >= 2 indicates controllable white LED / floodlight (1 = IR only)
16283
- hasFloodlight: Number.isFinite(lightType) ? lightType >= 2 : hasFloodlightFromAbilities,
16285
+ // lightType >= 2 indicates controllable white LED / floodlight (1 = IR only).
16286
+ // ledCtrl > 1 is a secondary signal that rescues firmwares like the Duo 3
16287
+ // WiFi which under-report lightType (=1) despite having a real spotlight.
16288
+ hasFloodlight: Number.isFinite(lightType) ? lightType >= 2 || hasFloodlightFromLedCtrl : hasFloodlightFromAbilities || hasFloodlightFromLedCtrl,
16284
16289
  hasPir: hasPirFromAbilities || hasPirFromSupport,
16285
16290
  isDoorbell,
16286
16291
  hasAutotracking: ptzDisabledBySupport ? false : hasAutotrackingFromSupport || hasAutotrackingFromAbilities,
@@ -18965,9 +18970,11 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
18965
18970
  if (!this.sessionGuardIntervalTimer) {
18966
18971
  client.once("push", () => {
18967
18972
  void this.logActiveSessionsOnStartup();
18968
- this.sessionGuardIntervalTimer = setInterval(() => {
18969
- void this.maybeRebootOnTooManySessions();
18970
- }, 6e4);
18973
+ if (this.sessionGuardEnabled) {
18974
+ this.sessionGuardIntervalTimer = setInterval(() => {
18975
+ void this.maybeRebootOnTooManySessions();
18976
+ }, 6e4);
18977
+ }
18971
18978
  });
18972
18979
  }
18973
18980
  }
@@ -19000,6 +19007,19 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
19000
19007
  _isMultiFocal;
19001
19008
  /** Maximum dedicated sessions allowed before triggering a reboot (default: 7). */
19002
19009
  maxDedicatedSessionsBeforeReboot;
19010
+ /**
19011
+ * Opt-in: when `false` (default), the lib never starts the 60s periodic
19012
+ * `getOnlineUserList` poll and never schedules an automatic reboot based
19013
+ * on the session count. The post-socket-create probe at line ~1859 is
19014
+ * also skipped. Consumers that want the legacy behaviour can pass
19015
+ * `enableSessionGuard: true` to the constructor.
19016
+ *
19017
+ * Rationale: on BCUDP (battery cameras) the periodic poll wakes the
19018
+ * camera every minute and triggers a perpetual sleeping↔awake cycle —
19019
+ * see issue #18. Even on AC cameras the auto-reboot side effect is
19020
+ * surprising; making it explicit avoids astonishment.
19021
+ */
19022
+ sessionGuardEnabled = false;
19003
19023
  sessionGuardRebootInFlight;
19004
19024
  sessionGuardLastRebootAtMs;
19005
19025
  /** Track last known session count and IDs for change detection. */
@@ -19691,7 +19711,9 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
19691
19711
  } catch {
19692
19712
  }
19693
19713
  }
19694
- void this.maybeRebootOnTooManySessions();
19714
+ if (this.sessionGuardEnabled) {
19715
+ void this.maybeRebootOnTooManySessions();
19716
+ }
19695
19717
  return newClient;
19696
19718
  } catch (loginError) {
19697
19719
  const prevCooldown = this.socketPoolCooldowns.get(this.host);
@@ -20001,6 +20023,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
20001
20023
  logger: this.logger,
20002
20024
  debugConfig: generalClient.getDebugConfig?.()
20003
20025
  });
20026
+ this.sessionGuardEnabled = opts.enableSessionGuard === true;
20004
20027
  const maxSessions = opts.maxDedicatedSessionsBeforeReboot;
20005
20028
  if (typeof maxSessions === "number" && Number.isFinite(maxSessions) && maxSessions > 0) {
20006
20029
  this.maxDedicatedSessionsBeforeReboot = Math.floor(maxSessions);
@@ -20174,6 +20197,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
20174
20197
  */
20175
20198
  async maybeRebootOnTooManySessions() {
20176
20199
  if (!this.client.isSocketConnected?.()) return;
20200
+ if (this.client.getTransport?.() === "udp") return;
20177
20201
  const threshold = this.maxDedicatedSessionsBeforeReboot ?? 10;
20178
20202
  if (this.sessionGuardRebootInFlight) return;
20179
20203
  const cooldownMs = 10 * 6e4;
@@ -26325,7 +26349,7 @@ ${xml}`
26325
26349
  const probed = await this.probeFloodlightSupportByCmd289(ch, {
26326
26350
  timeoutMs: 2500
26327
26351
  });
26328
- capabilities.hasFloodlight = probed;
26352
+ capabilities.hasFloodlight = capabilities.hasFloodlight || probed;
26329
26353
  }
26330
26354
  let dingDongListIds;
26331
26355
  let dingDongCfgIds;
@@ -26518,7 +26542,17 @@ ${xml}`
26518
26542
  const isSingleMotionModel = normalizedModel ? checkModelMatch(DUAL_LENS_SINGLE_MOTION_MODELS, normalizedModel) : false;
26519
26543
  const channelNumValue = typeof channelNum === "string" ? Number.parseInt(channelNum, 10) : channelNum;
26520
26544
  const hasDualLensChannelCount = channelNumValue === 2 && Number.isFinite(channelNumValue);
26521
- const isDualLens = isDualMotionModel || isSingleMotionModel || hasDualLensChannelCount;
26545
+ const supportItemForChannel = (() => {
26546
+ if (!supportInfo) return void 0;
26547
+ const items = supportInfo.items;
26548
+ if (!Array.isArray(items)) return void 0;
26549
+ return items.find(
26550
+ (it) => typeof it === "object" && it !== null && "ledCtrl" in it
26551
+ );
26552
+ })();
26553
+ const binoCfgRaw = supportItemForChannel ? supportItemForChannel.binoCfg : void 0;
26554
+ const hasBinoCfgFlag = typeof binoCfgRaw === "number" ? binoCfgRaw > 0 : typeof binoCfgRaw === "string" ? Number(binoCfgRaw) > 0 : false;
26555
+ const isDualLens = hasBinoCfgFlag || isDualMotionModel || isSingleMotionModel || hasDualLensChannelCount;
26522
26556
  if (!isDualLens) {
26523
26557
  return {
26524
26558
  isDualLens: false,