@camstack/addon-provider-reolink 1.2.113 → 1.2.116
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/addon.js +286 -86
- package/dist/addon.mjs +286 -86
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import * as net2 from "net";
|
|
|
20
20
|
import netImpl from "net";
|
|
21
21
|
import { mkdir } from "fs/promises";
|
|
22
22
|
import os from "node:os";
|
|
23
|
-
//#region ../types/dist/event-category-
|
|
23
|
+
//#region ../types/dist/event-category-DAXzJeTX.mjs
|
|
24
24
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
25
25
|
EventCategory["SystemBoot"] = "system.boot";
|
|
26
26
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -612,7 +612,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
612
612
|
* issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
|
|
613
613
|
*/
|
|
614
614
|
EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
|
|
615
|
-
EventCategory["FrigateLiveEvent"] = "frigate.live-event";
|
|
616
615
|
EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
|
|
617
616
|
/**
|
|
618
617
|
* Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
|
|
@@ -13224,7 +13223,7 @@ DeviceType.Camera;
|
|
|
13224
13223
|
var SourceInfoSchema = object({
|
|
13225
13224
|
/** Live dispatch key — mutable when the source system allows rename. */
|
|
13226
13225
|
id: string(),
|
|
13227
|
-
/** Source system tag — e.g. 'homeassistant' | 'reolink' | '
|
|
13226
|
+
/** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
|
|
13228
13227
|
system: string(),
|
|
13229
13228
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
13230
13229
|
* Used to detect rename when `id` changes. */
|
|
@@ -13237,7 +13236,7 @@ var SourceInfoSchema = object({
|
|
|
13237
13236
|
/**
|
|
13238
13237
|
* Build the synthetic SourceInfo every existing provider falls back to
|
|
13239
13238
|
* when no upstream value has been persisted. Keeps non-migrated providers
|
|
13240
|
-
* (Reolink / Hikvision / ONVIF /
|
|
13239
|
+
* (Reolink / Hikvision / ONVIF / RTSP) functional without code
|
|
13241
13240
|
* changes — `id` reuses the CamStack stableId, `system` reuses the addon
|
|
13242
13241
|
* id. Real upstream identity replaces this once a provider migrates and
|
|
13243
13242
|
* calls `updateSourceInfo()` with concrete values.
|
|
@@ -13899,7 +13898,7 @@ var deviceProviderCapability = {
|
|
|
13899
13898
|
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13900
13899
|
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13901
13900
|
*
|
|
13902
|
-
* All device provider addons (rtsp, onvif,
|
|
13901
|
+
* All device provider addons (rtsp, onvif, …) are hub-local: they may
|
|
13903
13902
|
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13904
13903
|
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13905
13904
|
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
@@ -17987,7 +17986,7 @@ var NcRuleInputSchema = object({
|
|
|
17987
17986
|
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
17988
17987
|
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
17989
17988
|
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
17990
|
-
* 30 is
|
|
17989
|
+
* 30 s is a widely shipped value for the same decision.
|
|
17991
17990
|
*
|
|
17992
17991
|
* ### What it replaces
|
|
17993
17992
|
*
|
|
@@ -20069,6 +20068,13 @@ var ZoneCrossingSchema = object({
|
|
|
20069
20068
|
/** Zone display name at crossing time (falls back to the id). */
|
|
20070
20069
|
zoneName: string().optional()
|
|
20071
20070
|
});
|
|
20071
|
+
/** One zone a box was stamped with, and how much of the BOX fell inside it. */
|
|
20072
|
+
var ZoneOverlapSchema = object({
|
|
20073
|
+
zoneId: string(),
|
|
20074
|
+
zoneName: string().optional(),
|
|
20075
|
+
/** Percentage of the BOX area inside the zone, 0–100. */
|
|
20076
|
+
overlapPct: number()
|
|
20077
|
+
});
|
|
20072
20078
|
var ObjectEventSchema = object({
|
|
20073
20079
|
...BaseEventFields,
|
|
20074
20080
|
kind: literal("object"),
|
|
@@ -20093,6 +20099,35 @@ var ObjectEventSchema = object({
|
|
|
20093
20099
|
bbox: BoundingBoxSchema.optional(),
|
|
20094
20100
|
/** Heavy JSON — omitted in slim projection. */
|
|
20095
20101
|
zones: array(string()).readonly().optional(),
|
|
20102
|
+
/**
|
|
20103
|
+
* How far inside each stamped zone the box actually was, as a percentage of
|
|
20104
|
+
* the BOX area.
|
|
20105
|
+
*
|
|
20106
|
+
* Membership alone cannot express "at least a third of it inside", which is
|
|
20107
|
+
* the bar an operator argues with — and the number already existed: the
|
|
20108
|
+
* engine computed it, the pipeline logged it, and then discarded it. It
|
|
20109
|
+
* matters most on the events that carry no track, where a rule has nothing
|
|
20110
|
+
* else to judge by.
|
|
20111
|
+
*/
|
|
20112
|
+
zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
|
|
20113
|
+
/**
|
|
20114
|
+
* Present when this event describes a detection the TRACKER refused, so it
|
|
20115
|
+
* has no track and never will.
|
|
20116
|
+
*
|
|
20117
|
+
* A zone-scoped immediate rule asks "is there an animal in the flowerbed
|
|
20118
|
+
* NOW?"; tracking answers a different question ("is this the same subject as
|
|
20119
|
+
* before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
|
|
20120
|
+
* dog at 0.7729, 100% inside a watched zone, was refused three times in six
|
|
20121
|
+
* seconds with three different candidate ids — seven analysed frames in the
|
|
20122
|
+
* window, the subject in a handful of them, metres apart — and produced no
|
|
20123
|
+
* event at all.
|
|
20124
|
+
*
|
|
20125
|
+
* It is NAMED rather than merely implied by a missing `trackId`: an event
|
|
20126
|
+
* with no track and no reason is indistinguishable from a track whose media
|
|
20127
|
+
* went missing, and a consumer that asks this one for a best shot or a
|
|
20128
|
+
* history is asking for something that never existed.
|
|
20129
|
+
*/
|
|
20130
|
+
spawnRefused: string().optional(),
|
|
20096
20131
|
/** Omitted in slim projection. */
|
|
20097
20132
|
state: TrackStateSchema.optional(),
|
|
20098
20133
|
/**
|
|
@@ -20519,7 +20554,17 @@ var EventDensityBucketSchema = object({
|
|
|
20519
20554
|
bucketStart: number(),
|
|
20520
20555
|
motion: number().int(),
|
|
20521
20556
|
object: number().int(),
|
|
20522
|
-
audio: number().int()
|
|
20557
|
+
audio: number().int(),
|
|
20558
|
+
/**
|
|
20559
|
+
* Energy-weighted mean dBFS of the audio events in this bucket — the LEVEL,
|
|
20560
|
+
* as opposed to `audio`, which is their COUNT (D431).
|
|
20561
|
+
*
|
|
20562
|
+
* ABSENT when the bucket holds no audio event. Absence means "nothing was
|
|
20563
|
+
* measured", which is not the same claim as silence, and a lane that cannot
|
|
20564
|
+
* tell them apart paints a quiet hour at full scale — which is exactly what
|
|
20565
|
+
* the count-on-a-level-meter did.
|
|
20566
|
+
*/
|
|
20567
|
+
audioDbfs: number().optional()
|
|
20523
20568
|
});
|
|
20524
20569
|
/**
|
|
20525
20570
|
* One camera's row in a `getEventDensityBatch` answer.
|
|
@@ -21166,6 +21211,60 @@ var NativeCropResultSchema = object({
|
|
|
21166
21211
|
*/
|
|
21167
21212
|
tier: _enum(["native", "ram-fullframe"]).optional()
|
|
21168
21213
|
});
|
|
21214
|
+
/**
|
|
21215
|
+
* What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
|
|
21216
|
+
* kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
|
|
21217
|
+
*
|
|
21218
|
+
* - `keyFrame` — the track's clean best FULL frame at native width (capped by
|
|
21219
|
+
* the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
|
|
21220
|
+
* from, and what the detail plane's full-frame rung cuts from.
|
|
21221
|
+
* - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
|
|
21222
|
+
* window, cut by the runner at uncapped native resolution.
|
|
21223
|
+
*
|
|
21224
|
+
* The runner never interprets `trackId`; it is an opaque key the hub owns.
|
|
21225
|
+
*/
|
|
21226
|
+
var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
|
|
21227
|
+
/**
|
|
21228
|
+
* Why a park did NOT happen. Every one is logged on the runner with
|
|
21229
|
+
* `tags: { deviceId }` and the handle's measured age, because a handle already
|
|
21230
|
+
* gone at park time IS the defect the 150–500 ms window exists to prevent —
|
|
21231
|
+
* never a reason to retry in a loop.
|
|
21232
|
+
*
|
|
21233
|
+
* - `handle-gone` — the native surface no longer resolves this handle (never
|
|
21234
|
+
* registered, past the lease bound, or the worker released it). `detail`
|
|
21235
|
+
* carries the runner's own miss reason.
|
|
21236
|
+
* - `encode-failed` — pixels resolved and the JPEG encode threw.
|
|
21237
|
+
*/
|
|
21238
|
+
var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
|
|
21239
|
+
/** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
|
|
21240
|
+
var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
|
|
21241
|
+
parked: literal(true),
|
|
21242
|
+
/** The node holding the parcel — what a later retrieval must be pinned to. */
|
|
21243
|
+
nodeId: string(),
|
|
21244
|
+
width: number().int().positive(),
|
|
21245
|
+
height: number().int().positive(),
|
|
21246
|
+
/** JPEG bytes the parcel costs on the node. */
|
|
21247
|
+
bytes: number().int().nonnegative(),
|
|
21248
|
+
/** Whether this park replaced a parcel already held for the key. */
|
|
21249
|
+
replaced: boolean()
|
|
21250
|
+
}), object({
|
|
21251
|
+
parked: literal(false),
|
|
21252
|
+
nodeId: string(),
|
|
21253
|
+
reason: ParkRefusalSchema,
|
|
21254
|
+
/** Age of the handle at the park, on the runner's clock; null if unknown. */
|
|
21255
|
+
handleAgeMs: number().nullable(),
|
|
21256
|
+
detail: string().optional()
|
|
21257
|
+
})]);
|
|
21258
|
+
/** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
|
|
21259
|
+
var ParkedTrackFrameSchema = object({
|
|
21260
|
+
jpeg: string(),
|
|
21261
|
+
width: number().int().positive(),
|
|
21262
|
+
height: number().int().positive(),
|
|
21263
|
+
/** The frame instant the parcel shows (the caller's clock, echoed back). */
|
|
21264
|
+
timestamp: number(),
|
|
21265
|
+
/** When the node stored it (the node's clock). */
|
|
21266
|
+
parkedAt: number()
|
|
21267
|
+
});
|
|
21169
21268
|
/** Parent detection context passed to `runDetailSubtree` — the crop's
|
|
21170
21269
|
* originating detection, in FRAME-space coordinates. Reuses
|
|
21171
21270
|
* `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
|
|
@@ -21555,7 +21654,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
21555
21654
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
21556
21655
|
* analyzer providers) running on decoded frames in this runner.
|
|
21557
21656
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
21558
|
-
* analytics
|
|
21657
|
+
* analytics). The provider emits ProviderMotion
|
|
21559
21658
|
* events; the orchestrator forwards to `reportMotion`.
|
|
21560
21659
|
*/
|
|
21561
21660
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
@@ -21797,7 +21896,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
|
|
|
21797
21896
|
className: string(),
|
|
21798
21897
|
/** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
|
|
21799
21898
|
sourceDeviceId: number()
|
|
21800
|
-
}), RunStatelessStepResultSchema, { kind: "mutation" })
|
|
21899
|
+
}), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
|
|
21900
|
+
deviceId: number(),
|
|
21901
|
+
/** Opaque to the runner — the hub's track id. */
|
|
21902
|
+
trackId: string(),
|
|
21903
|
+
kind: ParkedFrameKindSchema,
|
|
21904
|
+
handle: FrameHandleSchema,
|
|
21905
|
+
/** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
|
|
21906
|
+
bbox: NativeCropBboxSchema,
|
|
21907
|
+
/** Width cap for a full-frame park (the `keyFrame` native cap). */
|
|
21908
|
+
maxWidth: number().int().positive().optional(),
|
|
21909
|
+
/** The frame instant (caller's clock) — orders parks for one key. */
|
|
21910
|
+
timestamp: number()
|
|
21911
|
+
}), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
|
|
21912
|
+
deviceId: number(),
|
|
21913
|
+
trackId: string(),
|
|
21914
|
+
kind: ParkedFrameKindSchema
|
|
21915
|
+
}), ParkedTrackFrameSchema.nullable()), method(object({
|
|
21916
|
+
deviceId: number(),
|
|
21917
|
+
trackId: string()
|
|
21918
|
+
}), object({ released: number().int().nonnegative() }), { kind: "mutation" });
|
|
21801
21919
|
var CameraPipelineConfigSchema = object({
|
|
21802
21920
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
21803
21921
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -24971,8 +25089,8 @@ onStatusChanged: { data: object({
|
|
|
24971
25089
|
/**
|
|
24972
25090
|
* Runtime-state slice — every provider that registers this cap
|
|
24973
25091
|
* stores the same shape under `device.runtimeState[battery]`.
|
|
24974
|
-
* Cross-provider uniformity: a Reolink Argus, a
|
|
24975
|
-
*
|
|
25092
|
+
* Cross-provider uniformity: a Reolink Argus, a sensor proxy,
|
|
25093
|
+
* an ONVIF battery cam all read/write the same keys.
|
|
24976
25094
|
* Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
|
|
24977
25095
|
* via `device.runtimeState.getCapState('battery')` regardless of
|
|
24978
25096
|
* the underlying driver.
|
|
@@ -25105,7 +25223,7 @@ DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _v
|
|
|
25105
25223
|
*
|
|
25106
25224
|
* Implementations:
|
|
25107
25225
|
* - Each camera-providing addon registers this cap natively per
|
|
25108
|
-
* device (Reolink, Hikvision, RTSP,
|
|
25226
|
+
* device (Reolink, Hikvision, RTSP, ONVIF self).
|
|
25109
25227
|
* - Returns a snapshot from the persisted device config blob — no
|
|
25110
25228
|
* extra round-trip to the camera, no probing.
|
|
25111
25229
|
* - The cap is admin-only (`auth: 'admin'`) — credentials must not
|
|
@@ -27197,7 +27315,7 @@ var AvailableIntegrationTypeSchema = object({
|
|
|
27197
27315
|
* Which integration-marker cap the addon declared, so the wizard can
|
|
27198
27316
|
* branch on CAP — never on addon name. `device-adoption` integrations
|
|
27199
27317
|
* (Home Assistant, …) route through the broker step (Approach A);
|
|
27200
|
-
* `device-provider` integrations (Reolink/
|
|
27318
|
+
* `device-provider` integrations (Reolink/ONVIF) keep the
|
|
27201
27319
|
* legacy config → discovery flow.
|
|
27202
27320
|
*/
|
|
27203
27321
|
kind: _enum(["device-adoption", "device-provider"]),
|
|
@@ -30672,7 +30790,23 @@ var RecordingRangeSchema = object({
|
|
|
30672
30790
|
});
|
|
30673
30791
|
var RecordingAvailabilitySchema = object({
|
|
30674
30792
|
deviceId: number(),
|
|
30675
|
-
ranges: array(RecordingRangeSchema)
|
|
30793
|
+
ranges: array(RecordingRangeSchema),
|
|
30794
|
+
/**
|
|
30795
|
+
* Every profile this camera has footage in — not only the one `ranges`
|
|
30796
|
+
* describes (D433).
|
|
30797
|
+
*
|
|
30798
|
+
* `ranges` answers for ONE profile by design: the timeline is a single bar,
|
|
30799
|
+
* and enumerating all of them triples the directory reads for a bar that
|
|
30800
|
+
* would look identical. But the answer used to say nothing about that, so a
|
|
30801
|
+
* caller asking "what can I export?" read the single preferred profile as
|
|
30802
|
+
* the only one that exists — on this deployment every camera records `high`
|
|
30803
|
+
* AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
|
|
30804
|
+
* UI could not see it.
|
|
30805
|
+
*
|
|
30806
|
+
* Cheap: it is the same shallow directory read the profile CHOICE already
|
|
30807
|
+
* makes. Ask for a specific profile's ranges with the `profile` input.
|
|
30808
|
+
*/
|
|
30809
|
+
profilesWithFootage: array(string())
|
|
30676
30810
|
});
|
|
30677
30811
|
var RecordingDaysSchema = object({
|
|
30678
30812
|
deviceId: number(),
|
|
@@ -30698,7 +30832,11 @@ var RecordingDaysSchema = object({
|
|
|
30698
30832
|
var RecordingAvailabilityForDeviceSchema = object({
|
|
30699
30833
|
deviceId: number(),
|
|
30700
30834
|
read: _enum(["read", "unreadable"]),
|
|
30701
|
-
ranges: array(RecordingRangeSchema).readonly()
|
|
30835
|
+
ranges: array(RecordingRangeSchema).readonly(),
|
|
30836
|
+
/** Same field, same meaning, as the singular answer (D433). A row that
|
|
30837
|
+
* dropped it would tell a grid caller the archive holds one profile.
|
|
30838
|
+
* Empty on an `'unreadable'` row: nobody looked. */
|
|
30839
|
+
profilesWithFootage: array(string()).readonly()
|
|
30702
30840
|
});
|
|
30703
30841
|
/**
|
|
30704
30842
|
* One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
|
|
@@ -30728,13 +30866,31 @@ var RecordingManifestSchema = object({
|
|
|
30728
30866
|
*/
|
|
30729
30867
|
playbackEndpoints: array(string())
|
|
30730
30868
|
});
|
|
30731
|
-
/**
|
|
30732
|
-
*
|
|
30869
|
+
/**
|
|
30870
|
+
* Recording storage usage for one camera — what the ARCHIVE holds for it,
|
|
30871
|
+
* across every profile and every resolvable location on this node.
|
|
30872
|
+
*
|
|
30873
|
+
* ## Archive vs residency, which is the whole point of this shape (D418)
|
|
30874
|
+
*
|
|
30875
|
+
* `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
|
|
30876
|
+
* the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
|
|
30877
|
+
* this camera writes to, so the two can be added up and compared.
|
|
30878
|
+
*
|
|
30879
|
+
* They were not always. Until D418 this row came from the recorder's in-RAM
|
|
30880
|
+
* `RecordingIndex`, which since D287 holds only the live tail plus the hours
|
|
30881
|
+
* somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
|
|
30882
|
+
* 60.5 GB and "oldest: three hours ago" on the same page as the volume row
|
|
30883
|
+
* that said otherwise, and two people read it as retention eating recent
|
|
30884
|
+
* footage. Residency is still reported, under `residentBytes` /
|
|
30885
|
+
* `residentOldestMs`, which answer a different question and say so.
|
|
30886
|
+
*/
|
|
30733
30887
|
var RecordingDeviceUsageSchema = object({
|
|
30734
30888
|
deviceId: number(),
|
|
30889
|
+
/** Bytes the ARCHIVE holds for this camera on this node's resolvable
|
|
30890
|
+
* recordings locations. */
|
|
30735
30891
|
usedBytes: number(),
|
|
30736
30892
|
/**
|
|
30737
|
-
* Start of this camera's OLDEST
|
|
30893
|
+
* Start of this camera's OLDEST ARCHIVED segment, across every profile and
|
|
30738
30894
|
* location — the "Oldest footage" column in Recordings → Storage, and the
|
|
30739
30895
|
* only honest answer to "is retention actually holding?" per camera.
|
|
30740
30896
|
*
|
|
@@ -30744,7 +30900,24 @@ var RecordingDeviceUsageSchema = object({
|
|
|
30744
30900
|
* (types) and the addon ship on different trains, and the addon is usually
|
|
30745
30901
|
* the later of the two.
|
|
30746
30902
|
*/
|
|
30747
|
-
oldestMs: number().nullable().optional()
|
|
30903
|
+
oldestMs: number().nullable().optional(),
|
|
30904
|
+
/** Segments the archive holds for this camera — the "M" beside `usedBytes`.
|
|
30905
|
+
* OPTIONAL for the same train-skew reason as `oldestMs`. */
|
|
30906
|
+
segments: number().optional(),
|
|
30907
|
+
/**
|
|
30908
|
+
* RESIDENCY, not the archive: bytes the recorder process currently holds in
|
|
30909
|
+
* its RAM index — the live tail plus the hours a reader hydrated.
|
|
30910
|
+
*
|
|
30911
|
+
* It answers "what can be served without touching the disk", never "how much
|
|
30912
|
+
* footage this camera has". A UI that renders it must label it as such, and
|
|
30913
|
+
* must never total it as storage. OPTIONAL: a recorder predating D418 omits
|
|
30914
|
+
* it, and so does a node whose ledger could not answer.
|
|
30915
|
+
*/
|
|
30916
|
+
residentBytes: number().optional(),
|
|
30917
|
+
/** The residency counterpart of `oldestMs` — the oldest segment currently in
|
|
30918
|
+
* RAM, which on a healthy recorder is minutes ago and means nothing about
|
|
30919
|
+
* retention. `null` = nothing resident. */
|
|
30920
|
+
residentOldestMs: number().nullable().optional()
|
|
30748
30921
|
});
|
|
30749
30922
|
/** Recording storage usage + capacity for one storage location. */
|
|
30750
30923
|
var RecordingLocationUsageSchema = object({
|
|
@@ -30782,6 +30955,17 @@ var RecordingStorageUsageSchema = object({
|
|
|
30782
30955
|
totalUsedBytes: number(),
|
|
30783
30956
|
devices: array(RecordingDeviceUsageSchema),
|
|
30784
30957
|
/**
|
|
30958
|
+
* WHERE `devices[]` came from, so an empty table is never mistaken for empty
|
|
30959
|
+
* disks (D418).
|
|
30960
|
+
*
|
|
30961
|
+
* `archive` = the durable hour ledger answered. `unavailable` = this node
|
|
30962
|
+
* declared no ledger and the recorder REFUSED rather than answering the
|
|
30963
|
+
* question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
|
|
30964
|
+
* zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
|
|
30965
|
+
* and its rows are residency.
|
|
30966
|
+
*/
|
|
30967
|
+
devicesRead: _enum(["archive", "unavailable"]).optional(),
|
|
30968
|
+
/**
|
|
30785
30969
|
* Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
|
|
30786
30970
|
* of the payload without it: the hub serves this method through a BAKED
|
|
30787
30971
|
* router, so a hub whose framework train predates a change to this array
|
|
@@ -30942,7 +31126,14 @@ var ReadWindowBytesResultSchema = discriminatedUnion("kind", [object({
|
|
|
30942
31126
|
method(object({
|
|
30943
31127
|
deviceId: number(),
|
|
30944
31128
|
fromMs: number(),
|
|
30945
|
-
toMs: number()
|
|
31129
|
+
toMs: number(),
|
|
31130
|
+
/**
|
|
31131
|
+
* Answer for THIS profile instead of the preferred one (D433). Absent
|
|
31132
|
+
* keeps the timeline's behaviour — one bar, one profile, one set of
|
|
31133
|
+
* reads. `profilesWithFootage` on the answer says what may be asked
|
|
31134
|
+
* for.
|
|
31135
|
+
*/
|
|
31136
|
+
profile: string().optional()
|
|
30946
31137
|
}), RecordingAvailabilitySchema, {
|
|
30947
31138
|
kind: "query",
|
|
30948
31139
|
auth: "protected"
|
|
@@ -34874,7 +35065,7 @@ function toDeviceSummary(device, addonId) {
|
|
|
34874
35065
|
};
|
|
34875
35066
|
}
|
|
34876
35067
|
/**
|
|
34877
|
-
* Base class for device-provider addons (rtsp, onvif
|
|
35068
|
+
* Base class for device-provider addons (rtsp, onvif).
|
|
34878
35069
|
*
|
|
34879
35070
|
* Provides default implementations for the common device-provider cap
|
|
34880
35071
|
* methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
|
|
@@ -39693,6 +39884,24 @@ Object.freeze({
|
|
|
39693
39884
|
addonId: null,
|
|
39694
39885
|
access: "view"
|
|
39695
39886
|
},
|
|
39887
|
+
"pipelineRunner.getParkedTrackFrame": {
|
|
39888
|
+
capName: "pipeline-runner",
|
|
39889
|
+
capScope: "system",
|
|
39890
|
+
addonId: null,
|
|
39891
|
+
access: "view"
|
|
39892
|
+
},
|
|
39893
|
+
"pipelineRunner.parkTrackFrame": {
|
|
39894
|
+
capName: "pipeline-runner",
|
|
39895
|
+
capScope: "system",
|
|
39896
|
+
addonId: null,
|
|
39897
|
+
access: "create"
|
|
39898
|
+
},
|
|
39899
|
+
"pipelineRunner.releaseParkedTrackFrames": {
|
|
39900
|
+
capName: "pipeline-runner",
|
|
39901
|
+
capScope: "system",
|
|
39902
|
+
addonId: null,
|
|
39903
|
+
access: "create"
|
|
39904
|
+
},
|
|
39696
39905
|
"pipelineRunner.reportMotion": {
|
|
39697
39906
|
capName: "pipeline-runner",
|
|
39698
39907
|
capScope: "system",
|
|
@@ -42970,6 +43179,21 @@ Object.freeze({
|
|
|
42970
43179
|
form: "single",
|
|
42971
43180
|
optional: false
|
|
42972
43181
|
}],
|
|
43182
|
+
"pipelineRunner.getParkedTrackFrame": [{
|
|
43183
|
+
name: "deviceId",
|
|
43184
|
+
form: "single",
|
|
43185
|
+
optional: false
|
|
43186
|
+
}],
|
|
43187
|
+
"pipelineRunner.parkTrackFrame": [{
|
|
43188
|
+
name: "deviceId",
|
|
43189
|
+
form: "single",
|
|
43190
|
+
optional: false
|
|
43191
|
+
}],
|
|
43192
|
+
"pipelineRunner.releaseParkedTrackFrames": [{
|
|
43193
|
+
name: "deviceId",
|
|
43194
|
+
form: "single",
|
|
43195
|
+
optional: false
|
|
43196
|
+
}],
|
|
42973
43197
|
"pipelineRunner.reportMotion": [{
|
|
42974
43198
|
name: "deviceId",
|
|
42975
43199
|
form: "single",
|
|
@@ -43661,7 +43885,7 @@ var PreviewTextField = string().max(200);
|
|
|
43661
43885
|
* Whether the notification's preview is a STILL or a short animation.
|
|
43662
43886
|
*
|
|
43663
43887
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
43664
|
-
* rule)"* —
|
|
43888
|
+
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
43665
43889
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
43666
43890
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
43667
43891
|
* simply applies it to a dozen frames sampled across the render and assembles
|
|
@@ -145531,12 +145755,10 @@ function mapNetworkReadout(readout, now) {
|
|
|
145531
145755
|
//#region src/error-classifier.ts
|
|
145532
145756
|
/**
|
|
145533
145757
|
* Recognise transient Baichuan/socket failures that are expected to
|
|
145534
|
-
* recover on the next reconnect cycle
|
|
145535
|
-
*
|
|
145536
|
-
* keeping parity so the same wire-level conditions are treated the
|
|
145537
|
-
* same way across plugins.
|
|
145758
|
+
* recover on the next reconnect cycle — the same wire-level conditions
|
|
145759
|
+
* are always treated the same way.
|
|
145538
145760
|
*
|
|
145539
|
-
*
|
|
145761
|
+
* Categories:
|
|
145540
145762
|
* - Baichuan-specific transport closes (`Baichuan socket closed`,
|
|
145541
145763
|
* `Baichuan UDP stream closed`, `Baichuan TCP socket is not
|
|
145542
145764
|
* connected`)
|
|
@@ -145606,9 +145828,7 @@ var resolveZoomStep = (travel, zoom) => {
|
|
|
145606
145828
|
/**
|
|
145607
145829
|
* IMA ADPCM (DVI4) encoder — Reolink Baichuan talk-back wire format.
|
|
145608
145830
|
*
|
|
145609
|
-
*
|
|
145610
|
-
* rest of the cross-cam Scrypted infra). Reolink cameras expect ADPCM
|
|
145611
|
-
* blocks of (4 + N) bytes:
|
|
145831
|
+
* Reolink cameras expect ADPCM blocks of (4 + N) bytes:
|
|
145612
145832
|
* - 2 bytes: little-endian Int16 predictor (first PCM sample of the
|
|
145613
145833
|
* block, used to seed the decoder state on the camera side)
|
|
145614
145834
|
* - 1 byte: index into the IMA step table (always 0 — we re-seed
|
|
@@ -145992,14 +146212,12 @@ var ReolinkIntercomSession = class {
|
|
|
145992
146212
|
}
|
|
145993
146213
|
}
|
|
145994
146214
|
};
|
|
145995
|
-
/** Clamp `blocksPerPayload` into the lib's accepted range.
|
|
145996
|
-
* scrypted-reolink-native's `intercom-mixin.ts:96-101` clamp. */
|
|
146215
|
+
/** Clamp `blocksPerPayload` into the lib's accepted range. */
|
|
145997
146216
|
function clampBlocks(value) {
|
|
145998
146217
|
if (value === void 0 || !Number.isFinite(value)) return DEFAULT_BLOCKS_PER_PAYLOAD;
|
|
145999
146218
|
return Math.max(1, Math.min(8, Math.floor(value)));
|
|
146000
146219
|
}
|
|
146001
|
-
/** Clamp `outputGain` into the operator-safe
|
|
146002
|
-
* band as Scrypted (`intercom-mixin.ts:104-107`). */
|
|
146220
|
+
/** Clamp `outputGain` into the operator-safe `[0.1, 10]` band. */
|
|
146003
146221
|
function clampGain(value) {
|
|
146004
146222
|
if (value === void 0 || !Number.isFinite(value)) return DEFAULT_GAIN;
|
|
146005
146223
|
return Math.max(MIN_GAIN, Math.min(MAX_GAIN, value));
|
|
@@ -146598,9 +146816,8 @@ var ReolinkUdpDiscoveryMethodSchema = _enum([
|
|
|
146598
146816
|
"map"
|
|
146599
146817
|
]);
|
|
146600
146818
|
/**
|
|
146601
|
-
* Lib-side socket debug categories
|
|
146602
|
-
*
|
|
146603
|
-
* users coming from Scrypted recognize them. Each flag is forwarded
|
|
146819
|
+
* Lib-side socket debug categories — the names and semantics the lib
|
|
146820
|
+
* itself uses, so they are recognizable. Each flag is forwarded
|
|
146604
146821
|
* verbatim into the `DebugOptions` blob `ReolinkBaichuanApi` accepts.
|
|
146605
146822
|
*/
|
|
146606
146823
|
var ReolinkSocketDebugFlagSchema = _enum([
|
|
@@ -147002,14 +147219,12 @@ var reolinkCameraSchema = object({
|
|
|
147002
147219
|
}).loose().optional(),
|
|
147003
147220
|
/**
|
|
147004
147221
|
* Generic Baichuan debug logs. Forwarded as `DebugOptions.general`
|
|
147005
|
-
* on the lib's `ReolinkBaichuanApi` constructor.
|
|
147006
|
-
* `debugLogs` boolean.
|
|
147222
|
+
* on the lib's `ReolinkBaichuanApi` constructor.
|
|
147007
147223
|
*/
|
|
147008
147224
|
debugGeneral: boolean().default(false),
|
|
147009
147225
|
/**
|
|
147010
147226
|
* Lib-side socket trace categories. Each flag flips the matching
|
|
147011
|
-
* `DebugOptions.<flag>` on the api.
|
|
147012
|
-
* `socketApiDebugLogs` multi-select.
|
|
147227
|
+
* `DebugOptions.<flag>` on the api.
|
|
147013
147228
|
*/
|
|
147014
147229
|
debugSocketLogs: array(ReolinkSocketDebugFlagSchema).default([]),
|
|
147015
147230
|
/**
|
|
@@ -147264,21 +147479,20 @@ var reolinkCameraSchema = object({
|
|
|
147264
147479
|
/**
|
|
147265
147480
|
* Intercom (browser→cam talk channel) tuning. Only consumed
|
|
147266
147481
|
* when the camera advertises two-way audio (`hasIntercom` in the
|
|
147267
|
-
* feature-probe slice).
|
|
147268
|
-
*
|
|
147269
|
-
* same defaults so the user-facing latency matches Scrypted's.
|
|
147482
|
+
* feature-probe slice). The names, ranges and defaults are the ones
|
|
147483
|
+
* the lib itself documents, so the user-facing latency is predictable.
|
|
147270
147484
|
*
|
|
147271
147485
|
* `intercomBlocksPerPayload` — number of IMA-ADPCM blocks bundled
|
|
147272
147486
|
* into each `sendAudio` call against the lib's dedicated talk
|
|
147273
147487
|
* session. Lower = smaller chunks, more sends/sec, lower latency.
|
|
147274
147488
|
* Higher = fewer sends, less per-call socket overhead. Default 1
|
|
147275
|
-
* = lowest latency
|
|
147489
|
+
* = lowest latency.
|
|
147276
147490
|
*/
|
|
147277
147491
|
intercomBlocksPerPayload: number().int().min(1).max(8).optional(),
|
|
147278
147492
|
/**
|
|
147279
147493
|
* `intercomMaxBacklogMs` — bound on the PCM backlog before the
|
|
147280
|
-
* pump drops oldest samples to cap latency. Default 120ms
|
|
147281
|
-
*
|
|
147494
|
+
* pump drops oldest samples to cap latency. Default 120ms; raise
|
|
147495
|
+
* via the Settings UI on systems where the cross-
|
|
147282
147496
|
* process Opus→PCM path is bursty enough to trigger frequent
|
|
147283
147497
|
* `intercom backlog clamped` warnings.
|
|
147284
147498
|
*/
|
|
@@ -147298,8 +147512,7 @@ var reolinkCameraSchema = object({
|
|
|
147298
147512
|
* instances; this schema only carries connection + debug + the cached
|
|
147299
147513
|
* channels summary so we can re-render the Discovery panel offline.
|
|
147300
147514
|
*
|
|
147301
|
-
*
|
|
147302
|
-
* `storageSettings` (`nvr.ts:49-178`): same scope, same fields, just
|
|
147515
|
+
* The NVR device's own settings scope and fields, just
|
|
147303
147516
|
* adapted to the Zod conventions used elsewhere in this package.
|
|
147304
147517
|
*/
|
|
147305
147518
|
var reolinkHubSchema = object({
|
|
@@ -148080,8 +148293,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
148080
148293
|
objectDetectionsSubscribed = false;
|
|
148081
148294
|
/**
|
|
148082
148295
|
* Plugin-level event-health interval — fallback layer over the
|
|
148083
|
-
* lib's internal 5-minute watchdog.
|
|
148084
|
-
* `startEventCheck` (`baichuan-base.ts:719-783`): every 60 s,
|
|
148296
|
+
* lib's internal 5-minute watchdog. The rule: every 60 s,
|
|
148085
148297
|
* if `eventSubscriptionActive` is false on a live socket OR no
|
|
148086
148298
|
* event has arrived in 10 min, force a full unsub/resub cycle.
|
|
148087
148299
|
*/
|
|
@@ -148196,9 +148408,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
148196
148408
|
/** Aux accessory references registered by spawned children
|
|
148197
148409
|
* (siren / floodlight / pir). The parent's centralised align
|
|
148198
148410
|
* method iterates these to refresh their slices on a single
|
|
148199
|
-
* cadence — replaces the old per-accessory setInterval.
|
|
148200
|
-
* scrypted-reolink-native's `motionSiren` / `floodlight` / `pir`
|
|
148201
|
-
* field refs + their `alignAuxDevicesState` method. */
|
|
148411
|
+
* cadence — replaces the old per-accessory setInterval. */
|
|
148202
148412
|
auxAccessoryRefs = /* @__PURE__ */ new Map();
|
|
148203
148413
|
/**
|
|
148204
148414
|
* Reliability watchdogs (Slice 10). Both timers are armed after a
|
|
@@ -149003,8 +149213,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
149003
149213
|
* Single-flight guard for snapshot fetches (Slice 10). When two
|
|
149004
149214
|
* consumers hit `getSnapshot` concurrently we issue ONE Baichuan
|
|
149005
149215
|
* request and let both await its result — saves a doubled wake on
|
|
149006
|
-
* battery cams and halves load for regular ones.
|
|
149007
|
-
* `takePictureInFlight` in scrypted-reolink-native.
|
|
149216
|
+
* battery cams and halves load for regular ones.
|
|
149008
149217
|
*/
|
|
149009
149218
|
snapshotInFlight = null;
|
|
149010
149219
|
/**
|
|
@@ -151337,9 +151546,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
151337
151546
|
};
|
|
151338
151547
|
}
|
|
151339
151548
|
/**
|
|
151340
|
-
* Battery-cam pre-wake hook for the intercom orchestrator
|
|
151341
|
-
*
|
|
151342
|
-
* the current sleep status (passive — no traffic), and if the cam
|
|
151549
|
+
* Battery-cam pre-wake hook for the intercom orchestrator: ask the
|
|
151550
|
+
* lib for the current sleep status (passive — no traffic), and if the cam
|
|
151343
151551
|
* is asleep issue an explicit `wakeUp(channel, {waitAfterWakeMs:2000})`
|
|
151344
151552
|
* + a 1s settle delay before letting the talk-session handshake
|
|
151345
151553
|
* fire. Without this, the handshake against a sleeping UDP/battery
|
|
@@ -151879,7 +152087,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
151879
152087
|
/**
|
|
151880
152088
|
* Synthesize the HTTP-FLV pull URL for a (channel, profile) pair. FLV is
|
|
151881
152089
|
* served off the Reolink Baichuan media port (default 1935, app `bcs`) as
|
|
151882
|
-
* `channel<channel>_<profile>.bcs` — the same shape
|
|
152090
|
+
* `channel<channel>_<profile>.bcs` — the same shape go2rtc uses. The
|
|
151883
152091
|
* lib does NOT surface this URL, so we build it from the SAME connection
|
|
151884
152092
|
* creds the RTSP/native paths use (`host`/`username`/`password` on the
|
|
151885
152093
|
* device config), URL-encoding the credentials.
|
|
@@ -152730,9 +152938,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
152730
152938
|
/**
|
|
152731
152939
|
* Shared wake-transition handler invoked by both the simpleEvent
|
|
152732
152940
|
* `awake` push (canonical fast path) and the sleep poll's
|
|
152733
|
-
* `sleeping → awake` flip (backstop).
|
|
152734
|
-
*
|
|
152735
|
-
* out the refreshes that depend on the camera being responsive:
|
|
152941
|
+
* `sleeping → awake` flip (backstop). Fan out the refreshes that
|
|
152942
|
+
* depend on the camera being responsive:
|
|
152736
152943
|
* - aux accessories (siren/floodlight/PIR) re-read their
|
|
152737
152944
|
* firmware state via `alignAuxDevicesState('wake')`
|
|
152738
152945
|
* - parent settings snapshot (image / motion / AI / enc / mask /
|
|
@@ -152881,8 +153088,6 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
152881
153088
|
* 3. Register via `onSimpleEvent(handleSimpleEventBound)`.
|
|
152882
153089
|
* Lib starts/refreshes its own subscribe + 5min watchdog.
|
|
152883
153090
|
*
|
|
152884
|
-
* Mirrors `subscribeToEventsInternal` in Scrypted's
|
|
152885
|
-
* `baichuan-base.ts:837-888` — same pattern, same rationale.
|
|
152886
153091
|
*/
|
|
152887
153092
|
async resubscribeSimpleEvents(api, reason) {
|
|
152888
153093
|
try {
|
|
@@ -153759,7 +153964,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
153759
153964
|
type: "slider",
|
|
153760
153965
|
key: "intercomBlocksPerPayload",
|
|
153761
153966
|
label: "Blocks per payload",
|
|
153762
|
-
description: "Lower = lower latency (more sendAudio calls/sec). Higher = fewer calls, less per-call socket overhead. Range 1..8. Default 1 (
|
|
153967
|
+
description: "Lower = lower latency (more sendAudio calls/sec). Higher = fewer calls, less per-call socket overhead. Range 1..8. Default 1 (lowest latency).",
|
|
153763
153968
|
min: 1,
|
|
153764
153969
|
max: 8,
|
|
153765
153970
|
step: 1,
|
|
@@ -153771,7 +153976,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
153771
153976
|
type: "slider",
|
|
153772
153977
|
key: "intercomMaxBacklogMs",
|
|
153773
153978
|
label: "Max backlog (ms)",
|
|
153774
|
-
description: "Maximum PCM backlog before dropping oldest samples to cap latency. Higher = more stable on slow systems but more latency. Range 20..5000. Default 120
|
|
153979
|
+
description: "Maximum PCM backlog before dropping oldest samples to cap latency. Higher = more stable on slow systems but more latency. Range 20..5000. Default 120.",
|
|
153775
153980
|
min: 20,
|
|
153776
153981
|
max: 5e3,
|
|
153777
153982
|
step: 20,
|
|
@@ -153906,7 +154111,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
153906
154111
|
id: "debug",
|
|
153907
154112
|
tab: "advanced",
|
|
153908
154113
|
title: "Debug",
|
|
153909
|
-
description: "Lib-side Baichuan tracing.
|
|
154114
|
+
description: "Lib-side Baichuan tracing. Changing these resets the control-channel client (active streams keep running) so new debug options take effect on the next dial.",
|
|
153910
154115
|
columns: 1,
|
|
153911
154116
|
fields: [{
|
|
153912
154117
|
type: "boolean",
|
|
@@ -154600,9 +154805,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
154600
154805
|
return this.loginPromise;
|
|
154601
154806
|
}
|
|
154602
154807
|
/**
|
|
154603
|
-
* Bridge Reolink hardware events to the camstack event bus
|
|
154604
|
-
*
|
|
154605
|
-
* (`camera.ts:1979-2033`): online and sleeping are TWO ORTHOGONAL
|
|
154808
|
+
* Bridge Reolink hardware events to the camstack event bus:
|
|
154809
|
+
* online and sleeping are TWO ORTHOGONAL
|
|
154606
154810
|
* axes, each driven exclusively by their own firmware push events.
|
|
154607
154811
|
*
|
|
154608
154812
|
* - 'motion' + AI types (people, vehicle, animal, face, package):
|
|
@@ -154631,8 +154835,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
154631
154835
|
}
|
|
154632
154836
|
/**
|
|
154633
154837
|
* Build the `DebugOptions` blob forwarded to `ReolinkBaichuanApi`'s
|
|
154634
|
-
* constructor.
|
|
154635
|
-
* `camera.ts:1778-1786`. Returns `undefined` when no flags are set
|
|
154838
|
+
* constructor. Returns `undefined` when no flags are set
|
|
154636
154839
|
* so the lib falls back to its own defaults instead of an empty
|
|
154637
154840
|
* object override.
|
|
154638
154841
|
*/
|
|
@@ -154891,8 +155094,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
154891
155094
|
* idle UDP socket on its own, the camera is asleep, and there is
|
|
154892
155095
|
* nothing to reconnect to. Aggressively reconnecting in that state
|
|
154893
155096
|
* is what was waking up the doorbell every ~60 s in production
|
|
154894
|
-
* logs.
|
|
154895
|
-
* reference, but DO NOT schedule a reconnect timer. The next
|
|
155097
|
+
* logs. Drop the api reference, but DO NOT schedule a reconnect timer. The next
|
|
154896
155098
|
* `awake` push (or a snapshot demand from the operator) will
|
|
154897
155099
|
* lazily call `ensureApi()` and re-establish the client.
|
|
154898
155100
|
*/
|
|
@@ -155005,8 +155207,8 @@ function isHubLike(d) {
|
|
|
155005
155207
|
* starts at 60s) OR the subscription is genuinely broken / nothing is
|
|
155006
155208
|
* happening in front of the cam (counter rises → backoff lengthens).
|
|
155007
155209
|
*
|
|
155008
|
-
* Schedule: 60s → 2min → 5min → 15min capped
|
|
155009
|
-
*
|
|
155210
|
+
* Schedule: 60s → 2min → 5min → 15min capped — the long-poll backoff
|
|
155211
|
+
* curve this hardware is known to tolerate.
|
|
155010
155212
|
*/
|
|
155011
155213
|
function computeHealthCheckBackoffMs(consecutive) {
|
|
155012
155214
|
if (consecutive <= 1) return 6e4;
|
|
@@ -155150,7 +155352,7 @@ var HUB_RECONNECT_MAX_MS = 3e4;
|
|
|
155150
155352
|
/**
|
|
155151
155353
|
* Reolink Hub / NVR — single Baichuan socket fronting N channels.
|
|
155152
155354
|
*
|
|
155153
|
-
*
|
|
155355
|
+
* The NVR pattern:
|
|
155154
155356
|
* - One persistent control + event socket on the parent (no
|
|
155155
155357
|
* per-channel login).
|
|
155156
155358
|
* - `device-discovery` cap exposes the channel list with status,
|
|
@@ -155303,8 +155505,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
155303
155505
|
}
|
|
155304
155506
|
}
|
|
155305
155507
|
/**
|
|
155306
|
-
* Hub-specific settings form
|
|
155307
|
-
* `ReolinkNativeNvrDevice.storageSettings` block (`nvr.ts:49-178`):
|
|
155508
|
+
* Hub-specific settings form:
|
|
155308
155509
|
* connection (host / port / credentials) on the General tab,
|
|
155309
155510
|
* Baichuan debug flags on Advanced. Per-channel settings (image,
|
|
155310
155511
|
* motion, AI sensitivity, …) live on the adopted child cameras —
|
|
@@ -155396,7 +155597,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
155396
155597
|
id: "debug",
|
|
155397
155598
|
tab: "advanced",
|
|
155398
155599
|
title: "Debug",
|
|
155399
|
-
description: "Lib-side Baichuan tracing.
|
|
155600
|
+
description: "Lib-side Baichuan tracing. Changing these resets the control-channel client (active streams keep running) so new debug options take effect on the next dial.",
|
|
155400
155601
|
columns: 1,
|
|
155401
155602
|
fields: [{
|
|
155402
155603
|
type: "boolean",
|
|
@@ -155559,8 +155760,8 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
155559
155760
|
}
|
|
155560
155761
|
/**
|
|
155561
155762
|
* Pull the channel list from the Hub via the lib's
|
|
155562
|
-
* `getNvrChannelsSummary({ source: 'cgi' })`. CGI
|
|
155563
|
-
*
|
|
155763
|
+
* `getNvrChannelsSummary({ source: 'cgi' })`. CGI is chosen because
|
|
155764
|
+
* `GetChannelstatus` returns the channel list
|
|
155564
155765
|
* synchronously (no race against the cmd_id 145 push cache that
|
|
155565
155766
|
* can be empty right after login).
|
|
155566
155767
|
*
|
|
@@ -155952,8 +156153,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
|
|
|
155952
156153
|
}
|
|
155953
156154
|
/**
|
|
155954
156155
|
* Dispatches a Hub-received simpleEvent to the matching child's
|
|
155955
|
-
* `handleSimpleEvent`.
|
|
155956
|
-
* `ReolinkNativeNvrDevice.onSimpleEvent` (`nvr.ts:288-319`).
|
|
156156
|
+
* `handleSimpleEvent`.
|
|
155957
156157
|
*/
|
|
155958
156158
|
routeSimpleEvent(ev) {
|
|
155959
156159
|
const channel = ev?.channel;
|
|
@@ -156111,7 +156311,7 @@ function computeChildNativeId(parentStableId, channel, uid) {
|
|
|
156111
156311
|
}
|
|
156112
156312
|
/**
|
|
156113
156313
|
* Map the lib's per-channel summary booleans to our `DiscoveredChildStatus`.
|
|
156114
|
-
* Order of precedence
|
|
156314
|
+
* Order of precedence:
|
|
156115
156315
|
* 1. `online === false` → offline
|
|
156116
156316
|
* 2. `sleeping === true` → sleeping
|
|
156117
156317
|
* 3. anything else with non-empty state → online
|