@camstack/addon-provider-reolink 1.2.139 → 1.2.140
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/BaichuanVideoStream-2M4UO7MB-CB-tIHMA.mjs +2 -0
- package/dist/BaichuanVideoStream-2M4UO7MB-Cqjt1oxu.js +3 -0
- package/dist/addon.js +548 -279
- package/dist/addon.mjs +398 -129
- package/dist/{chunk-KWWUCNIY-Ccq-OAGJ.mjs → chunk-ZQFQRCLQ-BNqCZtSS.mjs} +1 -1
- package/dist/{chunk-KWWUCNIY-BtO6U6BT.js → chunk-ZQFQRCLQ-CR7OOtpp.js} +1 -1
- package/package.json +2 -2
- package/dist/BaichuanVideoStream-PBJL3EB5-D-etWPiW.mjs +0 -2
- package/dist/BaichuanVideoStream-PBJL3EB5-qv_JKCPo.js +0 -3
- /package/dist/{DiagnosticsTools-TID5M22B-9NV95vRN.mjs → DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs} +0 -0
- /package/dist/{DiagnosticsTools-TID5M22B-CD4rRF8a.js → DiagnosticsTools-GOFDNGAY-CD4rRF8a.js} +0 -0
package/dist/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { A as splitAnnexBToNalPayloads2, C as extractVpsFromAnnexB, D as normalizeDebugOptions, E as md5StrModern, M as traceLog, O as recordingsTraceLog, S as extractSpsFromAnnexB, T as isH265Irap, _ as convertToAnnexB2, a as BC_MAGIC, b as eventTraceLog, c as BaichuanVideoStream, d as aesDecrypt, f as aesEncrypt, g as convertToAnnexB, h as bcHeaderHasPayloadOffset, i as BC_CLASS_MODERN_24, j as talkTraceLog, k as splitAnnexBToNalPayloads, l as BcMediaAnnexBDecoder, m as bcEncrypt, n as BC_CLASS_LEGACY, o as BC_MAGIC_REV, p as bcDecrypt, r as BC_CLASS_MODERN_20, t as BC_CLASS_FILE_DOWNLOAD, u as __require$1, v as debugLog, w as getH265NalType, x as extractPpsFromAnnexB, y as deriveAesKey } from "./chunk-
|
|
2
|
+
import { A as splitAnnexBToNalPayloads2, C as extractVpsFromAnnexB, D as normalizeDebugOptions, E as md5StrModern, M as traceLog, O as recordingsTraceLog, S as extractSpsFromAnnexB, T as isH265Irap, _ as convertToAnnexB2, a as BC_MAGIC, b as eventTraceLog, c as BaichuanVideoStream, d as aesDecrypt, f as aesEncrypt, g as convertToAnnexB, h as bcHeaderHasPayloadOffset, i as BC_CLASS_MODERN_24, j as talkTraceLog, k as splitAnnexBToNalPayloads, l as BcMediaAnnexBDecoder, m as bcEncrypt, n as BC_CLASS_LEGACY, o as BC_MAGIC_REV, p as bcDecrypt, r as BC_CLASS_MODERN_20, t as BC_CLASS_FILE_DOWNLOAD, u as __require$1, v as debugLog, w as getH265NalType, x as extractPpsFromAnnexB, y as deriveAesKey } from "./chunk-ZQFQRCLQ-BNqCZtSS.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { EventEmitter } from "events";
|
|
5
5
|
import * as fs2 from "fs";
|
|
@@ -5381,7 +5381,7 @@ var ZodIssueCode = {
|
|
|
5381
5381
|
var ZodFirstPartyTypeKind;
|
|
5382
5382
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5383
5383
|
//#endregion
|
|
5384
|
-
//#region ../types/dist/sleep-
|
|
5384
|
+
//#region ../types/dist/sleep-vl6nBE8d.mjs
|
|
5385
5385
|
/**
|
|
5386
5386
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5387
5387
|
* window to float samples (D455).
|
|
@@ -31874,6 +31874,47 @@ var ptzCapability = {
|
|
|
31874
31874
|
auth: "admin"
|
|
31875
31875
|
}),
|
|
31876
31876
|
/**
|
|
31877
|
+
* Make WHERE THE HEAD IS POINTING RIGHT NOW this camera's home.
|
|
31878
|
+
*
|
|
31879
|
+
* `setHomePreset` takes a preset id, and a preset id is the wrong shape for
|
|
31880
|
+
* the most natural thing an operator does: aim the camera, then say "here".
|
|
31881
|
+
* It is also the only shape a camera whose home is NOT a preset can accept
|
|
31882
|
+
* -- Reolink's home is a guard point, a stored position with no id at all,
|
|
31883
|
+
* and hiding the control for that case (as the UI briefly did) left the one
|
|
31884
|
+
* vendor with a native home unable to set it.
|
|
31885
|
+
*
|
|
31886
|
+
* Each provider does it its own way:
|
|
31887
|
+
* reolink `setGrd` with `needSetPos`, pinning the guard point here
|
|
31888
|
+
* hikvision / amcrest save a preset, then pin it as home
|
|
31889
|
+
* onvif REFUSES -- its home is the PTZ origin and cannot be moved
|
|
31890
|
+
*
|
|
31891
|
+
* A provider that cannot honour it throws rather than silently doing
|
|
31892
|
+
* nothing: an operator who pressed "set home here" and saw no error would
|
|
31893
|
+
* believe it took.
|
|
31894
|
+
*/
|
|
31895
|
+
captureHomeHere: method(object({ deviceId: number() }), _void(), {
|
|
31896
|
+
kind: "mutation",
|
|
31897
|
+
auth: "admin"
|
|
31898
|
+
}),
|
|
31899
|
+
/**
|
|
31900
|
+
* How long the camera waits, idle, before returning home on its own --
|
|
31901
|
+
* `null` when it has no such behaviour.
|
|
31902
|
+
*
|
|
31903
|
+
* Reolink's guard point carries one (`timeout`, freely settable in
|
|
31904
|
+
* seconds). It is a real function of the camera that we did not expose at
|
|
31905
|
+
* all, and it belongs next to the home it governs rather than in a vendor
|
|
31906
|
+
* settings page nobody associates with Home.
|
|
31907
|
+
*/
|
|
31908
|
+
getHomeReturnSeconds: method(object({ deviceId: number() }), number().int().nullable()),
|
|
31909
|
+
/** Set the idle-return delay. Refused by a camera that has no such timer. */
|
|
31910
|
+
setHomeReturnSeconds: method(object({
|
|
31911
|
+
deviceId: number(),
|
|
31912
|
+
seconds: number().int().min(0).max(3600)
|
|
31913
|
+
}), _void(), {
|
|
31914
|
+
kind: "mutation",
|
|
31915
|
+
auth: "admin"
|
|
31916
|
+
}),
|
|
31917
|
+
/**
|
|
31877
31918
|
* Pull the current PTZ position. Redundant with the auto-injected
|
|
31878
31919
|
* `getStatus` method (see `status` below); kept for callers that
|
|
31879
31920
|
* haven't migrated. Will be folded into `getStatus` in a future
|
|
@@ -41531,6 +41572,12 @@ Object.freeze({
|
|
|
41531
41572
|
addonId: null,
|
|
41532
41573
|
access: "create"
|
|
41533
41574
|
},
|
|
41575
|
+
"ptz.captureHomeHere": {
|
|
41576
|
+
capName: "ptz",
|
|
41577
|
+
capScope: "device",
|
|
41578
|
+
addonId: null,
|
|
41579
|
+
access: "create"
|
|
41580
|
+
},
|
|
41534
41581
|
"ptz.continuousMove": {
|
|
41535
41582
|
capName: "ptz",
|
|
41536
41583
|
capScope: "device",
|
|
@@ -41549,6 +41596,12 @@ Object.freeze({
|
|
|
41549
41596
|
addonId: null,
|
|
41550
41597
|
access: "view"
|
|
41551
41598
|
},
|
|
41599
|
+
"ptz.getHomeReturnSeconds": {
|
|
41600
|
+
capName: "ptz",
|
|
41601
|
+
capScope: "device",
|
|
41602
|
+
addonId: null,
|
|
41603
|
+
access: "view"
|
|
41604
|
+
},
|
|
41552
41605
|
"ptz.getOptions": {
|
|
41553
41606
|
capName: "ptz",
|
|
41554
41607
|
capScope: "device",
|
|
@@ -41603,6 +41656,12 @@ Object.freeze({
|
|
|
41603
41656
|
addonId: null,
|
|
41604
41657
|
access: "create"
|
|
41605
41658
|
},
|
|
41659
|
+
"ptz.setHomeReturnSeconds": {
|
|
41660
|
+
capName: "ptz",
|
|
41661
|
+
capScope: "device",
|
|
41662
|
+
addonId: null,
|
|
41663
|
+
access: "create"
|
|
41664
|
+
},
|
|
41606
41665
|
"ptz.stop": {
|
|
41607
41666
|
capName: "ptz",
|
|
41608
41667
|
capScope: "device",
|
|
@@ -44766,6 +44825,11 @@ Object.freeze({
|
|
|
44766
44825
|
form: "single",
|
|
44767
44826
|
optional: false
|
|
44768
44827
|
}],
|
|
44828
|
+
"ptz.captureHomeHere": [{
|
|
44829
|
+
name: "deviceId",
|
|
44830
|
+
form: "single",
|
|
44831
|
+
optional: false
|
|
44832
|
+
}],
|
|
44769
44833
|
"ptz.continuousMove": [{
|
|
44770
44834
|
name: "deviceId",
|
|
44771
44835
|
form: "single",
|
|
@@ -44781,6 +44845,11 @@ Object.freeze({
|
|
|
44781
44845
|
form: "single",
|
|
44782
44846
|
optional: false
|
|
44783
44847
|
}],
|
|
44848
|
+
"ptz.getHomeReturnSeconds": [{
|
|
44849
|
+
name: "deviceId",
|
|
44850
|
+
form: "single",
|
|
44851
|
+
optional: false
|
|
44852
|
+
}],
|
|
44784
44853
|
"ptz.getOptions": [{
|
|
44785
44854
|
name: "deviceId",
|
|
44786
44855
|
form: "single",
|
|
@@ -44826,6 +44895,11 @@ Object.freeze({
|
|
|
44826
44895
|
form: "single",
|
|
44827
44896
|
optional: false
|
|
44828
44897
|
}],
|
|
44898
|
+
"ptz.setHomeReturnSeconds": [{
|
|
44899
|
+
name: "deviceId",
|
|
44900
|
+
form: "single",
|
|
44901
|
+
optional: false
|
|
44902
|
+
}],
|
|
44829
44903
|
"ptz.stop": [{
|
|
44830
44904
|
name: "deviceId",
|
|
44831
44905
|
form: "single",
|
|
@@ -68510,7 +68584,7 @@ var require_yazl = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
68510
68584
|
}
|
|
68511
68585
|
}));
|
|
68512
68586
|
//#endregion
|
|
68513
|
-
//#region node_modules/@apocaliss92/nodelink-js/dist/chunk-
|
|
68587
|
+
//#region node_modules/@apocaliss92/nodelink-js/dist/chunk-KWQVN7H5.js
|
|
68514
68588
|
var import_undici = require_undici();
|
|
68515
68589
|
var import_yazl = /* @__PURE__ */ __toESM(require_yazl(), 1);
|
|
68516
68590
|
var FLAGS_CAM_V2 = {
|
|
@@ -74927,7 +75001,7 @@ var require_lz4 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
74927
75001
|
};
|
|
74928
75002
|
}));
|
|
74929
75003
|
//#endregion
|
|
74930
|
-
//#region node_modules/@apocaliss92/nodelink-js/dist/chunk-
|
|
75004
|
+
//#region node_modules/@apocaliss92/nodelink-js/dist/chunk-CE77DTET.js
|
|
74931
75005
|
var import_fxp = require_fxp();
|
|
74932
75006
|
var import_lz4 = /* @__PURE__ */ __toESM(require_lz4(), 1);
|
|
74933
75007
|
function encodeHeader(h) {
|
|
@@ -75246,8 +75320,8 @@ function buildC2mQ(params) {
|
|
|
75246
75320
|
const os = params.os ?? "MAC";
|
|
75247
75321
|
return buildP2pXml(`<C2M_Q><uid>${xmlEscape(params.uid)}</uid><p>${xmlEscape(os)}</p></C2M_Q>`);
|
|
75248
75322
|
}
|
|
75249
|
-
function parseIpPortBlock(
|
|
75250
|
-
const m = new RegExp(`<${
|
|
75323
|
+
function parseIpPortBlock(tag2, body) {
|
|
75324
|
+
const m = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
|
|
75251
75325
|
if (!m) return void 0;
|
|
75252
75326
|
const block = m[1] ?? "";
|
|
75253
75327
|
const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
|
|
@@ -75292,8 +75366,8 @@ function parseR2cCr(xml) {
|
|
|
75292
75366
|
if (!Number.isFinite(rsp)) return void 0;
|
|
75293
75367
|
const sidStr = /<sid>(-?\d+)<\/sid>/i.exec(body)?.[1];
|
|
75294
75368
|
const sid = sidStr != null ? Number(sidStr) : void 0;
|
|
75295
|
-
const parseCustom = (
|
|
75296
|
-
const mm = new RegExp(`<${
|
|
75369
|
+
const parseCustom = (tag2) => {
|
|
75370
|
+
const mm = new RegExp(`<${tag2}>([\\s\\S]*?)</${tag2}>`, "i").exec(body);
|
|
75297
75371
|
if (!mm) return void 0;
|
|
75298
75372
|
const block = mm[1] ?? "";
|
|
75299
75373
|
const ip = /<ip>([^<]+)<\/ip>/i.exec(block)?.[1];
|
|
@@ -76853,12 +76927,12 @@ function asLogger(logger) {
|
|
|
76853
76927
|
error: resolveMethod(base, "error"),
|
|
76854
76928
|
debug: resolveMethod(base, "debug")
|
|
76855
76929
|
};
|
|
76856
|
-
out.child = (
|
|
76930
|
+
out.child = (tag2) => createTaggedLogger(out, tag2);
|
|
76857
76931
|
return out;
|
|
76858
76932
|
}
|
|
76859
|
-
function createTaggedLogger(base,
|
|
76933
|
+
function createTaggedLogger(base, tag2) {
|
|
76860
76934
|
const b = base.log ? base : asLogger(base);
|
|
76861
|
-
const prefix = `[${
|
|
76935
|
+
const prefix = `[${tag2}] `;
|
|
76862
76936
|
const wrap = (fn) => {
|
|
76863
76937
|
return (message, ...optionalParams) => {
|
|
76864
76938
|
if (typeof message === "string") fn(`${prefix}${message}`, ...optionalParams);
|
|
@@ -76885,7 +76959,7 @@ function createDebugGateLogger(base, enabled = false) {
|
|
|
76885
76959
|
error: b.error,
|
|
76886
76960
|
debug: enabled ? b.debug : noop
|
|
76887
76961
|
};
|
|
76888
|
-
out.child = (
|
|
76962
|
+
out.child = (tag2) => createDebugGateLogger(createTaggedLogger(out, tag2), enabled);
|
|
76889
76963
|
return out;
|
|
76890
76964
|
}
|
|
76891
76965
|
function isTalkCmd(cmdId) {
|
|
@@ -82579,29 +82653,29 @@ function parseSupportXml(xml) {
|
|
|
82579
82653
|
if (!match) return void 0;
|
|
82580
82654
|
const supportXml = match[1] ?? "";
|
|
82581
82655
|
const ptzMode = supportXml.match(/<ptzMode>([^<]*)<\/ptzMode>/i)?.[1];
|
|
82582
|
-
const topLevelInt = (
|
|
82583
|
-
return toNumberOrUndefined(supportXml.match(new RegExp(`<${
|
|
82656
|
+
const topLevelInt = (tag2) => {
|
|
82657
|
+
return toNumberOrUndefined(supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1]);
|
|
82584
82658
|
};
|
|
82585
|
-
const topLevelString = (
|
|
82586
|
-
return supportXml.match(new RegExp(`<${
|
|
82659
|
+
const topLevelString = (tag2) => {
|
|
82660
|
+
return supportXml.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`, "i"))?.[1];
|
|
82587
82661
|
};
|
|
82588
82662
|
const items = [];
|
|
82589
82663
|
for (const itemMatch of supportXml.matchAll(/<item[^>]*>([\s\S]*?)<\/item>/gi)) {
|
|
82590
82664
|
const itemXml = itemMatch[1] ?? "";
|
|
82591
82665
|
const item = { chnID: toNumberOrUndefined(itemXml.match(/<chnID>([^<]*)<\/chnID>/i)?.[1]) ?? 0 };
|
|
82592
82666
|
for (const tagMatch of itemXml.matchAll(/<([A-Za-z0-9_]+)>([^<]*)<\/\1>/g)) {
|
|
82593
|
-
const
|
|
82667
|
+
const tag2 = tagMatch[1];
|
|
82594
82668
|
const value = tagMatch[2];
|
|
82595
|
-
if (!
|
|
82596
|
-
if (
|
|
82597
|
-
item[
|
|
82669
|
+
if (!tag2) continue;
|
|
82670
|
+
if (tag2 === "chnID") continue;
|
|
82671
|
+
item[tag2] = toNumberOrUndefined(value) ?? value;
|
|
82598
82672
|
}
|
|
82599
82673
|
items.push(item);
|
|
82600
82674
|
}
|
|
82601
82675
|
const support = { items };
|
|
82602
82676
|
if (ptzMode !== void 0) support.ptzMode = ptzMode;
|
|
82603
|
-
const assignInt = (key,
|
|
82604
|
-
const v = topLevelInt(
|
|
82677
|
+
const assignInt = (key, tag2) => {
|
|
82678
|
+
const v = topLevelInt(tag2);
|
|
82605
82679
|
if (v !== void 0) support[key] = v;
|
|
82606
82680
|
};
|
|
82607
82681
|
assignInt("IOInputPortNum", "IOInputPortNum");
|
|
@@ -82828,15 +82902,15 @@ function extractCanvasFromShelterXml(xml) {
|
|
|
82828
82902
|
const yMatch = xml.match(/<topLeftY>(\d+)<\/topLeftY>/g) ?? [];
|
|
82829
82903
|
let canvasX = 0;
|
|
82830
82904
|
let canvasY = 0;
|
|
82831
|
-
for (const
|
|
82832
|
-
const v = Number(
|
|
82905
|
+
for (const tag2 of xMatch) {
|
|
82906
|
+
const v = Number(tag2.replace(/<\/?topLeftX>/g, "")) | 0;
|
|
82833
82907
|
if (v > 0) {
|
|
82834
82908
|
canvasX = v & 65535;
|
|
82835
82909
|
break;
|
|
82836
82910
|
}
|
|
82837
82911
|
}
|
|
82838
|
-
for (const
|
|
82839
|
-
const v = Number(
|
|
82912
|
+
for (const tag2 of yMatch) {
|
|
82913
|
+
const v = Number(tag2.replace(/<\/?topLeftY>/g, "")) | 0;
|
|
82840
82914
|
if (v > 0) {
|
|
82841
82915
|
canvasY = v & 65535;
|
|
82842
82916
|
break;
|
|
@@ -82849,9 +82923,9 @@ function extractCanvasFromShelterXml(xml) {
|
|
|
82849
82923
|
}
|
|
82850
82924
|
function parseRectTags(block) {
|
|
82851
82925
|
const out = {};
|
|
82852
|
-
const grab = (
|
|
82853
|
-
const m = block.match(new RegExp(`<${
|
|
82854
|
-
if (m && m[1] !== void 0) out[
|
|
82926
|
+
const grab = (tag2) => {
|
|
82927
|
+
const m = block.match(new RegExp(`<${tag2}>([^<]*)<\\/${tag2}>`));
|
|
82928
|
+
if (m && m[1] !== void 0) out[tag2] = m[1];
|
|
82855
82929
|
};
|
|
82856
82930
|
grab("id");
|
|
82857
82931
|
grab("name");
|
|
@@ -83096,9 +83170,9 @@ var buildDetectionClasses = (parsed, recordType) => {
|
|
|
83096
83170
|
};
|
|
83097
83171
|
var getXmlTexts = (xml, tags) => {
|
|
83098
83172
|
const out = {};
|
|
83099
|
-
for (const
|
|
83100
|
-
const v = getXmlText(xml,
|
|
83101
|
-
if (v !== void 0) out[
|
|
83173
|
+
for (const tag2 of tags) {
|
|
83174
|
+
const v = getXmlText(xml, tag2);
|
|
83175
|
+
if (v !== void 0) out[tag2] = v;
|
|
83102
83176
|
}
|
|
83103
83177
|
return out;
|
|
83104
83178
|
};
|
|
@@ -83360,11 +83434,11 @@ function patchBlock(xml, block, fields) {
|
|
|
83360
83434
|
const end = xml.indexOf(`</${block}>`, start);
|
|
83361
83435
|
if (end < 0) return xml;
|
|
83362
83436
|
let body = xml.slice(start, end);
|
|
83363
|
-
for (const [
|
|
83437
|
+
for (const [tag2, value] of Object.entries(fields)) {
|
|
83364
83438
|
if (value === void 0) continue;
|
|
83365
83439
|
const escaped = escapeXmlText(typeof value === "boolean" ? value ? "1" : "0" : String(value));
|
|
83366
|
-
if (body.includes(`<${
|
|
83367
|
-
else body += `<${
|
|
83440
|
+
if (body.includes(`<${tag2}>`)) body = body.replace(new RegExp(`<${tag2}>[^<]*<\\/${tag2}>`), `<${tag2}>${escaped}</${tag2}>`);
|
|
83441
|
+
else body += `<${tag2}>${escaped}</${tag2}>`;
|
|
83368
83442
|
}
|
|
83369
83443
|
return xml.slice(0, start) + body + xml.slice(end);
|
|
83370
83444
|
}
|
|
@@ -83432,6 +83506,66 @@ var OSD_CORNER_LABELS = {
|
|
|
83432
83506
|
"bottom-left": "Bottom left",
|
|
83433
83507
|
"bottom-right": "Bottom right"
|
|
83434
83508
|
};
|
|
83509
|
+
function wireFloat(value) {
|
|
83510
|
+
return value.toExponential(6).replace(/e([+-])(\d)$/, "e$10$2");
|
|
83511
|
+
}
|
|
83512
|
+
function buildPtzGuardExtensionXml(channelId, direction) {
|
|
83513
|
+
return `<?xml version="1.0" encoding="UTF-8" ?>
|
|
83514
|
+
<Extension version="1.1">
|
|
83515
|
+
<channelId>${channelId}</channelId>${direction === "read" ? `
|
|
83516
|
+
<chnType>0</chnType>` : ""}
|
|
83517
|
+
</Extension>
|
|
83518
|
+
`;
|
|
83519
|
+
}
|
|
83520
|
+
function guardBody(channelId, command, fields) {
|
|
83521
|
+
return [
|
|
83522
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",
|
|
83523
|
+
"<body>",
|
|
83524
|
+
"<PtzGuard version=\"1.1\">",
|
|
83525
|
+
`<channelId>${channelId}</channelId>`,
|
|
83526
|
+
...fields,
|
|
83527
|
+
`<command>${command}</command>`,
|
|
83528
|
+
"<imageName></imageName>",
|
|
83529
|
+
`<xpos>${wireFloat(0)}</xpos>`,
|
|
83530
|
+
`<ypos>${wireFloat(0)}</ypos>`,
|
|
83531
|
+
`<height>${wireFloat(0)}</height>`,
|
|
83532
|
+
`<width>${wireFloat(0)}</width>`,
|
|
83533
|
+
"<mode>global</mode>",
|
|
83534
|
+
"</PtzGuard>",
|
|
83535
|
+
"</body>",
|
|
83536
|
+
""
|
|
83537
|
+
].join("\n");
|
|
83538
|
+
}
|
|
83539
|
+
function buildPtzGuardGoXml(channelId) {
|
|
83540
|
+
return guardBody(channelId, "toGrd", ["<benable>0</benable>", "<timeout>68</timeout>"]);
|
|
83541
|
+
}
|
|
83542
|
+
function buildPtzGuardSetXml(input) {
|
|
83543
|
+
return guardBody(input.channelId, "setGrd", [
|
|
83544
|
+
`<benable>${input.enabled ? 1 : 0}</benable>`,
|
|
83545
|
+
`<timeout>${Math.round(input.timeoutSeconds)}</timeout>`,
|
|
83546
|
+
...input.setPosition ? ["<needSetPos>1</needSetPos>"] : []
|
|
83547
|
+
]);
|
|
83548
|
+
}
|
|
83549
|
+
function tag(xml, name) {
|
|
83550
|
+
const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml);
|
|
83551
|
+
return m === null ? null : (m[1] ?? "").trim();
|
|
83552
|
+
}
|
|
83553
|
+
function parsePtzGuardXml(xml) {
|
|
83554
|
+
if (!xml.includes("<PtzGuard")) return null;
|
|
83555
|
+
const enabled = tag(xml, "benable");
|
|
83556
|
+
const valid = tag(xml, "bvalid");
|
|
83557
|
+
const timeout = tag(xml, "timeout");
|
|
83558
|
+
if (enabled === null || valid === null || timeout === null) return null;
|
|
83559
|
+
const timeoutSeconds = Number.parseInt(timeout, 10);
|
|
83560
|
+
if (!Number.isFinite(timeoutSeconds)) return null;
|
|
83561
|
+
return {
|
|
83562
|
+
enabled: enabled === "1",
|
|
83563
|
+
valid: valid === "1",
|
|
83564
|
+
timeoutSeconds,
|
|
83565
|
+
mode: tag(xml, "mode") ?? "global",
|
|
83566
|
+
imageName: tag(xml, "imageName") ?? ""
|
|
83567
|
+
};
|
|
83568
|
+
}
|
|
83435
83569
|
var emitter = new EventEmitter();
|
|
83436
83570
|
var lastEventByCamera = /* @__PURE__ */ new Map();
|
|
83437
83571
|
var MAX_GLOBAL_EVENTS = 300;
|
|
@@ -84644,8 +84778,8 @@ var buildFileInfoListStopXml = (params) => {
|
|
|
84644
84778
|
</body>`;
|
|
84645
84779
|
};
|
|
84646
84780
|
var sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
84647
|
-
var xmlDateTimePayload = (
|
|
84648
|
-
return `<${
|
|
84781
|
+
var xmlDateTimePayload = (tag2, d) => {
|
|
84782
|
+
return `<${tag2}><year>${d.getFullYear()}</year><month>${d.getMonth() + 1}</month><day>${d.getDate()}</day><hour>${d.getHours()}</hour><minute>${d.getMinutes()}</minute><second>${d.getSeconds()}</second></${tag2}>`;
|
|
84649
84783
|
};
|
|
84650
84784
|
var buildFileInfoListOpenXml = (params) => {
|
|
84651
84785
|
return `<?xml version="1.0" encoding="UTF-8" ?>
|
|
@@ -84833,10 +84967,10 @@ var isPlausibleStream = (s) => {
|
|
|
84833
84967
|
return s.width > 0 && s.height > 0 && (s.frameRate > 0 || s.bitRate > 0);
|
|
84834
84968
|
};
|
|
84835
84969
|
var logDebugStreamBlock = (params) => {
|
|
84836
|
-
const { logger, traceNativeStream, channel, tag, blockXml } = params;
|
|
84970
|
+
const { logger, traceNativeStream, channel, tag: tag2, blockXml } = params;
|
|
84837
84971
|
if (!traceNativeStream) return;
|
|
84838
84972
|
if (!blockXml) {
|
|
84839
|
-
(logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${
|
|
84973
|
+
(logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag2}> missing`);
|
|
84840
84974
|
return;
|
|
84841
84975
|
}
|
|
84842
84976
|
const raw = blockXml;
|
|
@@ -84863,7 +84997,7 @@ var logDebugStreamBlock = (params) => {
|
|
|
84863
84997
|
const previewMax = 1400;
|
|
84864
84998
|
const xmlPreview = raw.length <= previewMax ? raw : raw.slice(0, previewMax) + `
|
|
84865
84999
|
...truncated (+${raw.length - previewMax} chars)`;
|
|
84866
|
-
(logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${
|
|
85000
|
+
(logger.warn ?? logger.log).call(logger, `[ReolinkBaichuanApi] getStreamMetadata(traceNativeStream): channel=${channel} tag=<${tag2}> enabled=${isEnabled} plausible=${plausible} width=${width} height=${height} frame=${frameRate} bitRate=${bitRate} audio=${audio} videoEncType=${videoEncTypeText ?? "?"} rawFields=${JSON.stringify({
|
|
84867
85001
|
widthText,
|
|
84868
85002
|
heightText,
|
|
84869
85003
|
frameText,
|
|
@@ -84956,20 +85090,20 @@ var parseChannelStreamMetadataFromGetEncXml = (params) => {
|
|
|
84956
85090
|
audioEnabled = audioEnabled && s.audio === 1;
|
|
84957
85091
|
}
|
|
84958
85092
|
}
|
|
84959
|
-
for (const
|
|
85093
|
+
for (const tag2 of [
|
|
84960
85094
|
"extStream",
|
|
84961
85095
|
"thirdStream",
|
|
84962
85096
|
"externStream",
|
|
84963
85097
|
"extraStream"
|
|
84964
85098
|
]) {
|
|
84965
|
-
const extMatch = xml.match(new RegExp(`<${
|
|
85099
|
+
const extMatch = xml.match(new RegExp(`<${tag2}[^>]*>([\\s\\S]*?)<\\/${tag2}>`));
|
|
84966
85100
|
if (!extMatch) continue;
|
|
84967
85101
|
const extXml = extMatch[1] ?? "";
|
|
84968
85102
|
logDebugStreamBlock({
|
|
84969
85103
|
logger,
|
|
84970
85104
|
traceNativeStream,
|
|
84971
85105
|
channel,
|
|
84972
|
-
tag,
|
|
85106
|
+
tag: tag2,
|
|
84973
85107
|
blockXml: extXml
|
|
84974
85108
|
});
|
|
84975
85109
|
const s = buildStream({
|
|
@@ -86562,7 +86696,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86562
86696
|
* @param logger - Optional logger for debug output
|
|
86563
86697
|
* @returns The socket and a release function
|
|
86564
86698
|
*/
|
|
86565
|
-
async acquirePooledSocket(
|
|
86699
|
+
async acquirePooledSocket(tag2, logger) {
|
|
86566
86700
|
const log = logger ?? this.logger;
|
|
86567
86701
|
const now = Date.now();
|
|
86568
86702
|
const cooldownEntry = this.socketPoolCooldowns.get(this.host);
|
|
@@ -86573,12 +86707,12 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86573
86707
|
} else if (now < cooldownEntry.cooldownUntil) {
|
|
86574
86708
|
const remainingMs = cooldownEntry.cooldownUntil - now;
|
|
86575
86709
|
const reason = this.lastD2cDiscAtMs > 0 && now - this.lastD2cDiscAtMs < 12e4 ? "D2C_DISC (camera sleeping)" : "repeated login failures";
|
|
86576
|
-
const error = /* @__PURE__ */ new Error(`[SocketPool] Host ${this.host} is in cooldown for ${Math.ceil(remainingMs / 1e3)}s due to ${reason}. tag=${
|
|
86710
|
+
const error = /* @__PURE__ */ new Error(`[SocketPool] Host ${this.host} is in cooldown for ${Math.ceil(remainingMs / 1e3)}s due to ${reason}. tag=${tag2}`);
|
|
86577
86711
|
log?.debug?.(error.message);
|
|
86578
86712
|
throw error;
|
|
86579
86713
|
}
|
|
86580
86714
|
}
|
|
86581
|
-
const existing = this.socketPool.get(
|
|
86715
|
+
const existing = this.socketPool.get(tag2);
|
|
86582
86716
|
if (existing) {
|
|
86583
86717
|
if (existing.idleCloseTimer) {
|
|
86584
86718
|
clearTimeout(existing.idleCloseTimer);
|
|
@@ -86588,35 +86722,35 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86588
86722
|
const client2 = await existing.pendingPromise;
|
|
86589
86723
|
existing.refCount++;
|
|
86590
86724
|
existing.lastUsedAt = Date.now();
|
|
86591
|
-
log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${
|
|
86725
|
+
log?.debug?.(`[SocketPool] Waited for pending socket creation for tag=${tag2} (refCount=${existing.refCount})`);
|
|
86592
86726
|
return {
|
|
86593
86727
|
client: client2,
|
|
86594
|
-
release: () => this.releasePooledSocket(
|
|
86728
|
+
release: () => this.releasePooledSocket(tag2, logger)
|
|
86595
86729
|
};
|
|
86596
86730
|
}
|
|
86597
86731
|
if (existing.refCount === 0) {
|
|
86598
86732
|
existing.refCount = 1;
|
|
86599
86733
|
existing.lastUsedAt = Date.now();
|
|
86600
|
-
log?.debug?.(`[SocketPool] Reusing idle socket for tag=${
|
|
86734
|
+
log?.debug?.(`[SocketPool] Reusing idle socket for tag=${tag2}`);
|
|
86601
86735
|
try {
|
|
86602
86736
|
if (!existing.client.loggedIn) await existing.client.login();
|
|
86603
86737
|
} catch {}
|
|
86604
86738
|
if (existing.client.loggedIn) return {
|
|
86605
86739
|
client: existing.client,
|
|
86606
|
-
release: () => this.releasePooledSocket(
|
|
86740
|
+
release: () => this.releasePooledSocket(tag2, logger)
|
|
86607
86741
|
};
|
|
86608
|
-
} else if (
|
|
86742
|
+
} else if (tag2.startsWith("replay:")) log?.debug?.(`[SocketPool] Preempting active replay socket for tag=${tag2}`);
|
|
86609
86743
|
else {
|
|
86610
86744
|
existing.refCount++;
|
|
86611
86745
|
existing.lastUsedAt = Date.now();
|
|
86612
|
-
log?.debug?.(`[SocketPool] Reusing active socket for tag=${
|
|
86746
|
+
log?.debug?.(`[SocketPool] Reusing active socket for tag=${tag2} (refCount=${existing.refCount})`);
|
|
86613
86747
|
return {
|
|
86614
86748
|
client: existing.client,
|
|
86615
|
-
release: () => this.releasePooledSocket(
|
|
86749
|
+
release: () => this.releasePooledSocket(tag2, logger)
|
|
86616
86750
|
};
|
|
86617
86751
|
}
|
|
86618
|
-
log?.debug?.(`[SocketPool] Closing existing socket for tag=${
|
|
86619
|
-
this.socketPool.delete(
|
|
86752
|
+
log?.debug?.(`[SocketPool] Closing existing socket for tag=${tag2} (recreating)`);
|
|
86753
|
+
this.socketPool.delete(tag2);
|
|
86620
86754
|
if (existing.generalPermitRelease) {
|
|
86621
86755
|
try {
|
|
86622
86756
|
existing.generalPermitRelease();
|
|
@@ -86629,10 +86763,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86629
86763
|
skipLogout: true
|
|
86630
86764
|
});
|
|
86631
86765
|
} catch (e) {
|
|
86632
|
-
log?.warn?.(`[SocketPool] Error closing old socket for tag=${
|
|
86766
|
+
log?.warn?.(`[SocketPool] Error closing old socket for tag=${tag2}: ${e}`);
|
|
86633
86767
|
}
|
|
86634
86768
|
}
|
|
86635
|
-
log?.log?.(`[SocketPool] Creating new socket for tag=${
|
|
86769
|
+
log?.log?.(`[SocketPool] Creating new socket for tag=${tag2}`);
|
|
86636
86770
|
const entry = {
|
|
86637
86771
|
client: void 0,
|
|
86638
86772
|
refCount: 0,
|
|
@@ -86649,7 +86783,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86649
86783
|
} : this.clientOptions);
|
|
86650
86784
|
this.attachD2cDiscListener(newClient);
|
|
86651
86785
|
newClient.on("error", (err) => {
|
|
86652
|
-
log?.debug?.(`[SocketPool] tag=${
|
|
86786
|
+
log?.debug?.(`[SocketPool] tag=${tag2} client error: ${err?.message ?? err}`);
|
|
86653
86787
|
});
|
|
86654
86788
|
await newClient.login();
|
|
86655
86789
|
const existingCooldown = this.socketPoolCooldowns.get(this.host);
|
|
@@ -86661,10 +86795,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86661
86795
|
entry.refCount = 1;
|
|
86662
86796
|
entry.lastUsedAt = Date.now();
|
|
86663
86797
|
delete entry.pendingPromise;
|
|
86664
|
-
log?.log?.(`[SocketPool] Socket connected for tag=${
|
|
86665
|
-
if (
|
|
86798
|
+
log?.log?.(`[SocketPool] Socket connected for tag=${tag2}`);
|
|
86799
|
+
if (tag2 !== "general") try {
|
|
86666
86800
|
const generalEntry = this.socketPool.get("general");
|
|
86667
|
-
if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${
|
|
86801
|
+
if (generalEntry?.client) entry.generalPermitRelease = generalEntry.client.acquirePermit(0, `streaming-peer:${tag2}`);
|
|
86668
86802
|
} catch {}
|
|
86669
86803
|
if (this.sessionGuardEnabled) this.maybeRebootOnTooManySessions();
|
|
86670
86804
|
return newClient;
|
|
@@ -86675,21 +86809,21 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86675
86809
|
if (failureCount >= _ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD) {
|
|
86676
86810
|
const backoffMs = Math.min(_ReolinkBaichuanApi.SOCKET_POOL_BASE_COOLDOWN_MS * Math.pow(2, failureCount - _ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD), _ReolinkBaichuanApi.SOCKET_POOL_MAX_COOLDOWN_MS);
|
|
86677
86811
|
cooldownUntil = now2 + backoffMs;
|
|
86678
|
-
log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}). Entering cooldown for ${Math.ceil(backoffMs / 1e3)}s. tag=${
|
|
86679
|
-
} else log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}/${_ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD} before cooldown). tag=${
|
|
86812
|
+
log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}). Entering cooldown for ${Math.ceil(backoffMs / 1e3)}s. tag=${tag2}`);
|
|
86813
|
+
} else log?.warn?.(`[SocketPool] Login failed for host=${this.host} (failure #${failureCount}/${_ReolinkBaichuanApi.SOCKET_POOL_FAILURE_THRESHOLD} before cooldown). tag=${tag2}`);
|
|
86680
86814
|
this.socketPoolCooldowns.set(this.host, {
|
|
86681
86815
|
failureCount,
|
|
86682
86816
|
lastFailureAt: now2,
|
|
86683
86817
|
cooldownUntil
|
|
86684
86818
|
});
|
|
86685
|
-
this.socketPool.delete(
|
|
86819
|
+
this.socketPool.delete(tag2);
|
|
86686
86820
|
throw loginError;
|
|
86687
86821
|
}
|
|
86688
86822
|
})();
|
|
86689
|
-
this.socketPool.set(
|
|
86823
|
+
this.socketPool.set(tag2, entry);
|
|
86690
86824
|
return {
|
|
86691
86825
|
client: await entry.pendingPromise,
|
|
86692
|
-
release: () => this.releasePooledSocket(
|
|
86826
|
+
release: () => this.releasePooledSocket(tag2, logger)
|
|
86693
86827
|
};
|
|
86694
86828
|
}
|
|
86695
86829
|
/**
|
|
@@ -86697,31 +86831,31 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86697
86831
|
* For shared sockets (general, streaming), just decrements refCount.
|
|
86698
86832
|
* For replay sockets, schedules idle close.
|
|
86699
86833
|
*/
|
|
86700
|
-
async releasePooledSocket(
|
|
86834
|
+
async releasePooledSocket(tag2, logger) {
|
|
86701
86835
|
const log = logger ?? this.logger;
|
|
86702
|
-
const entry = this.socketPool.get(
|
|
86836
|
+
const entry = this.socketPool.get(tag2);
|
|
86703
86837
|
if (!entry) return;
|
|
86704
86838
|
entry.refCount = Math.max(0, entry.refCount - 1);
|
|
86705
86839
|
entry.lastUsedAt = Date.now();
|
|
86706
|
-
log?.debug?.(`[SocketPool] Released socket for tag=${
|
|
86840
|
+
log?.debug?.(`[SocketPool] Released socket for tag=${tag2} (refCount=${entry.refCount})`);
|
|
86707
86841
|
if (entry.refCount > 0) return;
|
|
86708
|
-
const isReplayTag =
|
|
86709
|
-
const isStreamingTag =
|
|
86710
|
-
if (
|
|
86842
|
+
const isReplayTag = tag2.startsWith("replay:");
|
|
86843
|
+
const isStreamingTag = tag2.startsWith("streaming:");
|
|
86844
|
+
if (tag2 === "general") return;
|
|
86711
86845
|
if (isStreamingTag) {
|
|
86712
86846
|
if (entry.idleCloseTimer) return;
|
|
86713
86847
|
entry.idleCloseTimer = setTimeout(async () => {
|
|
86714
|
-
const current = this.socketPool.get(
|
|
86848
|
+
const current = this.socketPool.get(tag2);
|
|
86715
86849
|
if (!current) return;
|
|
86716
86850
|
if (current.refCount > 0) return;
|
|
86717
|
-
this.socketPool.delete(
|
|
86851
|
+
this.socketPool.delete(tag2);
|
|
86718
86852
|
if (current.generalPermitRelease) {
|
|
86719
86853
|
try {
|
|
86720
86854
|
current.generalPermitRelease();
|
|
86721
86855
|
} catch {}
|
|
86722
86856
|
current.generalPermitRelease = void 0;
|
|
86723
86857
|
}
|
|
86724
|
-
log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${
|
|
86858
|
+
log?.log?.(`[SocketPool] Closing idle streaming socket for tag=${tag2}`);
|
|
86725
86859
|
try {
|
|
86726
86860
|
await current.client.close({
|
|
86727
86861
|
reason: "streaming idle close",
|
|
@@ -86734,11 +86868,11 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86734
86868
|
if (isReplayTag) {
|
|
86735
86869
|
if (entry.idleCloseTimer) return;
|
|
86736
86870
|
entry.idleCloseTimer = setTimeout(async () => {
|
|
86737
|
-
const current = this.socketPool.get(
|
|
86871
|
+
const current = this.socketPool.get(tag2);
|
|
86738
86872
|
if (!current) return;
|
|
86739
86873
|
if (current.refCount > 0) return;
|
|
86740
|
-
this.socketPool.delete(
|
|
86741
|
-
log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${
|
|
86874
|
+
this.socketPool.delete(tag2);
|
|
86875
|
+
log?.debug?.(`[SocketPool] Closing idle replay socket for tag=${tag2} (keepalive expired)`);
|
|
86742
86876
|
try {
|
|
86743
86877
|
await current.client.close({
|
|
86744
86878
|
reason: "replay idle keepalive expired",
|
|
@@ -86748,24 +86882,24 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86748
86882
|
}, _ReolinkBaichuanApi.SOCKET_POOL_KEEPALIVE_MS);
|
|
86749
86883
|
return;
|
|
86750
86884
|
}
|
|
86751
|
-
this.socketPool.delete(
|
|
86885
|
+
this.socketPool.delete(tag2);
|
|
86752
86886
|
try {
|
|
86753
86887
|
await entry.client.close({
|
|
86754
86888
|
reason: "socket pool release",
|
|
86755
86889
|
skipLogout: true
|
|
86756
86890
|
});
|
|
86757
|
-
log?.log?.(`[SocketPool] Closed socket for tag=${
|
|
86891
|
+
log?.log?.(`[SocketPool] Closed socket for tag=${tag2}`);
|
|
86758
86892
|
} catch (e) {
|
|
86759
|
-
log?.warn?.(`[SocketPool] Error closing socket for tag=${
|
|
86893
|
+
log?.warn?.(`[SocketPool] Error closing socket for tag=${tag2}: ${e}`);
|
|
86760
86894
|
}
|
|
86761
86895
|
}
|
|
86762
86896
|
/**
|
|
86763
86897
|
* Force-close a socket by tag.
|
|
86764
86898
|
* Used to preempt existing connections before acquiring a new one.
|
|
86765
86899
|
*/
|
|
86766
|
-
async forceClosePooledSocket(
|
|
86900
|
+
async forceClosePooledSocket(tag2, logger) {
|
|
86767
86901
|
const log = logger ?? this.logger;
|
|
86768
|
-
const entry = this.socketPool.get(
|
|
86902
|
+
const entry = this.socketPool.get(tag2);
|
|
86769
86903
|
if (!entry) return false;
|
|
86770
86904
|
if (entry.idleCloseTimer) {
|
|
86771
86905
|
clearTimeout(entry.idleCloseTimer);
|
|
@@ -86777,16 +86911,16 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86777
86911
|
} catch {}
|
|
86778
86912
|
entry.generalPermitRelease = void 0;
|
|
86779
86913
|
}
|
|
86780
|
-
log?.debug?.(`[SocketPool] Force-closing socket for tag=${
|
|
86781
|
-
this.socketPool.delete(
|
|
86914
|
+
log?.debug?.(`[SocketPool] Force-closing socket for tag=${tag2}`);
|
|
86915
|
+
this.socketPool.delete(tag2);
|
|
86782
86916
|
try {
|
|
86783
86917
|
await entry.client.close({
|
|
86784
86918
|
reason: "force closed",
|
|
86785
86919
|
skipLogout: true
|
|
86786
86920
|
});
|
|
86787
|
-
log?.log?.(`[SocketPool] Force-closed socket for tag=${
|
|
86921
|
+
log?.log?.(`[SocketPool] Force-closed socket for tag=${tag2}`);
|
|
86788
86922
|
} catch (e) {
|
|
86789
|
-
log?.warn?.(`[SocketPool] Error during force-close for tag=${
|
|
86923
|
+
log?.warn?.(`[SocketPool] Error during force-close for tag=${tag2}: ${e}`);
|
|
86790
86924
|
}
|
|
86791
86925
|
return true;
|
|
86792
86926
|
}
|
|
@@ -86796,7 +86930,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86796
86930
|
async cleanupSocketPool() {
|
|
86797
86931
|
const entries = Array.from(this.socketPool.entries());
|
|
86798
86932
|
this.socketPool.clear();
|
|
86799
|
-
await Promise.allSettled(entries.map(async ([
|
|
86933
|
+
await Promise.allSettled(entries.map(async ([tag2, entry]) => {
|
|
86800
86934
|
try {
|
|
86801
86935
|
if (entry.idleCloseTimer) clearTimeout(entry.idleCloseTimer);
|
|
86802
86936
|
if (entry.generalPermitRelease) {
|
|
@@ -86805,7 +86939,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86805
86939
|
} catch {}
|
|
86806
86940
|
entry.generalPermitRelease = void 0;
|
|
86807
86941
|
}
|
|
86808
|
-
this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${
|
|
86942
|
+
this.logger?.debug?.(`[SocketPool] Cleanup: closing tag=${tag2}`);
|
|
86809
86943
|
await entry.client.close({
|
|
86810
86944
|
reason: "API cleanup",
|
|
86811
86945
|
skipLogout: true
|
|
@@ -86838,17 +86972,17 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86838
86972
|
* ```
|
|
86839
86973
|
*/
|
|
86840
86974
|
async createDedicatedSession(sessionKey, logger) {
|
|
86841
|
-
const
|
|
86842
|
-
(logger ?? this.logger)?.debug?.(`[SocketPool] createDedicatedSession sessionKey=${sessionKey} \u2192 tag=${
|
|
86843
|
-
return await this.acquirePooledSocket(
|
|
86975
|
+
const tag2 = this.resolveSocketTag(sessionKey);
|
|
86976
|
+
(logger ?? this.logger)?.debug?.(`[SocketPool] createDedicatedSession sessionKey=${sessionKey} \u2192 tag=${tag2}`);
|
|
86977
|
+
return await this.acquirePooledSocket(tag2, logger);
|
|
86844
86978
|
}
|
|
86845
86979
|
/**
|
|
86846
86980
|
* @deprecated Use forceClosePooledSocket via createDedicatedSession instead.
|
|
86847
86981
|
* Force-close a dedicated client if it exists.
|
|
86848
86982
|
*/
|
|
86849
86983
|
async forceCloseDedicatedClient(sessionKey, logger) {
|
|
86850
|
-
const
|
|
86851
|
-
return await this.forceClosePooledSocket(
|
|
86984
|
+
const tag2 = this.resolveSocketTag(sessionKey);
|
|
86985
|
+
return await this.forceClosePooledSocket(tag2, logger);
|
|
86852
86986
|
}
|
|
86853
86987
|
/**
|
|
86854
86988
|
* @deprecated Cleanup handled by cleanupSocketPool now.
|
|
@@ -86863,8 +86997,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
86863
86997
|
const debugCfg = this.client.getDebugConfig?.();
|
|
86864
86998
|
if (debugCfg) {
|
|
86865
86999
|
const sid = this.client.getSocketSessionId?.();
|
|
86866
|
-
const
|
|
86867
|
-
eventTraceLog(debugCfg, this.logger,
|
|
87000
|
+
const tag2 = sid ? `ReolinkSimpleEvent sid=${sid}` : "ReolinkSimpleEvent";
|
|
87001
|
+
eventTraceLog(debugCfg, this.logger, tag2, `dispatch type=${evt.type} channel=${evt.channel} timestamp=${evt.timestamp}`);
|
|
86868
87002
|
}
|
|
86869
87003
|
for (const cb of this.simpleEventListeners) try {
|
|
86870
87004
|
Promise.resolve(cb(evt)).catch((e) => {
|
|
@@ -87462,7 +87596,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
87462
87596
|
return;
|
|
87463
87597
|
}
|
|
87464
87598
|
entry.startInFlight = (async () => {
|
|
87465
|
-
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-
|
|
87599
|
+
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-2M4UO7MB-CB-tIHMA.mjs");
|
|
87466
87600
|
const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
|
|
87467
87601
|
const dedicated = await this.createDedicatedSession(sessionKey);
|
|
87468
87602
|
const stream = new BaichuanVideoStream2({
|
|
@@ -88029,8 +88163,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
88029
88163
|
const idleTimeoutMs = options?.idleTimeoutMs ?? 3e4;
|
|
88030
88164
|
const sessionKey = `talk:${options?.deviceId ?? "unknown"}:ch${channel}:${Date.now()}`;
|
|
88031
88165
|
logger?.info?.(`[DedicatedTalk] Creating session: ${sessionKey} (idleTimeout=${idleTimeoutMs}ms)`);
|
|
88032
|
-
const
|
|
88033
|
-
const { client: dedicatedClient, release } = await this.acquirePooledSocket(
|
|
88166
|
+
const tag2 = this.resolveSocketTag(sessionKey);
|
|
88167
|
+
const { client: dedicatedClient, release } = await this.acquirePooledSocket(tag2, logger);
|
|
88034
88168
|
const summary = this.getSocketPoolSummary();
|
|
88035
88169
|
logger?.info?.(`[DedicatedTalk] Session created [sessions: ${summary.count} active${summary.count > 0 ? ` (${summary.tags.join(", ")})` : ""}]`);
|
|
88036
88170
|
try {
|
|
@@ -88143,8 +88277,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
88143
88277
|
}
|
|
88144
88278
|
/** SetNetPort via Baichuan: cmd_id 36 (enable/disable rtsp/rtmp/onvif/http/https) */
|
|
88145
88279
|
async setPortEnabled(params) {
|
|
88146
|
-
const
|
|
88147
|
-
const xml = `<?xml version="1.0" encoding="UTF-8" ?><body><${
|
|
88280
|
+
const tag2 = `${params.port[0].toUpperCase()}${params.port.slice(1)}Port`;
|
|
88281
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" ?><body><${tag2} version="1.1"><enable>${params.enable ? 1 : 0}</enable></${tag2}></body>`;
|
|
88148
88282
|
await this.sendXml({
|
|
88149
88283
|
cmdId: 36,
|
|
88150
88284
|
payloadXml: xml
|
|
@@ -88175,13 +88309,13 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
88175
88309
|
*/
|
|
88176
88310
|
async setPortConfig(patch) {
|
|
88177
88311
|
const blocks = [];
|
|
88178
|
-
const append = (
|
|
88312
|
+
const append = (tag2, portField, cfg) => {
|
|
88179
88313
|
if (!cfg) return;
|
|
88180
88314
|
if (cfg.port === void 0 && cfg.enable === void 0) return;
|
|
88181
88315
|
const inner = [];
|
|
88182
88316
|
if (cfg.port !== void 0) inner.push(`<${portField}>${cfg.port}</${portField}>`);
|
|
88183
88317
|
if (cfg.enable !== void 0) inner.push(`<enable>${cfg.enable ? 1 : 0}</enable>`);
|
|
88184
|
-
blocks.push(`<${
|
|
88318
|
+
blocks.push(`<${tag2} version="1.1">${inner.join("")}</${tag2}>`);
|
|
88185
88319
|
};
|
|
88186
88320
|
append("ServerPort", "serverPort", patch.server);
|
|
88187
88321
|
append("HttpPort", "httpPort", patch.http);
|
|
@@ -88695,8 +88829,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
88695
88829
|
];
|
|
88696
88830
|
const current = await this.getEncXml(ch);
|
|
88697
88831
|
let updated = null;
|
|
88698
|
-
for (const
|
|
88699
|
-
const sectionRe = new RegExp(`(<${
|
|
88832
|
+
for (const tag2 of candidateTags) {
|
|
88833
|
+
const sectionRe = new RegExp(`(<${tag2}[^>]*>[\\s\\S]*?<videoEncType>)(\\d+)(</videoEncType>)`);
|
|
88700
88834
|
if (!sectionRe.test(current)) continue;
|
|
88701
88835
|
const next = current.replace(sectionRe, `$1${desired}$3`);
|
|
88702
88836
|
if (next !== current) {
|
|
@@ -89226,9 +89360,9 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
89226
89360
|
const streamType = params.streamType;
|
|
89227
89361
|
const logger = params.logger ?? this.logger;
|
|
89228
89362
|
const sessionKey = params.deviceId ? `replay:${params.deviceId}:ch${channel}` : `replay:standalone:ch${channel}:${Date.now()}`;
|
|
89229
|
-
const
|
|
89230
|
-
logger?.debug?.(`[startRecordingReplayStreamStandalone] sessionKey=${sessionKey} -> tag=${
|
|
89231
|
-
const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(
|
|
89363
|
+
const tag2 = this.resolveSocketTag(sessionKey);
|
|
89364
|
+
logger?.debug?.(`[startRecordingReplayStreamStandalone] sessionKey=${sessionKey} -> tag=${tag2}`);
|
|
89365
|
+
const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
|
|
89232
89366
|
const uid = await this.ensureUidForRecordings(channel, void 0);
|
|
89233
89367
|
const payloadXml = buildFileInfoListReplayByNameXml({
|
|
89234
89368
|
channel,
|
|
@@ -89331,8 +89465,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
89331
89465
|
const streamType = params.streamType;
|
|
89332
89466
|
const logger = params.logger ?? this.logger;
|
|
89333
89467
|
const sessionKey = params.deviceId ? `replay:${params.deviceId}:ch${channel}` : `replay:nvr:ch${channel}:${Date.now()}`;
|
|
89334
|
-
const
|
|
89335
|
-
const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(
|
|
89468
|
+
const tag2 = this.resolveSocketTag(sessionKey);
|
|
89469
|
+
const { client: dedicatedClient, release: releaseDedicatedClient } = await this.acquirePooledSocket(tag2, logger);
|
|
89336
89470
|
let uid;
|
|
89337
89471
|
try {
|
|
89338
89472
|
uid = await this.ensureUidForRecordings(channel, void 0);
|
|
@@ -91559,6 +91693,73 @@ ${stderr}`));
|
|
|
91559
91693
|
return result;
|
|
91560
91694
|
}
|
|
91561
91695
|
/**
|
|
91696
|
+
* Read the PTZ guard point ("monitoring point" in the app).
|
|
91697
|
+
*
|
|
91698
|
+
* cmd_id: 332
|
|
91699
|
+
*
|
|
91700
|
+
* Returns `null` when the camera has no readable guard configuration — never
|
|
91701
|
+
* a fabricated "none", because that answer is what a consumer uses to decide
|
|
91702
|
+
* whether to move the head.
|
|
91703
|
+
*/
|
|
91704
|
+
async getPtzGuard(channel) {
|
|
91705
|
+
const ch = this.normalizeChannel(channel);
|
|
91706
|
+
return parsePtzGuardXml(await this.sendXml({
|
|
91707
|
+
cmdId: 332,
|
|
91708
|
+
channel: ch,
|
|
91709
|
+
channelIdOverride: ch,
|
|
91710
|
+
extensionXml: buildPtzGuardExtensionXml(ch, "read"),
|
|
91711
|
+
messageClass: BC_CLASS_MODERN_24,
|
|
91712
|
+
streamType: 0
|
|
91713
|
+
}));
|
|
91714
|
+
}
|
|
91715
|
+
/**
|
|
91716
|
+
* Configure the PTZ guard point.
|
|
91717
|
+
*
|
|
91718
|
+
* cmd_id: 331 with `<command>setGrd</command>`
|
|
91719
|
+
*
|
|
91720
|
+
* `setPosition` pins the guard point to the head's CURRENT position. Leave it
|
|
91721
|
+
* false when only changing the timeout or the enable flag: re-sending it
|
|
91722
|
+
* would silently move a point the operator had already placed.
|
|
91723
|
+
*/
|
|
91724
|
+
async setPtzGuard(options, channel) {
|
|
91725
|
+
const ch = this.normalizeChannel(channel);
|
|
91726
|
+
await this.sendXml({
|
|
91727
|
+
cmdId: 331,
|
|
91728
|
+
channel: ch,
|
|
91729
|
+
channelIdOverride: ch,
|
|
91730
|
+
extensionXml: buildPtzGuardExtensionXml(ch, "write"),
|
|
91731
|
+
payloadXml: buildPtzGuardSetXml({
|
|
91732
|
+
channelId: ch,
|
|
91733
|
+
enabled: options.enabled,
|
|
91734
|
+
timeoutSeconds: options.timeoutSeconds,
|
|
91735
|
+
setPosition: options.setPosition === true
|
|
91736
|
+
}),
|
|
91737
|
+
messageClass: BC_CLASS_MODERN_24,
|
|
91738
|
+
streamType: 0
|
|
91739
|
+
});
|
|
91740
|
+
}
|
|
91741
|
+
/**
|
|
91742
|
+
* Send the head to the guard point NOW.
|
|
91743
|
+
*
|
|
91744
|
+
* cmd_id: 331 with `<command>toGrd</command>`
|
|
91745
|
+
*
|
|
91746
|
+
* This is the closest thing Baichuan has to a "go home": the guard point is
|
|
91747
|
+
* an operator-placed position, unlike preset slot 0 which merely happens to
|
|
91748
|
+
* be first.
|
|
91749
|
+
*/
|
|
91750
|
+
async goToPtzGuard(channel) {
|
|
91751
|
+
const ch = this.normalizeChannel(channel);
|
|
91752
|
+
await this.sendXml({
|
|
91753
|
+
cmdId: 331,
|
|
91754
|
+
channel: ch,
|
|
91755
|
+
channelIdOverride: ch,
|
|
91756
|
+
extensionXml: buildPtzGuardExtensionXml(ch, "write"),
|
|
91757
|
+
payloadXml: buildPtzGuardGoXml(ch),
|
|
91758
|
+
messageClass: BC_CLASS_MODERN_24,
|
|
91759
|
+
streamType: 0
|
|
91760
|
+
});
|
|
91761
|
+
}
|
|
91762
|
+
/**
|
|
91562
91763
|
* Read zoom/focus min/max/current positions.
|
|
91563
91764
|
* cmd_id: 294 (MSG_ID_GET_ZOOM_FOCUS)
|
|
91564
91765
|
*/
|
|
@@ -91651,10 +91852,10 @@ ${stderr}`));
|
|
|
91651
91852
|
notifyD2cDisc() {
|
|
91652
91853
|
const now = Date.now();
|
|
91653
91854
|
this.lastD2cDiscAtMs = now;
|
|
91654
|
-
const streamingTags = Array.from(this.socketPool.keys()).filter((
|
|
91855
|
+
const streamingTags = Array.from(this.socketPool.keys()).filter((tag2) => tag2.startsWith("streaming:"));
|
|
91655
91856
|
if (streamingTags.length > 0) {
|
|
91656
91857
|
this.logger?.log?.(`[D2C_DISC] Force-closing ${streamingTags.length} streaming socket(s): ${streamingTags.join(", ")}`);
|
|
91657
|
-
for (const
|
|
91858
|
+
for (const tag2 of streamingTags) this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
|
|
91658
91859
|
}
|
|
91659
91860
|
const immediateCooldownUntil = now + _ReolinkBaichuanApi.D2C_DISC_IMMEDIATE_COOLDOWN_MS;
|
|
91660
91861
|
const existing = this.socketPoolCooldowns.get(this.host);
|
|
@@ -91687,15 +91888,15 @@ ${stderr}`));
|
|
|
91687
91888
|
* Returns undefined if the client is not in the pool (e.g. it's the general socket used directly).
|
|
91688
91889
|
*/
|
|
91689
91890
|
findSocketTagForClient(client) {
|
|
91690
|
-
for (const [
|
|
91891
|
+
for (const [tag2, entry] of this.socketPool) if (entry.client === client) return tag2;
|
|
91691
91892
|
}
|
|
91692
91893
|
/**
|
|
91693
91894
|
* Reset the consecutive stream-start timeout counter for a streaming socket.
|
|
91694
91895
|
* Called on successful stream start.
|
|
91695
91896
|
*/
|
|
91696
91897
|
resetStreamTimeoutCounter(client) {
|
|
91697
|
-
const
|
|
91698
|
-
if (
|
|
91898
|
+
const tag2 = this.findSocketTagForClient(client);
|
|
91899
|
+
if (tag2) this.consecutiveStreamTimeouts.delete(tag2);
|
|
91699
91900
|
}
|
|
91700
91901
|
/**
|
|
91701
91902
|
* Track a stream-start timeout on a streaming socket.
|
|
@@ -91703,14 +91904,14 @@ ${stderr}`));
|
|
|
91703
91904
|
* socket so the next attempt creates a fresh connection.
|
|
91704
91905
|
*/
|
|
91705
91906
|
trackStreamTimeout(client) {
|
|
91706
|
-
const
|
|
91707
|
-
if (!
|
|
91708
|
-
const count = (this.consecutiveStreamTimeouts.get(
|
|
91709
|
-
this.consecutiveStreamTimeouts.set(
|
|
91907
|
+
const tag2 = this.findSocketTagForClient(client);
|
|
91908
|
+
if (!tag2 || !tag2.startsWith("streaming:")) return;
|
|
91909
|
+
const count = (this.consecutiveStreamTimeouts.get(tag2) ?? 0) + 1;
|
|
91910
|
+
this.consecutiveStreamTimeouts.set(tag2, count);
|
|
91710
91911
|
if (count >= _ReolinkBaichuanApi.MAX_CONSECUTIVE_STREAM_TIMEOUTS) {
|
|
91711
|
-
this.logger?.warn?.(`[SocketPool] ${count} consecutive stream timeouts on tag=${
|
|
91712
|
-
this.consecutiveStreamTimeouts.delete(
|
|
91713
|
-
this.forceClosePooledSocket(
|
|
91912
|
+
this.logger?.warn?.(`[SocketPool] ${count} consecutive stream timeouts on tag=${tag2}, force-closing socket`);
|
|
91913
|
+
this.consecutiveStreamTimeouts.delete(tag2);
|
|
91914
|
+
this.forceClosePooledSocket(tag2, this.logger).catch(() => {});
|
|
91714
91915
|
}
|
|
91715
91916
|
}
|
|
91716
91917
|
/**
|
|
@@ -92577,8 +92778,20 @@ ${xml}`);
|
|
|
92577
92778
|
const support = supportResult.status === "fulfilled" ? supportResult.value : void 0;
|
|
92578
92779
|
const abilities = abilitiesResult.status === "fulfilled" ? abilitiesResult.value : void 0;
|
|
92579
92780
|
const supportItem = getSupportItemForChannel(support, ch);
|
|
92781
|
+
let model;
|
|
92782
|
+
try {
|
|
92783
|
+
const info = await this.getInfo(void 0, { timeoutMs: 5e3 });
|
|
92784
|
+
model = typeof info?.type === "string" ? info.type : void 0;
|
|
92785
|
+
} catch (e) {
|
|
92786
|
+
this.logger.debug("[ReolinkBaichuanApi] getDeviceCapabilities: getInfo(type) failed", {
|
|
92787
|
+
host: this.host,
|
|
92788
|
+
channel: ch,
|
|
92789
|
+
err: e instanceof Error ? e.message : String(e)
|
|
92790
|
+
});
|
|
92791
|
+
}
|
|
92580
92792
|
const capabilities = computeDeviceCapabilities({
|
|
92581
92793
|
channel: ch,
|
|
92794
|
+
...model != null && { model },
|
|
92582
92795
|
...support != null && { support },
|
|
92583
92796
|
...abilities != null && { abilities }
|
|
92584
92797
|
});
|
|
@@ -93347,7 +93560,7 @@ ${xml}`);
|
|
|
93347
93560
|
* @returns Test results for all stream types and profiles
|
|
93348
93561
|
*/
|
|
93349
93562
|
async testChannelStreams(channel, logger) {
|
|
93350
|
-
const { testChannelStreams } = await import("./DiagnosticsTools-
|
|
93563
|
+
const { testChannelStreams } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
|
|
93351
93564
|
return await testChannelStreams({
|
|
93352
93565
|
api: this,
|
|
93353
93566
|
channel: this.normalizeChannel(channel),
|
|
@@ -93363,7 +93576,7 @@ ${xml}`);
|
|
|
93363
93576
|
* @returns Complete diagnostics for all channels and streams
|
|
93364
93577
|
*/
|
|
93365
93578
|
async collectMultifocalDiagnostics(logger) {
|
|
93366
|
-
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-
|
|
93579
|
+
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-GOFDNGAY-9NV95vRN.mjs");
|
|
93367
93580
|
return await collectMultifocalDiagnostics({
|
|
93368
93581
|
api: this,
|
|
93369
93582
|
logger
|
|
@@ -150155,15 +150368,39 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
150155
150368
|
*/
|
|
150156
150369
|
async resolveHomePreset() {
|
|
150157
150370
|
const chosen = this.config.get("homePresetId") ?? "";
|
|
150158
|
-
if (chosen
|
|
150371
|
+
if (chosen !== "") return {
|
|
150372
|
+
presetId: chosen,
|
|
150373
|
+
source: "operator"
|
|
150374
|
+
};
|
|
150375
|
+
if ((await this.readGuardStatus())?.valid === true) return {
|
|
150159
150376
|
presetId: null,
|
|
150160
|
-
source: "
|
|
150377
|
+
source: "native"
|
|
150161
150378
|
};
|
|
150162
150379
|
return {
|
|
150163
|
-
presetId:
|
|
150164
|
-
source: "
|
|
150380
|
+
presetId: null,
|
|
150381
|
+
source: "none"
|
|
150165
150382
|
};
|
|
150166
150383
|
}
|
|
150384
|
+
/**
|
|
150385
|
+
* The camera's guard-point configuration, or `null` when it cannot be read.
|
|
150386
|
+
*
|
|
150387
|
+
* Never a fabricated "no guard configured": that answer decides whether
|
|
150388
|
+
* `goHome` moves the head, and an unreadable camera is not evidence that no
|
|
150389
|
+
* guard point exists (D393).
|
|
150390
|
+
*/
|
|
150391
|
+
async readGuardStatus() {
|
|
150392
|
+
try {
|
|
150393
|
+
const api = await this.ensureApi();
|
|
150394
|
+
const channel = this.getChannel();
|
|
150395
|
+
return await api.getPtzGuard(channel);
|
|
150396
|
+
} catch (err) {
|
|
150397
|
+
this.ctx.logger.warn("reolink guard point unreadable — goHome will fall back", {
|
|
150398
|
+
tags: { deviceId: this.id },
|
|
150399
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
150400
|
+
});
|
|
150401
|
+
return null;
|
|
150402
|
+
}
|
|
150403
|
+
}
|
|
150167
150404
|
getChannel() {
|
|
150168
150405
|
const ch = this.config.get("channel");
|
|
150169
150406
|
if (typeof ch === "number" && ch >= 0) return ch;
|
|
@@ -153616,7 +153853,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
153616
153853
|
goHome: async ({ deviceId }) => {
|
|
153617
153854
|
if (deviceId !== this.id) return;
|
|
153618
153855
|
const home = await this.resolveHomePreset();
|
|
153619
|
-
if (home.source === "
|
|
153856
|
+
if (home.source === "native") {
|
|
153857
|
+
await (await this.ensureApi()).goToPtzGuard(this.getChannel());
|
|
153858
|
+
return;
|
|
153859
|
+
}
|
|
153860
|
+
if (home.source === "none" || home.presetId === null) throw new Error("No home preset configured for this camera, and it has no guard point set — set one in the PTZ settings, or place a guard point on the camera");
|
|
153620
153861
|
const id = Number(home.presetId);
|
|
153621
153862
|
if (!Number.isFinite(id)) throw new Error(`Configured home preset is not a Baichuan id: ${home.presetId}`);
|
|
153622
153863
|
const api = await this.ensureApi();
|
|
@@ -153630,6 +153871,34 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
153630
153871
|
};
|
|
153631
153872
|
return this.resolveHomePreset();
|
|
153632
153873
|
},
|
|
153874
|
+
captureHomeHere: async ({ deviceId }) => {
|
|
153875
|
+
if (deviceId !== this.id) return;
|
|
153876
|
+
const current = await this.readGuardStatus();
|
|
153877
|
+
const api = await this.ensureApi();
|
|
153878
|
+
const channel = this.getChannel();
|
|
153879
|
+
await api.setPtzGuard({
|
|
153880
|
+
enabled: current?.enabled ?? false,
|
|
153881
|
+
timeoutSeconds: current?.timeoutSeconds ?? 60,
|
|
153882
|
+
setPosition: true
|
|
153883
|
+
}, channel);
|
|
153884
|
+
this.ctx.logger.info("reolink: guard point pinned to the current position", { tags: { deviceId: this.id } });
|
|
153885
|
+
},
|
|
153886
|
+
getHomeReturnSeconds: async ({ deviceId }) => {
|
|
153887
|
+
if (deviceId !== this.id) return null;
|
|
153888
|
+
const guard = await this.readGuardStatus();
|
|
153889
|
+
return guard === null ? null : guard.timeoutSeconds;
|
|
153890
|
+
},
|
|
153891
|
+
setHomeReturnSeconds: async ({ deviceId, seconds }) => {
|
|
153892
|
+
if (deviceId !== this.id) return;
|
|
153893
|
+
const current = await this.readGuardStatus();
|
|
153894
|
+
const api = await this.ensureApi();
|
|
153895
|
+
const channel = this.getChannel();
|
|
153896
|
+
await api.setPtzGuard({
|
|
153897
|
+
enabled: current?.enabled ?? true,
|
|
153898
|
+
timeoutSeconds: seconds,
|
|
153899
|
+
setPosition: false
|
|
153900
|
+
}, channel);
|
|
153901
|
+
},
|
|
153633
153902
|
setHomePreset: async ({ deviceId, presetId }) => {
|
|
153634
153903
|
if (deviceId !== this.id) return;
|
|
153635
153904
|
await this.config.setAll({ homePresetId: presetId ?? "" });
|