@apocaliss92/nodelink-js 0.4.23 → 0.4.26

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.
@@ -17088,9 +17088,10 @@ function parseRectTags(block) {
17088
17088
  function decodePrivacyMaskZones(xml) {
17089
17089
  const canvas = extractCanvasFromShelterXml(xml);
17090
17090
  const enable = Number(getXmlText(xml, "enable") ?? "0") === 1;
17091
- const maxNum = Number(getXmlText(xml, "maxNum") ?? "0") | 0;
17092
17091
  const trackEnable = Number(getXmlText(xml, "trackEnable") ?? "0") === 1;
17093
17092
  const maxTrackShelterNum = Number(getXmlText(xml, "maxTrackShelterNum") ?? "0") | 0;
17093
+ const rawMaxNum = getXmlText(xml, "maxNum");
17094
+ const maxNum = rawMaxNum !== void 0 ? Number(rawMaxNum) | 0 : maxTrackShelterNum > 0 ? maxTrackShelterNum : 4;
17094
17095
  const shelterList = [];
17095
17096
  const shelterListBlock = xml.match(
17096
17097
  /<shelterList>([\s\S]*?)<\/shelterList>/
@@ -18999,6 +19000,39 @@ var applyFloodlightSettingsToXml = (xml, settings) => {
18999
19000
  return modifiedXml;
19000
19001
  };
19001
19002
 
19003
+ // src/reolink/baichuan/utils/whiteLedStatusPush.ts
19004
+ var parseFloodlightStatusListPushXml = (xml) => {
19005
+ const out = [];
19006
+ const re = /<channel>\s*(\d+)\s*<\/channel>[\s\S]*?<status>\s*(\d+)\s*<\/status>/gi;
19007
+ let m;
19008
+ while ((m = re.exec(xml)) !== null) {
19009
+ const channel = Number.parseInt(m[1] ?? "", 10);
19010
+ const status = Number.parseInt(m[2] ?? "", 10);
19011
+ if (!Number.isFinite(channel) || !Number.isFinite(status)) continue;
19012
+ out.push({ channel, status });
19013
+ }
19014
+ return out;
19015
+ };
19016
+
19017
+ // src/reolink/baichuan/utils/sirenStatusPush.ts
19018
+ var parseSirenStatusListPushXml = (xml) => {
19019
+ const out = [];
19020
+ const re = /<(?:channelId|channel)>\s*(\d+)\s*<\/(?:channelId|channel)>[\s\S]*?<status>\s*(\d+)\s*<\/status>(?:[\s\S]*?<playing>\s*(\d+)\s*<\/playing>)?/gi;
19021
+ let m;
19022
+ while ((m = re.exec(xml)) !== null) {
19023
+ const channel = Number.parseInt(m[1] ?? "", 10);
19024
+ const status = Number.parseInt(m[2] ?? "", 10);
19025
+ if (!Number.isFinite(channel) || !Number.isFinite(status)) continue;
19026
+ const entry = { channel, status };
19027
+ if (m[3] !== void 0) {
19028
+ const playing = Number.parseInt(m[3], 10);
19029
+ if (Number.isFinite(playing)) entry.playing = playing;
19030
+ }
19031
+ out.push(entry);
19032
+ }
19033
+ return out;
19034
+ };
19035
+
19002
19036
  // src/reolink/baichuan/ReolinkBaichuanApi.ts
19003
19037
  var DUAL_LENS_DUAL_MOTION_MODELS = /* @__PURE__ */ new Set([
19004
19038
  "Reolink Duo PoE",
@@ -19277,7 +19311,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
19277
19311
  });
19278
19312
  client.on("push", (frame) => {
19279
19313
  const cmdId = frame.header.cmdId;
19280
- if (cmdId !== BC_CMD_ID_PUSH_VIDEO_INPUT && cmdId !== BC_CMD_ID_PUSH_SERIAL && cmdId !== BC_CMD_ID_PUSH_NET_INFO && cmdId !== BC_CMD_ID_PUSH_DINGDONG_LIST && cmdId !== BC_CMD_ID_PUSH_SLEEP_STATUS && cmdId !== BC_CMD_ID_PUSH_COORDINATE_POINT_LIST) {
19314
+ if (cmdId !== BC_CMD_ID_PUSH_VIDEO_INPUT && cmdId !== BC_CMD_ID_PUSH_SERIAL && cmdId !== BC_CMD_ID_PUSH_NET_INFO && cmdId !== BC_CMD_ID_PUSH_DINGDONG_LIST && cmdId !== BC_CMD_ID_PUSH_SLEEP_STATUS && cmdId !== BC_CMD_ID_PUSH_COORDINATE_POINT_LIST && cmdId !== BC_CMD_ID_FLOODLIGHT_STATUS_LIST && cmdId !== BC_CMD_ID_GET_AUDIO_ALARM) {
19281
19315
  return;
19282
19316
  }
19283
19317
  try {
@@ -28318,6 +28352,33 @@ ${xml}`
28318
28352
  };
28319
28353
  return;
28320
28354
  }
28355
+ if (cmdId === BC_CMD_ID_FLOODLIGHT_STATUS_LIST) {
28356
+ const entries = parseFloodlightStatusListPushXml(xml);
28357
+ if (entries.length === 0) return;
28358
+ for (const entry of entries) {
28359
+ const channel = normalizePushChannel(entry.channel) ?? channelFromHeader;
28360
+ getEntry(channel).floodlightStatus = {
28361
+ updatedAtMs: now,
28362
+ value: { status: entry.status === 1 }
28363
+ };
28364
+ }
28365
+ return;
28366
+ }
28367
+ if (cmdId === BC_CMD_ID_GET_AUDIO_ALARM) {
28368
+ const entries = parseSirenStatusListPushXml(xml);
28369
+ if (entries.length === 0) return;
28370
+ for (const entry of entries) {
28371
+ const channel = normalizePushChannel(entry.channel) ?? channelFromHeader;
28372
+ getEntry(channel).sirenStatus = {
28373
+ updatedAtMs: now,
28374
+ value: {
28375
+ status: entry.status === 1,
28376
+ ...entry.playing !== void 0 ? { playing: entry.playing === 1 } : {}
28377
+ }
28378
+ };
28379
+ }
28380
+ return;
28381
+ }
28321
28382
  }
28322
28383
  /** Read-only snapshot of cached settings pushes (cmd_id 78/79/464/484/623/723). */
28323
28384
  getSettingsPushCacheSnapshot() {
@@ -28350,6 +28411,18 @@ ${xml}`
28350
28411
  ...entry.coordinatePointList,
28351
28412
  value: { ...entry.coordinatePointList.value }
28352
28413
  }
28414
+ } : {},
28415
+ ...entry.floodlightStatus ? {
28416
+ floodlightStatus: {
28417
+ ...entry.floodlightStatus,
28418
+ value: { ...entry.floodlightStatus.value }
28419
+ }
28420
+ } : {},
28421
+ ...entry.sirenStatus ? {
28422
+ sirenStatus: {
28423
+ ...entry.sirenStatus,
28424
+ value: { ...entry.sirenStatus.value }
28425
+ }
28353
28426
  } : {}
28354
28427
  });
28355
28428
  }
@@ -28373,6 +28446,29 @@ ${xml}`
28373
28446
  getCoordinatePointListFromPushCache(channel = 0) {
28374
28447
  return this.settingsPushCache.get(channel)?.coordinatePointList;
28375
28448
  }
28449
+ /**
28450
+ * Last cmd_id 291 (FloodlightStatusList) push observed for the channel.
28451
+ * The camera emits this whenever the floodlight transitions on/off,
28452
+ * including the auto-off after the FloodlightManual duration. This is
28453
+ * the only reliable source for the current manual state because cmd 289
28454
+ * only returns the FloodlightTask config.
28455
+ *
28456
+ * Returns undefined when no push has been received yet.
28457
+ */
28458
+ getCachedFloodlightStatus(channel = 0) {
28459
+ return this.settingsPushCache.get(channel)?.floodlightStatus;
28460
+ }
28461
+ /**
28462
+ * Last cmd_id 547 (SirenStatusList) push observed for the channel.
28463
+ * Captures the actual on/off transitions including the firmware's
28464
+ * built-in auto-off after the siren playback duration expires —
28465
+ * polling cmd 547 alone can race that auto-off.
28466
+ *
28467
+ * Returns undefined when no push has been received yet.
28468
+ */
28469
+ getCachedSirenStatus(channel = 0) {
28470
+ return this.settingsPushCache.get(channel)?.sirenStatus;
28471
+ }
28376
28472
  // --------------------
28377
28473
  // PCAP-derived settings getters (typed wrappers)
28378
28474
  // --------------------