@apocaliss92/nodelink-js 0.4.8 → 0.4.11
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/{DiagnosticsTools-HJDH4GPP.js → DiagnosticsTools-RNIDFEJK.js} +2 -2
- package/dist/{chunk-YKKQDUKU.js → chunk-EDLMKBG2.js} +224 -1
- package/dist/chunk-EDLMKBG2.js.map +1 -0
- package/dist/{chunk-VBYF3BQX.js → chunk-HGQ53FB3.js} +388 -4
- package/dist/chunk-HGQ53FB3.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +565 -1
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +614 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +736 -1
- package/dist/index.d.ts +812 -0
- package/dist/index.js +46 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-VBYF3BQX.js.map +0 -1
- package/dist/chunk-YKKQDUKU.js.map +0 -1
- /package/dist/{DiagnosticsTools-HJDH4GPP.js.map → DiagnosticsTools-RNIDFEJK.js.map} +0 -0
package/dist/cli/rtsp-server.cjs
CHANGED
|
@@ -60,7 +60,7 @@ var init_urls = __esm({
|
|
|
60
60
|
function bcHeaderHasPayloadOffset(messageClass) {
|
|
61
61
|
return messageClass === BC_CLASS_MODERN_24 || messageClass === BC_CLASS_MODERN_24_ALT || messageClass === BC_CLASS_FILE_DOWNLOAD;
|
|
62
62
|
}
|
|
63
|
-
var BC_TCP_DEFAULT_PORT, BC_MAGIC, BC_MAGIC_REV, BC_XML_KEY, BC_AES_IV, BC_CLASS_LEGACY, BC_CLASS_MODERN_20, BC_CLASS_MODERN_24, BC_CLASS_MODERN_24_ALT, BC_CLASS_FILE_DOWNLOAD, BC_CMD_ID_LOGOUT, BC_CMD_ID_VIDEO, BC_CMD_ID_VIDEO_STOP, BC_CMD_ID_FILE_INFO_LIST_REPLAY, BC_CMD_ID_FILE_INFO_LIST_STOP, BC_CMD_ID_FILE_INFO_LIST_DL_VIDEO, BC_CMD_ID_FILE_INFO_LIST_DOWNLOAD, BC_CMD_ID_FILE_INFO_LIST_OPEN, BC_CMD_ID_FILE_INFO_LIST_GET, BC_CMD_ID_FILE_INFO_LIST_CLOSE, BC_CMD_ID_FIND_REC_VIDEO_OPEN, BC_CMD_ID_FIND_REC_VIDEO_GET, BC_CMD_ID_FIND_REC_VIDEO_CLOSE, BC_CMD_ID_TALK_ABILITY, BC_CMD_ID_TALK_RESET, BC_CMD_ID_TALK_CONFIG, BC_CMD_ID_TALK, BC_CMD_ID_PTZ_CONTROL, BC_CMD_ID_PTZ_CONTROL_PRESET, BC_CMD_ID_GET_PTZ_PRESET, BC_CMD_ID_GET_PTZ_POSITION, BC_CMD_ID_GET_ZOOM_FOCUS, BC_CMD_ID_SET_ZOOM_FOCUS, BC_CMD_ID_GET_BATTERY_INFO_LIST, BC_CMD_ID_GET_BATTERY_INFO, BC_CMD_ID_UDP_KEEP_ALIVE, BC_CMD_ID_GET_PIR_INFO, BC_CMD_ID_SET_PIR_INFO, BC_CMD_ID_GET_MOTION_ALARM, BC_CMD_ID_SET_MOTION_ALARM, BC_CMD_ID_GET_AI_ALARM, BC_CMD_ID_SET_AI_ALARM, BC_CMD_ID_GET_AUDIO_ALARM, BC_CMD_ID_AUDIO_ALARM_PLAY, BC_CMD_ID_GET_WHITE_LED, BC_CMD_ID_SET_WHITE_LED_STATE, BC_CMD_ID_SET_WHITE_LED_TASK, BC_CMD_ID_FLOODLIGHT_STATUS_LIST, BC_CMD_ID_ABILITY_INFO, BC_CMD_ID_SUPPORT, BC_CMD_ID_PING, BC_CMD_ID_CHANNEL_INFO_ALL, BC_CMD_ID_GET_OSD_DATETIME, BC_CMD_ID_GET_RECORD_CFG, BC_CMD_ID_GET_ABILITY_SUPPORT, BC_CMD_ID_GET_FTP_TASK, BC_CMD_ID_GET_RECORD, BC_CMD_ID_GET_HDD_INFO_LIST, BC_CMD_ID_GET_WIFI_SIGNAL, BC_CMD_ID_GET_WIFI, BC_CMD_ID_GET_ONLINE_USER_LIST, BC_CMD_ID_GET_DAY_RECORDS, BC_CMD_ID_GET_STREAM_INFO_LIST, BC_CMD_ID_GET_LED_STATE, BC_CMD_ID_GET_EMAIL_TASK, BC_CMD_ID_GET_AUDIO_TASK, BC_CMD_ID_GET_AUDIO_CFG, BC_CMD_ID_GET_DAY_NIGHT_THRESHOLD, BC_CMD_ID_GET_TIMELAPSE_CFG, BC_CMD_ID_GET_AI_DENOISE, BC_CMD_ID_GET_KIT_AP_CFG, BC_CMD_ID_GET_REC_ENC_CFG, BC_CMD_ID_GET_ACCESS_USER_LIST, BC_CMD_ID_GET_SLEEP_STATE, BC_CMD_ID_GET_VIDEO_INPUT, BC_CMD_ID_GET_SYSTEM_GENERAL, BC_CMD_ID_GET_SUPPORT, BC_CMD_ID_GET_AI_CFG, BC_CMD_ID_SET_AI_CFG, BC_CMD_ID_GET_SIREN_STATUS, BC_CMD_ID_SET_AUDIO_TASK, BC_CMD_ID_CMD_123, BC_CMD_ID_CMD_209, BC_CMD_ID_CMD_265, BC_CMD_ID_CMD_440, BC_CMD_ID_PUSH_VIDEO_INPUT, BC_CMD_ID_PUSH_SERIAL, BC_CMD_ID_PUSH_NET_INFO, BC_CMD_ID_PUSH_DINGDONG_LIST, BC_CMD_ID_PUSH_SLEEP_STATUS, BC_CMD_ID_PUSH_COORDINATE_POINT_LIST, BC_CMD_ID_DING_DONG_CTRL, BC_CMD_ID_GET_DING_DONG_LIST, BC_CMD_ID_DING_DONG_OPT, BC_CMD_ID_GET_DING_DONG_CFG, BC_CMD_ID_SET_DING_DONG_CFG, BC_CMD_ID_QUICK_REPLY_PLAY, BC_CMD_ID_GET_DING_DONG_SILENT, BC_CMD_ID_SET_DING_DONG_SILENT;
|
|
63
|
+
var BC_TCP_DEFAULT_PORT, BC_MAGIC, BC_MAGIC_REV, BC_XML_KEY, BC_AES_IV, BC_CLASS_LEGACY, BC_CLASS_MODERN_20, BC_CLASS_MODERN_24, BC_CLASS_MODERN_24_ALT, BC_CLASS_FILE_DOWNLOAD, BC_CMD_ID_LOGOUT, BC_CMD_ID_VIDEO, BC_CMD_ID_VIDEO_STOP, BC_CMD_ID_FILE_INFO_LIST_REPLAY, BC_CMD_ID_FILE_INFO_LIST_STOP, BC_CMD_ID_FILE_INFO_LIST_DL_VIDEO, BC_CMD_ID_FILE_INFO_LIST_DOWNLOAD, BC_CMD_ID_FILE_INFO_LIST_OPEN, BC_CMD_ID_FILE_INFO_LIST_GET, BC_CMD_ID_FILE_INFO_LIST_CLOSE, BC_CMD_ID_FIND_REC_VIDEO_OPEN, BC_CMD_ID_FIND_REC_VIDEO_GET, BC_CMD_ID_FIND_REC_VIDEO_CLOSE, BC_CMD_ID_TALK_ABILITY, BC_CMD_ID_TALK_RESET, BC_CMD_ID_TALK_CONFIG, BC_CMD_ID_TALK, BC_CMD_ID_PTZ_CONTROL, BC_CMD_ID_PTZ_CONTROL_PRESET, BC_CMD_ID_GET_PTZ_PRESET, BC_CMD_ID_GET_PTZ_POSITION, BC_CMD_ID_GET_ZOOM_FOCUS, BC_CMD_ID_SET_ZOOM_FOCUS, BC_CMD_ID_GET_BATTERY_INFO_LIST, BC_CMD_ID_GET_BATTERY_INFO, BC_CMD_ID_UDP_KEEP_ALIVE, BC_CMD_ID_GET_PIR_INFO, BC_CMD_ID_SET_PIR_INFO, BC_CMD_ID_GET_MOTION_ALARM, BC_CMD_ID_SET_MOTION_ALARM, BC_CMD_ID_GET_AI_ALARM, BC_CMD_ID_SET_AI_ALARM, BC_CMD_ID_GET_AUDIO_ALARM, BC_CMD_ID_AUDIO_ALARM_PLAY, BC_CMD_ID_GET_WHITE_LED, BC_CMD_ID_SET_WHITE_LED_STATE, BC_CMD_ID_SET_WHITE_LED_TASK, BC_CMD_ID_FLOODLIGHT_STATUS_LIST, BC_CMD_ID_ABILITY_INFO, BC_CMD_ID_SUPPORT, BC_CMD_ID_PING, BC_CMD_ID_CHANNEL_INFO_ALL, BC_CMD_ID_GET_OSD_DATETIME, BC_CMD_ID_GET_RECORD_CFG, BC_CMD_ID_GET_ABILITY_SUPPORT, BC_CMD_ID_GET_FTP_TASK, BC_CMD_ID_GET_RECORD, BC_CMD_ID_GET_HDD_INFO_LIST, BC_CMD_ID_GET_WIFI_SIGNAL, BC_CMD_ID_GET_WIFI, BC_CMD_ID_GET_ONLINE_USER_LIST, BC_CMD_ID_GET_DAY_RECORDS, BC_CMD_ID_GET_STREAM_INFO_LIST, BC_CMD_ID_GET_LED_STATE, BC_CMD_ID_GET_EMAIL_TASK, BC_CMD_ID_GET_AUDIO_TASK, BC_CMD_ID_GET_AUDIO_CFG, BC_CMD_ID_GET_DAY_NIGHT_THRESHOLD, BC_CMD_ID_GET_TIMELAPSE_CFG, BC_CMD_ID_GET_AI_DENOISE, BC_CMD_ID_GET_KIT_AP_CFG, BC_CMD_ID_GET_REC_ENC_CFG, BC_CMD_ID_GET_ACCESS_USER_LIST, BC_CMD_ID_GET_SLEEP_STATE, BC_CMD_ID_GET_VIDEO_INPUT, BC_CMD_ID_GET_SYSTEM_GENERAL, BC_CMD_ID_GET_SUPPORT, BC_CMD_ID_GET_AI_CFG, BC_CMD_ID_SET_AI_CFG, BC_CMD_ID_GET_SIREN_STATUS, BC_CMD_ID_SET_AUDIO_TASK, BC_CMD_ID_SET_VIDEO_INPUT, BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD, BC_CMD_ID_GET_ENC, BC_CMD_ID_SET_ENC, BC_CMD_ID_GET_PRIVACY_MASK, BC_CMD_ID_SET_PRIVACY_MASK, BC_CMD_ID_SET_AI_DENOISE, BC_CMD_ID_SET_LED_STATE, BC_CMD_ID_SET_AUDIO_CFG, BC_CMD_ID_GET_AUTO_FOCUS, BC_CMD_ID_SET_AUTO_FOCUS, BC_CMD_ID_CMD_123, BC_CMD_ID_CMD_209, BC_CMD_ID_CMD_265, BC_CMD_ID_CMD_440, BC_CMD_ID_PUSH_VIDEO_INPUT, BC_CMD_ID_PUSH_SERIAL, BC_CMD_ID_PUSH_NET_INFO, BC_CMD_ID_PUSH_DINGDONG_LIST, BC_CMD_ID_PUSH_SLEEP_STATUS, BC_CMD_ID_PUSH_COORDINATE_POINT_LIST, BC_CMD_ID_DING_DONG_CTRL, BC_CMD_ID_GET_DING_DONG_LIST, BC_CMD_ID_DING_DONG_OPT, BC_CMD_ID_GET_DING_DONG_CFG, BC_CMD_ID_SET_DING_DONG_CFG, BC_CMD_ID_QUICK_REPLY_PLAY, BC_CMD_ID_GET_DING_DONG_SILENT, BC_CMD_ID_SET_DING_DONG_SILENT;
|
|
64
64
|
var init_constants = __esm({
|
|
65
65
|
"src/protocol/constants.ts"() {
|
|
66
66
|
"use strict";
|
|
@@ -154,6 +154,17 @@ var init_constants = __esm({
|
|
|
154
154
|
BC_CMD_ID_SET_AI_CFG = 300;
|
|
155
155
|
BC_CMD_ID_GET_SIREN_STATUS = 547;
|
|
156
156
|
BC_CMD_ID_SET_AUDIO_TASK = 231;
|
|
157
|
+
BC_CMD_ID_SET_VIDEO_INPUT = 25;
|
|
158
|
+
BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD = 297;
|
|
159
|
+
BC_CMD_ID_GET_ENC = 56;
|
|
160
|
+
BC_CMD_ID_SET_ENC = 57;
|
|
161
|
+
BC_CMD_ID_GET_PRIVACY_MASK = 52;
|
|
162
|
+
BC_CMD_ID_SET_PRIVACY_MASK = 53;
|
|
163
|
+
BC_CMD_ID_SET_AI_DENOISE = 440;
|
|
164
|
+
BC_CMD_ID_SET_LED_STATE = 209;
|
|
165
|
+
BC_CMD_ID_SET_AUDIO_CFG = 265;
|
|
166
|
+
BC_CMD_ID_GET_AUTO_FOCUS = 224;
|
|
167
|
+
BC_CMD_ID_SET_AUTO_FOCUS = 225;
|
|
157
168
|
BC_CMD_ID_CMD_123 = 123;
|
|
158
169
|
BC_CMD_ID_CMD_209 = 209;
|
|
159
170
|
BC_CMD_ID_CMD_265 = 265;
|
|
@@ -2691,6 +2702,59 @@ function buildFloodlightManualXml(channelId, status, durationSeconds = 180) {
|
|
|
2691
2702
|
</FloodlightManual>
|
|
2692
2703
|
</body>`;
|
|
2693
2704
|
}
|
|
2705
|
+
function ensureXmlHeader(xml) {
|
|
2706
|
+
const trimmed = xml.trimStart();
|
|
2707
|
+
if (trimmed.startsWith("<?xml")) return xml;
|
|
2708
|
+
return `${XML_HEADER}
|
|
2709
|
+
${xml}`;
|
|
2710
|
+
}
|
|
2711
|
+
function applyXmlTagPatch(xml, tag, value) {
|
|
2712
|
+
if (value === void 0) return xml;
|
|
2713
|
+
const v = typeof value === "boolean" ? value ? 1 : 0 : value;
|
|
2714
|
+
const re = new RegExp(`<${tag}>[^<]*</${tag}>`);
|
|
2715
|
+
return xml.replace(re, `<${tag}>${v}</${tag}>`);
|
|
2716
|
+
}
|
|
2717
|
+
function patchNestedTag(xml, parent, child, value) {
|
|
2718
|
+
if (value === void 0) return xml;
|
|
2719
|
+
const v = typeof value === "boolean" ? value ? 1 : 0 : value;
|
|
2720
|
+
const re = new RegExp(
|
|
2721
|
+
`(<${parent}[^>]*>[\\s\\S]*?<${child}>)[^<]*(</${child}>[\\s\\S]*?</${parent}>)`
|
|
2722
|
+
);
|
|
2723
|
+
return xml.replace(re, `$1${v}$2`);
|
|
2724
|
+
}
|
|
2725
|
+
function applyStreamPatch(xml, streamTag, patch) {
|
|
2726
|
+
if (!patch) return xml;
|
|
2727
|
+
const re = new RegExp(
|
|
2728
|
+
`(<${streamTag}[^>]*>)([\\s\\S]*?)(</${streamTag}>)`
|
|
2729
|
+
);
|
|
2730
|
+
return xml.replace(re, (_match, open, body, close) => {
|
|
2731
|
+
let next = body;
|
|
2732
|
+
if (patch.bitRate !== void 0) {
|
|
2733
|
+
next = applyXmlTagPatch(next, "bitRate", patch.bitRate);
|
|
2734
|
+
}
|
|
2735
|
+
if (patch.frameRate !== void 0) {
|
|
2736
|
+
next = applyXmlTagPatch(next, "frameRate", patch.frameRate);
|
|
2737
|
+
next = applyXmlTagPatch(next, "frame", patch.frameRate);
|
|
2738
|
+
}
|
|
2739
|
+
if (patch.videoEncType !== void 0) {
|
|
2740
|
+
const intVal = patch.videoEncType === "h265" ? 1 : 0;
|
|
2741
|
+
next = applyXmlTagPatch(next, "videoEncType", intVal);
|
|
2742
|
+
}
|
|
2743
|
+
return `${open}${next}${close}`;
|
|
2744
|
+
});
|
|
2745
|
+
}
|
|
2746
|
+
function normalizeDayNightMode(input) {
|
|
2747
|
+
const stripped = String(input).replace(/&/g, "And");
|
|
2748
|
+
if (!stripped) return stripped;
|
|
2749
|
+
const first = stripped[0];
|
|
2750
|
+
if (first === void 0) return stripped;
|
|
2751
|
+
return first.toLowerCase() + stripped.slice(1);
|
|
2752
|
+
}
|
|
2753
|
+
function normalizeOpenClose(input) {
|
|
2754
|
+
const v = String(input).toLowerCase();
|
|
2755
|
+
if (v === "on" || v === "open" || v === "1" || v === "true") return "open";
|
|
2756
|
+
return "close";
|
|
2757
|
+
}
|
|
2694
2758
|
function buildAbilityInfoExtensionXml(username) {
|
|
2695
2759
|
return `<?xml version="1.0" encoding="UTF-8" ?>
|
|
2696
2760
|
<Extension version="1.1">
|
|
@@ -2698,9 +2762,11 @@ function buildAbilityInfoExtensionXml(username) {
|
|
|
2698
2762
|
<token>system, streaming, PTZ, IO, security, replay, disk, network, alarm, record, video, image</token>
|
|
2699
2763
|
</Extension>`;
|
|
2700
2764
|
}
|
|
2765
|
+
var XML_HEADER;
|
|
2701
2766
|
var init_xml = __esm({
|
|
2702
2767
|
"src/protocol/xml.ts"() {
|
|
2703
2768
|
"use strict";
|
|
2769
|
+
XML_HEADER = `<?xml version="1.0" encoding="UTF-8" ?>`;
|
|
2704
2770
|
}
|
|
2705
2771
|
});
|
|
2706
2772
|
|
|
@@ -3520,6 +3586,137 @@ var init_ReolinkCgiApi = __esm({
|
|
|
3520
3586
|
const param = channel == null ? {} : { channel };
|
|
3521
3587
|
return await this.call("GetPtzPreset", param, 1);
|
|
3522
3588
|
}
|
|
3589
|
+
// ── Isp / Image (colour, flip, day-night, exposure) ──────────────
|
|
3590
|
+
async GetIsp(channel) {
|
|
3591
|
+
const param = channel == null ? {} : { channel };
|
|
3592
|
+
return await this.call("GetIsp", param, 1);
|
|
3593
|
+
}
|
|
3594
|
+
async SetIsp(isp) {
|
|
3595
|
+
return await this.call("SetIsp", isp, 0);
|
|
3596
|
+
}
|
|
3597
|
+
async GetImage(channel) {
|
|
3598
|
+
const param = channel == null ? {} : { channel };
|
|
3599
|
+
return await this.call("GetImage", param, 1);
|
|
3600
|
+
}
|
|
3601
|
+
async SetImage(image) {
|
|
3602
|
+
return await this.call("SetImage", image, 0);
|
|
3603
|
+
}
|
|
3604
|
+
// ── AudioCfg (mute / volume) ─────────────────────────────────────
|
|
3605
|
+
async GetAudioCfg(channel) {
|
|
3606
|
+
const param = channel == null ? {} : { channel };
|
|
3607
|
+
return await this.call("GetAudioCfg", param, 1);
|
|
3608
|
+
}
|
|
3609
|
+
async SetAudioCfg(audio) {
|
|
3610
|
+
return await this.call("SetAudioCfg", audio, 0);
|
|
3611
|
+
}
|
|
3612
|
+
// ── Enc setter (Get already exists above) ────────────────────────
|
|
3613
|
+
async SetEnc(enc) {
|
|
3614
|
+
return await this.call("SetEnc", enc, 0);
|
|
3615
|
+
}
|
|
3616
|
+
// ── MdAlarm (motion detection sensitivity / regions) ─────────────
|
|
3617
|
+
async GetMdAlarm(channel) {
|
|
3618
|
+
const param = channel == null ? {} : { channel };
|
|
3619
|
+
return await this.call("GetMdAlarm", param, 1);
|
|
3620
|
+
}
|
|
3621
|
+
async SetMdAlarm(md) {
|
|
3622
|
+
return await this.call("SetMdAlarm", md, 0);
|
|
3623
|
+
}
|
|
3624
|
+
// ── IrLights ─────────────────────────────────────────────────────
|
|
3625
|
+
async GetIrLights(channel) {
|
|
3626
|
+
const param = channel == null ? {} : { channel };
|
|
3627
|
+
return await this.call("GetIrLights", param, 1);
|
|
3628
|
+
}
|
|
3629
|
+
async SetIrLights(ir) {
|
|
3630
|
+
return await this.call("SetIrLights", ir, 0);
|
|
3631
|
+
}
|
|
3632
|
+
// ── AiCfg (smart-detection enable + class filter) ────────────────
|
|
3633
|
+
async GetAiCfg(channel) {
|
|
3634
|
+
const param = channel == null ? {} : { channel };
|
|
3635
|
+
return await this.call("GetAiCfg", param, 1);
|
|
3636
|
+
}
|
|
3637
|
+
async SetAiCfg(ai) {
|
|
3638
|
+
return await this.call("SetAiCfg", ai, 0);
|
|
3639
|
+
}
|
|
3640
|
+
// ── Mask (privacy-mask zones) ────────────────────────────────────
|
|
3641
|
+
async GetMask(channel) {
|
|
3642
|
+
return await this.call("GetMask", { channel }, 1);
|
|
3643
|
+
}
|
|
3644
|
+
async SetMask(mask) {
|
|
3645
|
+
return await this.call("SetMask", mask, 0);
|
|
3646
|
+
}
|
|
3647
|
+
// ── AudioNoise (input noise reduction) ───────────────────────────
|
|
3648
|
+
async GetAudioNoise(channel) {
|
|
3649
|
+
return await this.call("GetAudioNoise", { channel }, 1);
|
|
3650
|
+
}
|
|
3651
|
+
async SetAudioNoise(noise) {
|
|
3652
|
+
return await this.call("SetAudioNoise", noise, 0);
|
|
3653
|
+
}
|
|
3654
|
+
// ── Rec / RecV20 (recording schedule) ────────────────────────────
|
|
3655
|
+
async GetRec(channel) {
|
|
3656
|
+
return await this.call("GetRec", { channel }, 1);
|
|
3657
|
+
}
|
|
3658
|
+
async SetRec(rec) {
|
|
3659
|
+
return await this.call("SetRec", rec, 0);
|
|
3660
|
+
}
|
|
3661
|
+
/** Newer firmwares advertise `GetRecV20` / `SetRecV20` with the
|
|
3662
|
+
* weekly-schedule `table` field. Same payload shape as `Rec`. */
|
|
3663
|
+
async GetRecV20(channel) {
|
|
3664
|
+
return await this.call("GetRecV20", { channel }, 1);
|
|
3665
|
+
}
|
|
3666
|
+
async SetRecV20(rec) {
|
|
3667
|
+
return await this.call("SetRecV20", rec, 0);
|
|
3668
|
+
}
|
|
3669
|
+
// ── Email (SMTP alert) ───────────────────────────────────────────
|
|
3670
|
+
async GetEmail(channel) {
|
|
3671
|
+
return await this.call("GetEmail", { channel }, 1);
|
|
3672
|
+
}
|
|
3673
|
+
async SetEmail(email) {
|
|
3674
|
+
return await this.call("SetEmail", email, 0);
|
|
3675
|
+
}
|
|
3676
|
+
/** V20 variant on newer firmwares with weekly-schedule `table`. */
|
|
3677
|
+
async GetEmailV20(channel) {
|
|
3678
|
+
return await this.call("GetEmailV20", { channel }, 1);
|
|
3679
|
+
}
|
|
3680
|
+
async SetEmailV20(email) {
|
|
3681
|
+
return await this.call("SetEmailV20", email, 0);
|
|
3682
|
+
}
|
|
3683
|
+
// ── Push (Reolink-cloud push notifications) ──────────────────────
|
|
3684
|
+
async GetPush(channel) {
|
|
3685
|
+
return await this.call("GetPush", { channel }, 1);
|
|
3686
|
+
}
|
|
3687
|
+
async SetPush(push) {
|
|
3688
|
+
return await this.call("SetPush", push, 0);
|
|
3689
|
+
}
|
|
3690
|
+
async GetPushV20(channel) {
|
|
3691
|
+
return await this.call("GetPushV20", { channel }, 1);
|
|
3692
|
+
}
|
|
3693
|
+
async SetPushV20(push) {
|
|
3694
|
+
return await this.call("SetPushV20", push, 0);
|
|
3695
|
+
}
|
|
3696
|
+
// ── AudioAlarm (siren-on-event) ──────────────────────────────────
|
|
3697
|
+
async GetAudioAlarm(channel) {
|
|
3698
|
+
return await this.call("GetAudioAlarm", { channel }, 1);
|
|
3699
|
+
}
|
|
3700
|
+
async SetAudioAlarm(audio) {
|
|
3701
|
+
return await this.call("SetAudioAlarm", audio, 0);
|
|
3702
|
+
}
|
|
3703
|
+
async SetAudioAlarmV20(audio) {
|
|
3704
|
+
return await this.call("SetAudioAlarmV20", audio, 0);
|
|
3705
|
+
}
|
|
3706
|
+
// ── AutoFocus (PTZ AF) ───────────────────────────────────────────
|
|
3707
|
+
async GetAutoFocus(channel) {
|
|
3708
|
+
return await this.call("GetAutoFocus", { channel }, 1);
|
|
3709
|
+
}
|
|
3710
|
+
async SetAutoFocus(af) {
|
|
3711
|
+
return await this.call("SetAutoFocus", af, 0);
|
|
3712
|
+
}
|
|
3713
|
+
// ── AiAlarm (per-class smart-detection thresholds) ───────────────
|
|
3714
|
+
async GetAiAlarm(channel, aiType) {
|
|
3715
|
+
return await this.call("GetAiAlarm", { channel, ai_type: aiType }, 1);
|
|
3716
|
+
}
|
|
3717
|
+
async SetAiAlarm(ai) {
|
|
3718
|
+
return await this.call("SetAiAlarm", ai, 0);
|
|
3719
|
+
}
|
|
3523
3720
|
async GetAudioAlarmV20(channel) {
|
|
3524
3721
|
const param = channel == null ? {} : { channel };
|
|
3525
3722
|
return await this.call("GetAudioAlarmV20", param, 0);
|
|
@@ -25859,6 +26056,373 @@ ${xml}`
|
|
|
25859
26056
|
await this.cgiApi.login();
|
|
25860
26057
|
return await this.cgiApi.getAllChannelsEvents(options);
|
|
25861
26058
|
}
|
|
26059
|
+
// ====================================================================
|
|
26060
|
+
// Native Baichuan tunable-settings setters
|
|
26061
|
+
//
|
|
26062
|
+
// Replace the CGI passthroughs above with on-wire Baichuan binary
|
|
26063
|
+
// calls. Mirrors the @http_cmd-decorated methods in reolink_aio's
|
|
26064
|
+
// baichuan.py — every command has a documented `cmd_id` (read) and
|
|
26065
|
+
// `cmd_id` (write) pair. The pattern is:
|
|
26066
|
+
//
|
|
26067
|
+
// 1. read XML via `sendXml({ cmdId: GET, channel })`
|
|
26068
|
+
// 2. patch fields via regex (camera firmware is XML-strict; using
|
|
26069
|
+
// the parser would force us to rebuild the document and risk
|
|
26070
|
+
// losing unmodified attributes / element order).
|
|
26071
|
+
// 3. write back via `sendXml({ cmdId: SET, channel, payloadXml })`
|
|
26072
|
+
//
|
|
26073
|
+
// All getters parse via `parseXmlFragmentToJson` so the consumer gets
|
|
26074
|
+
// a clean JSON object instead of XML.
|
|
26075
|
+
// ====================================================================
|
|
26076
|
+
/**
|
|
26077
|
+
* GetEnc via Baichuan (cmdId=56). Returns the `<Compression>` block:
|
|
26078
|
+
* per-stream `mainStream` / `subStream` / `thirdStream` with `audio`
|
|
26079
|
+
* flag, `width`, `height`, `frame` (NOT `frameRate`), `bitRate`,
|
|
26080
|
+
* `videoEncType` (0=h264, 1=h265), `encoderProfile`, `gop`. Mirrors
|
|
26081
|
+
* reolink_aio's `GetEnc` — note the wire payload wraps everything
|
|
26082
|
+
* in `Compression`, not `Enc`.
|
|
26083
|
+
*/
|
|
26084
|
+
async getEnc(channel, options) {
|
|
26085
|
+
const xml = await this.sendPcapDerivedSettingsGetXml({
|
|
26086
|
+
cmdId: BC_CMD_ID_GET_ENC,
|
|
26087
|
+
...channel != null ? { channel } : {},
|
|
26088
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26089
|
+
});
|
|
26090
|
+
return parseXmlFragmentToJson(xml);
|
|
26091
|
+
}
|
|
26092
|
+
/**
|
|
26093
|
+
* SetEnc via Baichuan (cmdId=57). Read-modify-write — preserves
|
|
26094
|
+
* unspecified fields. Mirrors reolink_aio's `SetEnc`.
|
|
26095
|
+
*
|
|
26096
|
+
* @param channel - Channel number (0-based)
|
|
26097
|
+
* @param patch - Fields to update on `mainStream` and/or `subStream`,
|
|
26098
|
+
* plus a top-level `audio` toggle (0/1). Pass only what you want
|
|
26099
|
+
* to change.
|
|
26100
|
+
*/
|
|
26101
|
+
async setEnc(channel, patch, options) {
|
|
26102
|
+
const ch = this.normalizeChannel(channel);
|
|
26103
|
+
let xml = await this.sendXml({
|
|
26104
|
+
cmdId: BC_CMD_ID_GET_ENC,
|
|
26105
|
+
channel: ch,
|
|
26106
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26107
|
+
});
|
|
26108
|
+
if (patch.audio !== void 0) {
|
|
26109
|
+
xml = xml.replace(
|
|
26110
|
+
/<audio>[^<]*<\/audio>/g,
|
|
26111
|
+
`<audio>${patch.audio}</audio>`
|
|
26112
|
+
);
|
|
26113
|
+
}
|
|
26114
|
+
xml = applyStreamPatch(xml, "mainStream", patch.mainStream);
|
|
26115
|
+
xml = applyStreamPatch(xml, "subStream", patch.subStream);
|
|
26116
|
+
await this.sendXml({
|
|
26117
|
+
cmdId: BC_CMD_ID_SET_ENC,
|
|
26118
|
+
channel: ch,
|
|
26119
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26120
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26121
|
+
});
|
|
26122
|
+
}
|
|
26123
|
+
/**
|
|
26124
|
+
* SetImage via Baichuan (cmdId=25, read via cmdId=26). Patches the
|
|
26125
|
+
* `<VideoInput>` block: bright / contrast / saturation / hue /
|
|
26126
|
+
* sharpen. Mirrors reolink_aio's `SetImage`.
|
|
26127
|
+
*/
|
|
26128
|
+
async setImage(channel, patch, options) {
|
|
26129
|
+
const ch = this.normalizeChannel(channel);
|
|
26130
|
+
let xml = await this.sendXml({
|
|
26131
|
+
cmdId: BC_CMD_ID_GET_VIDEO_INPUT,
|
|
26132
|
+
channel: ch,
|
|
26133
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26134
|
+
});
|
|
26135
|
+
xml = applyXmlTagPatch(xml, "bright", patch.bright);
|
|
26136
|
+
xml = applyXmlTagPatch(xml, "contrast", patch.contrast);
|
|
26137
|
+
xml = applyXmlTagPatch(xml, "saturation", patch.saturation);
|
|
26138
|
+
xml = applyXmlTagPatch(xml, "hue", patch.hue);
|
|
26139
|
+
xml = applyXmlTagPatch(xml, "sharpen", patch.sharpen);
|
|
26140
|
+
await this.sendXml({
|
|
26141
|
+
cmdId: BC_CMD_ID_SET_VIDEO_INPUT,
|
|
26142
|
+
channel: ch,
|
|
26143
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26144
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26145
|
+
});
|
|
26146
|
+
}
|
|
26147
|
+
/**
|
|
26148
|
+
* SetIsp via Baichuan (cmdId=25 for image side, cmdId=297 for
|
|
26149
|
+
* dayNightThreshold). Patches the `<InputAdvanceCfg>` block:
|
|
26150
|
+
* `DayNight/mode`, `Exposure/mode`, `binning_mode`, `hdrSwitch`.
|
|
26151
|
+
* Mirrors reolink_aio's `SetIsp`.
|
|
26152
|
+
*
|
|
26153
|
+
* @param channel - Channel number (0-based)
|
|
26154
|
+
* @param patch - Fields to update. `dayNight` accepts the camera's
|
|
26155
|
+
* raw enum (`color`, `auto`, `blackAndWhite`, …) — pass it as the
|
|
26156
|
+
* camera reports it (PascalCase / dotted forms get normalized
|
|
26157
|
+
* server-side).
|
|
26158
|
+
*/
|
|
26159
|
+
async setIsp(channel, patch, options) {
|
|
26160
|
+
const ch = this.normalizeChannel(channel);
|
|
26161
|
+
const timeoutOpts = options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {};
|
|
26162
|
+
const wantsImageWrite = patch.dayNight !== void 0 || patch.exposure !== void 0 || patch.binningMode !== void 0 || patch.hdr !== void 0;
|
|
26163
|
+
if (wantsImageWrite) {
|
|
26164
|
+
let xml = await this.sendXml({
|
|
26165
|
+
cmdId: BC_CMD_ID_GET_VIDEO_INPUT,
|
|
26166
|
+
channel: ch,
|
|
26167
|
+
...timeoutOpts
|
|
26168
|
+
});
|
|
26169
|
+
if (patch.dayNight !== void 0) {
|
|
26170
|
+
const normalized = normalizeDayNightMode(patch.dayNight);
|
|
26171
|
+
xml = patchNestedTag(xml, "DayNight", "mode", normalized);
|
|
26172
|
+
}
|
|
26173
|
+
if (patch.exposure !== void 0) {
|
|
26174
|
+
xml = patchNestedTag(
|
|
26175
|
+
xml,
|
|
26176
|
+
"Exposure",
|
|
26177
|
+
"mode",
|
|
26178
|
+
patch.exposure.toLowerCase()
|
|
26179
|
+
);
|
|
26180
|
+
}
|
|
26181
|
+
if (patch.binningMode !== void 0) {
|
|
26182
|
+
xml = applyXmlTagPatch(xml, "binning_mode", patch.binningMode);
|
|
26183
|
+
}
|
|
26184
|
+
if (patch.hdr !== void 0) {
|
|
26185
|
+
xml = applyXmlTagPatch(xml, "hdrSwitch", patch.hdr);
|
|
26186
|
+
}
|
|
26187
|
+
await this.sendXml({
|
|
26188
|
+
cmdId: BC_CMD_ID_SET_VIDEO_INPUT,
|
|
26189
|
+
channel: ch,
|
|
26190
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26191
|
+
...timeoutOpts
|
|
26192
|
+
});
|
|
26193
|
+
}
|
|
26194
|
+
if (patch.dayNightThreshold !== void 0) {
|
|
26195
|
+
let xml = await this.sendXml({
|
|
26196
|
+
cmdId: BC_CMD_ID_GET_DAY_NIGHT_THRESHOLD,
|
|
26197
|
+
channel: ch,
|
|
26198
|
+
...timeoutOpts
|
|
26199
|
+
});
|
|
26200
|
+
xml = applyXmlTagPatch(xml, "cur", patch.dayNightThreshold);
|
|
26201
|
+
await this.sendXml({
|
|
26202
|
+
cmdId: BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD,
|
|
26203
|
+
channel: ch,
|
|
26204
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26205
|
+
...timeoutOpts
|
|
26206
|
+
});
|
|
26207
|
+
}
|
|
26208
|
+
}
|
|
26209
|
+
/**
|
|
26210
|
+
* GetIsp via Baichuan (cmdId=26). Convenience alias of
|
|
26211
|
+
* `getVideoInput()` so callers that switched from CGI keep the
|
|
26212
|
+
* familiar name. Both return the merged VideoInput +
|
|
26213
|
+
* InputAdvanceCfg blob.
|
|
26214
|
+
*/
|
|
26215
|
+
async getIsp(channel, options) {
|
|
26216
|
+
return this.getVideoInput(channel, options);
|
|
26217
|
+
}
|
|
26218
|
+
/** GetImage via Baichuan (cmdId=26). Same payload as `getIsp` —
|
|
26219
|
+
* Reolink merged VideoInput + InputAdvanceCfg under one cmdId. */
|
|
26220
|
+
async getImage(channel, options) {
|
|
26221
|
+
return this.getVideoInput(channel, options);
|
|
26222
|
+
}
|
|
26223
|
+
/**
|
|
26224
|
+
* GetIrLights via Baichuan (cmdId=208). Returns LedState block:
|
|
26225
|
+
* `IRLedBrightness`, `state` (ir on/off), `lightState` (status LED
|
|
26226
|
+
* open/close), `doorbellLightState`. Mirrors reolink_aio's
|
|
26227
|
+
* `get_status_led`.
|
|
26228
|
+
*/
|
|
26229
|
+
async getIrLights(channel, options) {
|
|
26230
|
+
const xml = await this.sendPcapDerivedSettingsGetXml({
|
|
26231
|
+
cmdId: BC_CMD_ID_GET_LED_STATE,
|
|
26232
|
+
...channel != null ? { channel } : {},
|
|
26233
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26234
|
+
});
|
|
26235
|
+
return parseXmlFragmentToJson(xml);
|
|
26236
|
+
}
|
|
26237
|
+
/**
|
|
26238
|
+
* SetIrLights via Baichuan (cmdId=209, read via cmdId=208). Patches
|
|
26239
|
+
* IR LED + status LED + doorbell LED + IR brightness. Mirrors
|
|
26240
|
+
* reolink_aio's `set_status_led`.
|
|
26241
|
+
*
|
|
26242
|
+
* @param channel - Channel number (0-based)
|
|
26243
|
+
* @param patch - `irState` ("On" | "Off" | "Auto"), `lightState`
|
|
26244
|
+
* (status LED), `doorbellLightState`, `irBrightness` (0..255).
|
|
26245
|
+
* Camera-side accepts lowercase strings (`open`/`close`); the
|
|
26246
|
+
* helper normalizes from the friendly variants.
|
|
26247
|
+
*/
|
|
26248
|
+
async setIrLights(channel, patch, options) {
|
|
26249
|
+
const ch = this.normalizeChannel(channel);
|
|
26250
|
+
const timeoutOpts = options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {};
|
|
26251
|
+
let xml = await this.sendXml({
|
|
26252
|
+
cmdId: BC_CMD_ID_GET_LED_STATE,
|
|
26253
|
+
channel: ch,
|
|
26254
|
+
...timeoutOpts
|
|
26255
|
+
});
|
|
26256
|
+
if (patch.lightState !== void 0) {
|
|
26257
|
+
xml = applyXmlTagPatch(
|
|
26258
|
+
xml,
|
|
26259
|
+
"lightState",
|
|
26260
|
+
patch.lightState === "On" ? "open" : "close"
|
|
26261
|
+
);
|
|
26262
|
+
}
|
|
26263
|
+
if (patch.doorbellLightState !== void 0) {
|
|
26264
|
+
xml = applyXmlTagPatch(
|
|
26265
|
+
xml,
|
|
26266
|
+
"doorbellLightState",
|
|
26267
|
+
normalizeOpenClose(patch.doorbellLightState)
|
|
26268
|
+
);
|
|
26269
|
+
}
|
|
26270
|
+
if (patch.irState !== void 0) {
|
|
26271
|
+
const v = String(patch.irState);
|
|
26272
|
+
const out = v === "Off" ? "close" : v.toLowerCase();
|
|
26273
|
+
xml = applyXmlTagPatch(xml, "state", out);
|
|
26274
|
+
}
|
|
26275
|
+
if (patch.irBrightness !== void 0) {
|
|
26276
|
+
xml = applyXmlTagPatch(xml, "IRLedBrightness", patch.irBrightness);
|
|
26277
|
+
}
|
|
26278
|
+
await this.sendXml({
|
|
26279
|
+
cmdId: BC_CMD_ID_SET_LED_STATE,
|
|
26280
|
+
channel: ch,
|
|
26281
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26282
|
+
...timeoutOpts
|
|
26283
|
+
});
|
|
26284
|
+
}
|
|
26285
|
+
/**
|
|
26286
|
+
* SetAudioCfg via Baichuan (cmdId=265, read via cmdId=264). Patches
|
|
26287
|
+
* volume / talk-and-reply / visitor settings. Mirrors reolink_aio's
|
|
26288
|
+
* `SetAudioCfg`.
|
|
26289
|
+
*/
|
|
26290
|
+
async setAudioCfg(channel, patch, options) {
|
|
26291
|
+
const ch = this.normalizeChannel(channel);
|
|
26292
|
+
const timeoutOpts = options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {};
|
|
26293
|
+
let xml = await this.sendXml({
|
|
26294
|
+
cmdId: BC_CMD_ID_GET_AUDIO_CFG,
|
|
26295
|
+
channel: ch,
|
|
26296
|
+
...timeoutOpts
|
|
26297
|
+
});
|
|
26298
|
+
xml = applyXmlTagPatch(xml, "volume", patch.volume);
|
|
26299
|
+
xml = applyXmlTagPatch(
|
|
26300
|
+
xml,
|
|
26301
|
+
"talkAndReplyVolume",
|
|
26302
|
+
patch.talkAndReplyVolume
|
|
26303
|
+
);
|
|
26304
|
+
xml = applyXmlTagPatch(xml, "visitorVolume", patch.visitorVolume);
|
|
26305
|
+
xml = applyXmlTagPatch(xml, "visitorLoudspeaker", patch.visitorLoudspeaker);
|
|
26306
|
+
await this.sendXml({
|
|
26307
|
+
cmdId: BC_CMD_ID_SET_AUDIO_CFG,
|
|
26308
|
+
channel: ch,
|
|
26309
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26310
|
+
...timeoutOpts
|
|
26311
|
+
});
|
|
26312
|
+
}
|
|
26313
|
+
/**
|
|
26314
|
+
* GetMask (privacy mask) via Baichuan (cmdId=52). Returns the
|
|
26315
|
+
* `<Shelter>` block — `enable` flag + `shelterList`. Mirrors
|
|
26316
|
+
* reolink_aio's `GetMask`.
|
|
26317
|
+
*/
|
|
26318
|
+
async getMask(channel, options) {
|
|
26319
|
+
const xml = await this.sendPcapDerivedSettingsGetXml({
|
|
26320
|
+
cmdId: BC_CMD_ID_GET_PRIVACY_MASK,
|
|
26321
|
+
...channel != null ? { channel } : {},
|
|
26322
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26323
|
+
});
|
|
26324
|
+
return parseXmlFragmentToJson(xml);
|
|
26325
|
+
}
|
|
26326
|
+
/**
|
|
26327
|
+
* SetMask (privacy mask) via Baichuan (cmdId=53, read via cmdId=52).
|
|
26328
|
+
* Toggles the `<Shelter><enable>` flag. Mirrors reolink_aio's
|
|
26329
|
+
* `SetMask` (which only touches enable too — shelter zone editing
|
|
26330
|
+
* goes through a separate flow).
|
|
26331
|
+
*/
|
|
26332
|
+
async setMask(channel, patch, options) {
|
|
26333
|
+
const ch = this.normalizeChannel(channel);
|
|
26334
|
+
const timeoutOpts = options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {};
|
|
26335
|
+
let xml = await this.sendXml({
|
|
26336
|
+
cmdId: BC_CMD_ID_GET_PRIVACY_MASK,
|
|
26337
|
+
channel: ch,
|
|
26338
|
+
...timeoutOpts
|
|
26339
|
+
});
|
|
26340
|
+
if (patch.enable !== void 0) {
|
|
26341
|
+
xml = applyXmlTagPatch(xml, "enable", patch.enable ? 1 : 0);
|
|
26342
|
+
}
|
|
26343
|
+
await this.sendXml({
|
|
26344
|
+
cmdId: BC_CMD_ID_SET_PRIVACY_MASK,
|
|
26345
|
+
channel: ch,
|
|
26346
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26347
|
+
...timeoutOpts
|
|
26348
|
+
});
|
|
26349
|
+
}
|
|
26350
|
+
/**
|
|
26351
|
+
* GetAudioNoise via Baichuan (cmdId=439). Reads `enable` + `level`
|
|
26352
|
+
* from the aiDenoise block. Mirrors reolink_aio's `GetAudioNoise`.
|
|
26353
|
+
*
|
|
26354
|
+
* Note: `getAiDenoise` already returns the same payload typed as
|
|
26355
|
+
* `AiDenoiseConfig`. This getter exists for naming parity with
|
|
26356
|
+
* reolink_aio + the reolink CGI.
|
|
26357
|
+
*/
|
|
26358
|
+
async getAudioNoise(channel, options) {
|
|
26359
|
+
const xml = await this.sendPcapDerivedSettingsGetXml({
|
|
26360
|
+
cmdId: BC_CMD_ID_GET_AI_DENOISE,
|
|
26361
|
+
...channel != null ? { channel } : {},
|
|
26362
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26363
|
+
});
|
|
26364
|
+
return parseXmlFragmentToJson(xml);
|
|
26365
|
+
}
|
|
26366
|
+
/**
|
|
26367
|
+
* SetAudioNoise via Baichuan (cmdId=440, read via cmdId=439).
|
|
26368
|
+
* Mirrors reolink_aio's `SetAudioNoise` — `level <= 0` flips the
|
|
26369
|
+
* enable flag off; positive values turn it on and update the level.
|
|
26370
|
+
*/
|
|
26371
|
+
async setAudioNoise(channel, level, options) {
|
|
26372
|
+
const ch = this.normalizeChannel(channel);
|
|
26373
|
+
const timeoutOpts = options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {};
|
|
26374
|
+
let xml = await this.sendXml({
|
|
26375
|
+
cmdId: BC_CMD_ID_GET_AI_DENOISE,
|
|
26376
|
+
channel: ch,
|
|
26377
|
+
...timeoutOpts
|
|
26378
|
+
});
|
|
26379
|
+
xml = applyXmlTagPatch(xml, "enable", level > 0 ? 1 : 0);
|
|
26380
|
+
if (level > 0) {
|
|
26381
|
+
xml = applyXmlTagPatch(xml, "level", level);
|
|
26382
|
+
}
|
|
26383
|
+
await this.sendXml({
|
|
26384
|
+
cmdId: BC_CMD_ID_SET_AI_DENOISE,
|
|
26385
|
+
channel: ch,
|
|
26386
|
+
payloadXml: ensureXmlHeader(xml),
|
|
26387
|
+
...timeoutOpts
|
|
26388
|
+
});
|
|
26389
|
+
}
|
|
26390
|
+
/**
|
|
26391
|
+
* GetAutoFocus via Baichuan (cmdId=224). Returns the `<AutoFocus>`
|
|
26392
|
+
* block — only `disable` (0 = AF on, 1 = AF off). Mirrors
|
|
26393
|
+
* reolink_aio's `GetAutoFocus`.
|
|
26394
|
+
*/
|
|
26395
|
+
async getAutoFocus(channel, options) {
|
|
26396
|
+
const ch = this.normalizeChannel(channel);
|
|
26397
|
+
const xml = await this.sendPcapDerivedSettingsGetXml({
|
|
26398
|
+
cmdId: BC_CMD_ID_GET_AUTO_FOCUS,
|
|
26399
|
+
channel: ch,
|
|
26400
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26401
|
+
});
|
|
26402
|
+
return parseXmlFragmentToJson(xml);
|
|
26403
|
+
}
|
|
26404
|
+
/**
|
|
26405
|
+
* SetAutoFocus via Baichuan (cmdId=225). Mirrors reolink_aio's
|
|
26406
|
+
* `SetAutoFocus`. Note: write-only command — the payload is built
|
|
26407
|
+
* from scratch (no read-modify-write needed).
|
|
26408
|
+
*/
|
|
26409
|
+
async setAutoFocus(channel, disable, options) {
|
|
26410
|
+
const ch = this.normalizeChannel(channel);
|
|
26411
|
+
const disableVal = disable ? 1 : 0;
|
|
26412
|
+
const payloadXml = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
26413
|
+
<body>
|
|
26414
|
+
<AutoFocus version="1.1">
|
|
26415
|
+
<channelId>${ch}</channelId>
|
|
26416
|
+
<disable>${disableVal}</disable>
|
|
26417
|
+
</AutoFocus>
|
|
26418
|
+
</body>`;
|
|
26419
|
+
await this.sendXml({
|
|
26420
|
+
cmdId: BC_CMD_ID_SET_AUTO_FOCUS,
|
|
26421
|
+
channel: ch,
|
|
26422
|
+
payloadXml,
|
|
26423
|
+
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
26424
|
+
});
|
|
26425
|
+
}
|
|
25862
26426
|
/**
|
|
25863
26427
|
* Passthrough to ReolinkCgiApi.getAllChannelsBatteryInfo.
|
|
25864
26428
|
* Fetches battery info for all channels via CGI (merged with channel status sleep flag).
|