@camstack/addon-provider-hikvision 1.1.19 → 1.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +296 -230
- package/dist/addon.mjs +296 -230
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -4635,7 +4635,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4635
4635
|
return inst;
|
|
4636
4636
|
}
|
|
4637
4637
|
//#endregion
|
|
4638
|
-
//#region ../types/dist/sleep-
|
|
4638
|
+
//#region ../types/dist/sleep-Cc14_yxc.mjs
|
|
4639
4639
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4640
4640
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4641
4641
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -4821,6 +4821,18 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
4821
4821
|
*/
|
|
4822
4822
|
EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
|
|
4823
4823
|
/**
|
|
4824
|
+
* The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
|
|
4825
|
+
* Emitted by addon-pipeline-orchestrator whenever it (re)derives node
|
|
4826
|
+
* capabilities — at boot, on agent online/offline, and on an ingest-node
|
|
4827
|
+
* flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
|
|
4828
|
+
* keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
|
|
4829
|
+
* cross-process `getIngestOwner` query (push the authority's decision instead
|
|
4830
|
+
* of polling it on the hot path). Idempotent state — re-emitted on every
|
|
4831
|
+
* topology change, so a dropped event self-heals on the next one (plus the
|
|
4832
|
+
* broker's long backstop reconcile query).
|
|
4833
|
+
*/
|
|
4834
|
+
EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
|
|
4835
|
+
/**
|
|
4824
4836
|
* Periodic snapshot of per-node pipeline-runner load
|
|
4825
4837
|
* (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
|
|
4826
4838
|
* subscribe instead of polling `pipelineRunner.getLocalLoad`.
|
|
@@ -6904,6 +6916,36 @@ var ModelFormatsSchema = object({
|
|
|
6904
6916
|
tflite: ModelFormatEntrySchema.optional(),
|
|
6905
6917
|
pt: ModelFormatEntrySchema.optional()
|
|
6906
6918
|
});
|
|
6919
|
+
/**
|
|
6920
|
+
* Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
|
|
6921
|
+
* the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
|
|
6922
|
+
* grouped Family→Tier→Variant picker renders identically in the config UI and
|
|
6923
|
+
* in the pipeline/device steppers. The flat `id` stays the source of truth for
|
|
6924
|
+
* resolution/download/persistence; this is a presentation overlay resolved back
|
|
6925
|
+
* to an `id`.
|
|
6926
|
+
*/
|
|
6927
|
+
var ModelVariantGroupSchema = object({
|
|
6928
|
+
/** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
|
|
6929
|
+
family: string(),
|
|
6930
|
+
/** Size within the family, e.g. `n` | `s` | `m` | `l`. */
|
|
6931
|
+
tier: string(),
|
|
6932
|
+
/** Quantization axis. Omit ⇒ the fp32 base build. */
|
|
6933
|
+
precision: _enum(["fp32", "int8"]).optional(),
|
|
6934
|
+
/**
|
|
6935
|
+
* Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
|
|
6936
|
+
* latency-optimized export (e.g. ReLU-activation variant) — the slot the
|
|
6937
|
+
* future performance variants plug into.
|
|
6938
|
+
*/
|
|
6939
|
+
optimization: _enum(["standard", "fast"]).optional(),
|
|
6940
|
+
/**
|
|
6941
|
+
* Input-resolution axis (square input side, px). Omit ⇒ the family's native
|
|
6942
|
+
* resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
|
|
6943
|
+
* cheap latency lever — especially on Apple ANE and the Intel N100 — at a
|
|
6944
|
+
* small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
|
|
6945
|
+
* the group so the selector can offer it as a variant axis.
|
|
6946
|
+
*/
|
|
6947
|
+
resolution: number().int().positive().optional()
|
|
6948
|
+
});
|
|
6907
6949
|
var ModelCatalogEntrySchema = object({
|
|
6908
6950
|
id: string(),
|
|
6909
6951
|
name: string(),
|
|
@@ -6933,7 +6975,43 @@ var ModelCatalogEntrySchema = object({
|
|
|
6933
6975
|
* Auxiliary files required at runtime (labels JSON, charset dict, etc.).
|
|
6934
6976
|
* Downloaded into the same modelsDir alongside the model file.
|
|
6935
6977
|
*/
|
|
6936
|
-
extraFiles: array(ModelExtraFileSchema).readonly().optional()
|
|
6978
|
+
extraFiles: array(ModelExtraFileSchema).readonly().optional(),
|
|
6979
|
+
/**
|
|
6980
|
+
* LEGACY entry — retained in the catalog so a persisted operator selection
|
|
6981
|
+
* still RESOLVES (and can be re-activated), but hidden from the selectable
|
|
6982
|
+
* model list and excluded from the auto format-default pick. Set on the
|
|
6983
|
+
* superseded / consolidated models (older lineages, redundant fp16 IRs) so
|
|
6984
|
+
* the active lineup stays the coherent curated ladder without deleting a
|
|
6985
|
+
* model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
|
|
6986
|
+
* an explicit legacy id that has a build for the node's format.
|
|
6987
|
+
*/
|
|
6988
|
+
legacy: boolean().optional(),
|
|
6989
|
+
/**
|
|
6990
|
+
* Measured quality/latency metadata — populated from the benchmark addon on
|
|
6991
|
+
* the real node classes. Absent = not yet measured (most entries today; the
|
|
6992
|
+
* catalog historically carried only `sizeMB`, a poor cross-architecture
|
|
6993
|
+
* speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
|
|
6994
|
+
*/
|
|
6995
|
+
metrics: object({
|
|
6996
|
+
map50: number().optional(),
|
|
6997
|
+
p95LatencyMs: record(string(), number()).optional()
|
|
6998
|
+
}).optional(),
|
|
6999
|
+
/**
|
|
7000
|
+
* SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
|
|
7001
|
+
* YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
|
|
7002
|
+
* the retraining addon and any future commercial distribution.
|
|
7003
|
+
*/
|
|
7004
|
+
license: string().optional(),
|
|
7005
|
+
/**
|
|
7006
|
+
* Variant-selector grouping. The UI groups models by `family` + `tier` and
|
|
7007
|
+
* offers `precision` / `optimization` as variant axes WITHIN a tier — so all
|
|
7008
|
+
* of a family's sizes and quantizations collapse into one grouped picker
|
|
7009
|
+
* instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
|
|
7010
|
+
* (legacy / custom models) — never shown in the grouped selector. The flat
|
|
7011
|
+
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
7012
|
+
* is a presentation overlay resolved back to an `id`.
|
|
7013
|
+
*/
|
|
7014
|
+
group: ModelVariantGroupSchema.optional()
|
|
6937
7015
|
});
|
|
6938
7016
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
6939
7017
|
format: literal("openvino"),
|
|
@@ -7169,8 +7247,8 @@ var RecordingModeSchema = _enum([
|
|
|
7169
7247
|
"onAudioThreshold"
|
|
7170
7248
|
]);
|
|
7171
7249
|
/**
|
|
7172
|
-
* First-class, authoritative per-camera storage mode — the
|
|
7173
|
-
* reads directly (never inferred from `rules`):
|
|
7250
|
+
* First-class, authoritative per-camera storage mode — the explicit choice the
|
|
7251
|
+
* UI reads directly (never inferred from `rules`):
|
|
7174
7252
|
* - `off` — not recording.
|
|
7175
7253
|
* - `events` — record only around triggers (motion / audio threshold),
|
|
7176
7254
|
* with pre/post-buffer.
|
|
@@ -8709,6 +8787,72 @@ function createRuntimeStateBridge(params) {
|
|
|
8709
8787
|
getStatus
|
|
8710
8788
|
};
|
|
8711
8789
|
}
|
|
8790
|
+
/** Reject after `ms`; always clears its own timer. */
|
|
8791
|
+
async function withTimeout$1(promise, ms, label) {
|
|
8792
|
+
let timer;
|
|
8793
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
8794
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`${label} timed out after ${String(ms)}ms`)), ms);
|
|
8795
|
+
});
|
|
8796
|
+
try {
|
|
8797
|
+
return await Promise.race([promise, timeout]);
|
|
8798
|
+
} finally {
|
|
8799
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
8800
|
+
}
|
|
8801
|
+
}
|
|
8802
|
+
/**
|
|
8803
|
+
* Start the reachability poll loop. Returns a handle whose `stop()` clears the
|
|
8804
|
+
* timer and prevents any further ticks. Start on device activation, stop on
|
|
8805
|
+
* device teardown (`removeDevice`) so no timer leaks.
|
|
8806
|
+
*/
|
|
8807
|
+
function startReachabilityPoll(options) {
|
|
8808
|
+
const intervalMs = options.intervalMs ?? 3e4;
|
|
8809
|
+
const failuresToOffline = options.failuresToOffline ?? 3;
|
|
8810
|
+
const probeTimeoutMs = options.probeTimeoutMs ?? 1e4;
|
|
8811
|
+
const runImmediately = options.runImmediately ?? true;
|
|
8812
|
+
let stopped = false;
|
|
8813
|
+
let running = false;
|
|
8814
|
+
let consecutiveFailures = 0;
|
|
8815
|
+
let timer;
|
|
8816
|
+
const tick = async () => {
|
|
8817
|
+
if (stopped) return;
|
|
8818
|
+
if (running) return;
|
|
8819
|
+
if (options.isEnabled && !options.isEnabled()) return;
|
|
8820
|
+
running = true;
|
|
8821
|
+
try {
|
|
8822
|
+
const reachable = await withTimeout$1(Promise.resolve().then(options.probe), probeTimeoutMs, "reachability probe");
|
|
8823
|
+
if (stopped) return;
|
|
8824
|
+
if (reachable) {
|
|
8825
|
+
consecutiveFailures = 0;
|
|
8826
|
+
options.setOnline(true);
|
|
8827
|
+
} else registerFailure("probe resolved unreachable");
|
|
8828
|
+
} catch (error) {
|
|
8829
|
+
if (stopped) return;
|
|
8830
|
+
registerFailure(error instanceof Error ? error.message : "probe threw");
|
|
8831
|
+
} finally {
|
|
8832
|
+
running = false;
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
const registerFailure = (reason) => {
|
|
8836
|
+
consecutiveFailures += 1;
|
|
8837
|
+
options.logger?.debug("reachability probe failed", {
|
|
8838
|
+
reason,
|
|
8839
|
+
consecutiveFailures,
|
|
8840
|
+
failuresToOffline
|
|
8841
|
+
});
|
|
8842
|
+
if (consecutiveFailures >= failuresToOffline) options.setOnline(false);
|
|
8843
|
+
};
|
|
8844
|
+
timer = setInterval(() => {
|
|
8845
|
+
tick();
|
|
8846
|
+
}, intervalMs);
|
|
8847
|
+
if (typeof timer === "object" && timer !== null && "unref" in timer) timer.unref();
|
|
8848
|
+
if (runImmediately) tick();
|
|
8849
|
+
return { stop: () => {
|
|
8850
|
+
if (stopped) return;
|
|
8851
|
+
stopped = true;
|
|
8852
|
+
if (timer !== void 0) clearInterval(timer);
|
|
8853
|
+
timer = void 0;
|
|
8854
|
+
} };
|
|
8855
|
+
}
|
|
8712
8856
|
/**
|
|
8713
8857
|
* Generic device-level status snapshot. Auto-registered by `BaseDevice`
|
|
8714
8858
|
* for every device, regardless of provider — the kernel needs a uniform
|
|
@@ -9372,26 +9516,13 @@ onBrightnessChanged: { data: object({
|
|
|
9372
9516
|
*/
|
|
9373
9517
|
runtimeState: BrightnessStatusSchema
|
|
9374
9518
|
};
|
|
9519
|
+
/** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
|
|
9375
9520
|
var StreamFormatSchema = _enum([
|
|
9376
9521
|
"webrtc",
|
|
9377
9522
|
"hls",
|
|
9378
9523
|
"mjpeg",
|
|
9379
9524
|
"rtsp"
|
|
9380
9525
|
]);
|
|
9381
|
-
var StreamInfoSchema = object({
|
|
9382
|
-
streamId: string(),
|
|
9383
|
-
format: StreamFormatSchema,
|
|
9384
|
-
url: string().nullable(),
|
|
9385
|
-
active: boolean()
|
|
9386
|
-
});
|
|
9387
|
-
method(object({
|
|
9388
|
-
streamId: string(),
|
|
9389
|
-
sourceUrl: string(),
|
|
9390
|
-
codec: string().optional()
|
|
9391
|
-
}), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
9392
|
-
streamId: string(),
|
|
9393
|
-
format: StreamFormatSchema
|
|
9394
|
-
}), string().nullable()), method(_void(), array(StreamInfoSchema));
|
|
9395
9526
|
var RtspRestreamEntrySchema = object({
|
|
9396
9527
|
brokerId: string(),
|
|
9397
9528
|
url: string(),
|
|
@@ -10259,37 +10390,7 @@ var consumablesCapability = {
|
|
|
10259
10390
|
scope: "device",
|
|
10260
10391
|
deviceNative: true,
|
|
10261
10392
|
mode: "singleton",
|
|
10262
|
-
deviceTypes:
|
|
10263
|
-
DeviceType.Camera,
|
|
10264
|
-
DeviceType.Hub,
|
|
10265
|
-
DeviceType.Light,
|
|
10266
|
-
DeviceType.Siren,
|
|
10267
|
-
DeviceType.Switch,
|
|
10268
|
-
DeviceType.Sensor,
|
|
10269
|
-
DeviceType.Thermostat,
|
|
10270
|
-
DeviceType.Button,
|
|
10271
|
-
DeviceType.EventEmitter,
|
|
10272
|
-
DeviceType.Update,
|
|
10273
|
-
DeviceType.Generic,
|
|
10274
|
-
DeviceType.Notifier,
|
|
10275
|
-
DeviceType.Script,
|
|
10276
|
-
DeviceType.Automation,
|
|
10277
|
-
DeviceType.Lock,
|
|
10278
|
-
DeviceType.Cover,
|
|
10279
|
-
DeviceType.Valve,
|
|
10280
|
-
DeviceType.Humidifier,
|
|
10281
|
-
DeviceType.WaterHeater,
|
|
10282
|
-
DeviceType.Fan,
|
|
10283
|
-
DeviceType.MediaPlayer,
|
|
10284
|
-
DeviceType.AlarmPanel,
|
|
10285
|
-
DeviceType.Control,
|
|
10286
|
-
DeviceType.Presence,
|
|
10287
|
-
DeviceType.Weather,
|
|
10288
|
-
DeviceType.Vacuum,
|
|
10289
|
-
DeviceType.LawnMower,
|
|
10290
|
-
DeviceType.Container,
|
|
10291
|
-
DeviceType.Image
|
|
10292
|
-
],
|
|
10393
|
+
deviceTypes: Object.values(DeviceType),
|
|
10293
10394
|
deviceConfig: { ui: {
|
|
10294
10395
|
kind: "widget",
|
|
10295
10396
|
widgetId: "host/consumables-panel",
|
|
@@ -11882,7 +11983,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
|
|
|
11882
11983
|
enabled: boolean(),
|
|
11883
11984
|
modelId: string(),
|
|
11884
11985
|
children: array(PipelineDefaultStepSchema).readonly(),
|
|
11885
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
11886
11986
|
group: string().optional(),
|
|
11887
11987
|
settings: record(string(), unknown()).optional()
|
|
11888
11988
|
}));
|
|
@@ -11907,7 +12007,9 @@ var PipelineModelOptionSchema = object({
|
|
|
11907
12007
|
formats: record(string(), object({
|
|
11908
12008
|
downloaded: boolean(),
|
|
11909
12009
|
sizeMB: number()
|
|
11910
|
-
}))
|
|
12010
|
+
})),
|
|
12011
|
+
group: ModelVariantGroupSchema.optional(),
|
|
12012
|
+
legacy: boolean().optional()
|
|
11911
12013
|
});
|
|
11912
12014
|
var ConfigFieldBridge = custom();
|
|
11913
12015
|
var PipelineAddonSchemaSchema = object({
|
|
@@ -11958,15 +12060,42 @@ var EngineProvisioningSchema = object({
|
|
|
11958
12060
|
]),
|
|
11959
12061
|
progress: number().optional(),
|
|
11960
12062
|
error: string().optional(),
|
|
11961
|
-
nextRetryAt: number().optional()
|
|
12063
|
+
nextRetryAt: number().optional(),
|
|
12064
|
+
/**
|
|
12065
|
+
* Gate A (config-correctness gate at engine change): human-readable
|
|
12066
|
+
* config issues surfaced EAGERLY when the node's engine changes — model
|
|
12067
|
+
* substitutions ("chose X, running Y") and zero-build steps ("no model
|
|
12068
|
+
* has a <format> build"). Additive/optional: informational only, never
|
|
12069
|
+
* enforced here — `assertEngineReady` (readiness) still gates inference.
|
|
12070
|
+
* Absent/empty when the node-default tree resolves cleanly.
|
|
12071
|
+
*/
|
|
12072
|
+
configIssues: array(string()).optional()
|
|
11962
12073
|
});
|
|
11963
12074
|
var PipelineStepInputSchema = lazy(() => object({
|
|
11964
12075
|
addonId: string(),
|
|
11965
|
-
modelId: string(),
|
|
12076
|
+
modelId: string().optional(),
|
|
11966
12077
|
enabled: boolean().default(true),
|
|
11967
12078
|
children: array(PipelineStepInputSchema).optional(),
|
|
11968
12079
|
settings: record(string(), unknown()).optional()
|
|
11969
12080
|
}));
|
|
12081
|
+
var ModelSubstitutionSchema = object({
|
|
12082
|
+
addonId: string(),
|
|
12083
|
+
chosen: string(),
|
|
12084
|
+
running: string(),
|
|
12085
|
+
format: string()
|
|
12086
|
+
});
|
|
12087
|
+
var PipelineValidationIssueSchema = object({
|
|
12088
|
+
addonId: string(),
|
|
12089
|
+
kind: _enum(["unknown-addon", "no-format-build"]),
|
|
12090
|
+
detail: string()
|
|
12091
|
+
});
|
|
12092
|
+
var PipelineValidationResultSchema = object({
|
|
12093
|
+
ok: boolean(),
|
|
12094
|
+
issues: array(PipelineValidationIssueSchema).readonly(),
|
|
12095
|
+
substitutions: array(ModelSubstitutionSchema).readonly(),
|
|
12096
|
+
/** The node's `currentEngine.format` this validation ran against. */
|
|
12097
|
+
format: string()
|
|
12098
|
+
});
|
|
11970
12099
|
var ReferenceImageEntrySchema = object({
|
|
11971
12100
|
filename: string(),
|
|
11972
12101
|
stepIds: array(string()).readonly().optional()
|
|
@@ -12037,7 +12166,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
12037
12166
|
})) }), object({ success: literal(true) }), {
|
|
12038
12167
|
kind: "mutation",
|
|
12039
12168
|
auth: "admin"
|
|
12040
|
-
}), method(
|
|
12169
|
+
}), method(object({ nodeId: string() }), object({
|
|
12170
|
+
success: literal(true),
|
|
12171
|
+
regeneratedModelId: string().nullable()
|
|
12172
|
+
}), {
|
|
12173
|
+
kind: "mutation",
|
|
12174
|
+
auth: "admin"
|
|
12175
|
+
}), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
|
|
12041
12176
|
name: string(),
|
|
12042
12177
|
steps: array(PipelineTemplateStepSchema).readonly(),
|
|
12043
12178
|
engine: PipelineEngineChoiceSchema
|
|
@@ -12330,6 +12465,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
12330
12465
|
kind: literal("remote-restream"),
|
|
12331
12466
|
/** The camera's source-owner node (slice 1: always the hub). */
|
|
12332
12467
|
ownerNodeId: string(),
|
|
12468
|
+
/**
|
|
12469
|
+
* The owner's LAN-reachable host, resolved by the orchestrator from the
|
|
12470
|
+
* per-node `reachableHost` override (Cluster UI). When present the runner
|
|
12471
|
+
* dials THIS host for the owner's restream, in preference to the
|
|
12472
|
+
* `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
|
|
12473
|
+
*/
|
|
12474
|
+
ownerReachableHost: string().optional(),
|
|
12333
12475
|
/** Operator override for the owner host the runner dials. */
|
|
12334
12476
|
hubHostnameOverride: string().optional()
|
|
12335
12477
|
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
@@ -12338,13 +12480,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
12338
12480
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
12339
12481
|
* runner needs to subscribe to the local broker and execute inference.
|
|
12340
12482
|
*
|
|
12341
|
-
* Stateless-pipeline model: the
|
|
12342
|
-
*
|
|
12343
|
-
*
|
|
12344
|
-
*
|
|
12345
|
-
*
|
|
12346
|
-
* `engine`/`steps`/`audio` are optional during the additive migration
|
|
12347
|
-
* window; once orchestrator + UI are migrated they become required.
|
|
12483
|
+
* Stateless-pipeline model: the pipeline content (`steps`, optional
|
|
12484
|
+
* `audio`) travels with the attach payload. The runner keeps it in RAM
|
|
12485
|
+
* for the lifetime of the attach — on rebalance, edit, or restart the
|
|
12486
|
+
* orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
|
|
12487
|
+
* node-local, resolved by the executing runner at dispatch time.
|
|
12348
12488
|
*/
|
|
12349
12489
|
var RunnerCameraConfigSchema = object({
|
|
12350
12490
|
deviceId: number(),
|
|
@@ -12395,14 +12535,11 @@ var RunnerCameraConfigSchema = object({
|
|
|
12395
12535
|
*/
|
|
12396
12536
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
12397
12537
|
pipelineEnabled: boolean().default(true),
|
|
12398
|
-
/** Engine choice for video steps (runtime+backend+format). */
|
|
12399
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
12400
12538
|
/** Ordered tree of video steps. Absent → runner skips video detection. */
|
|
12401
12539
|
steps: array(PipelineStepInputSchema).readonly().optional(),
|
|
12402
12540
|
/** Audio classification branch. `enabled:false` disables, null skips. */
|
|
12403
12541
|
audio: object({
|
|
12404
|
-
|
|
12405
|
-
modelId: string(),
|
|
12542
|
+
modelId: string().optional(),
|
|
12406
12543
|
enabled: boolean()
|
|
12407
12544
|
}).nullable().optional(),
|
|
12408
12545
|
/**
|
|
@@ -18277,11 +18414,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18277
18414
|
timestamp: number()
|
|
18278
18415
|
});
|
|
18279
18416
|
var CameraPipelineConfigSchema = object({
|
|
18280
|
-
engine: PipelineEngineChoiceSchema,
|
|
18417
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
18281
18418
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
18282
18419
|
audio: object({
|
|
18283
|
-
engine: PipelineEngineChoiceSchema,
|
|
18284
|
-
modelId: string(),
|
|
18420
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
18421
|
+
modelId: string().optional(),
|
|
18285
18422
|
enabled: boolean(),
|
|
18286
18423
|
settings: record(string(), unknown()).readonly().optional()
|
|
18287
18424
|
}).nullable().optional()
|
|
@@ -18296,7 +18433,7 @@ var PipelineTemplateSchema = object({
|
|
|
18296
18433
|
});
|
|
18297
18434
|
var AgentAddonConfigSchema = object({
|
|
18298
18435
|
enabled: boolean(),
|
|
18299
|
-
modelId: string(),
|
|
18436
|
+
modelId: string().optional(),
|
|
18300
18437
|
settings: record(string(), unknown()).readonly()
|
|
18301
18438
|
});
|
|
18302
18439
|
var AgentPipelineSettingsSchema = object({
|
|
@@ -18311,7 +18448,15 @@ var AgentPipelineSettingsSchema = object({
|
|
|
18311
18448
|
/** Node is eligible to run audio-analyzer sessions. */
|
|
18312
18449
|
audio: boolean().optional(),
|
|
18313
18450
|
/** Node is eligible to be the ingest / source-owner (serve the restream). */
|
|
18314
|
-
ingest: boolean().optional()
|
|
18451
|
+
ingest: boolean().optional(),
|
|
18452
|
+
/**
|
|
18453
|
+
* Operator override for the LAN host a cross-node decoder dials to reach
|
|
18454
|
+
* THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
|
|
18455
|
+
* falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
|
|
18456
|
+
* it already uses to reach the hub). Set this only when the auto-detected
|
|
18457
|
+
* address is wrong (multi-homed host, NAT, custom interface).
|
|
18458
|
+
*/
|
|
18459
|
+
reachableHost: string().optional()
|
|
18315
18460
|
});
|
|
18316
18461
|
var CameraPipelineForAgentSchema = object({
|
|
18317
18462
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -18417,6 +18562,15 @@ var GlobalMetricsSchema = object({
|
|
|
18417
18562
|
* capability providers.
|
|
18418
18563
|
*/
|
|
18419
18564
|
var CapabilityBindingsSchema = record(string(), string());
|
|
18565
|
+
/**
|
|
18566
|
+
* The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
|
|
18567
|
+
* its LAN-reachable host, if one is registered. See `getIngestOwner`.
|
|
18568
|
+
*/
|
|
18569
|
+
var IngestOwnerSchema = object({
|
|
18570
|
+
ownerNodeId: string(),
|
|
18571
|
+
reachableHost: string().optional(),
|
|
18572
|
+
configIssue: string().optional()
|
|
18573
|
+
});
|
|
18420
18574
|
/** Source block — always present; derives from the stream catalog. */
|
|
18421
18575
|
var CameraSourceStatusSchema = object({ streams: array(object({
|
|
18422
18576
|
camStreamId: string(),
|
|
@@ -18431,6 +18585,14 @@ var CameraAssignmentStatusSchema = object({
|
|
|
18431
18585
|
detectionNodeId: string().nullable(),
|
|
18432
18586
|
decoderNodeId: string().nullable(),
|
|
18433
18587
|
audioNodeId: string().nullable(),
|
|
18588
|
+
/**
|
|
18589
|
+
* The node that OWNS this camera's physical source pull (dials the RTSP and
|
|
18590
|
+
* hosts the broker/restream) — the cluster ingest owner today
|
|
18591
|
+
* (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
|
|
18592
|
+
* the UI show WHERE a camera is sourced without SSH/logs, and is the node the
|
|
18593
|
+
* broker block below was read from (pinned). Nullable only pre-wiring.
|
|
18594
|
+
*/
|
|
18595
|
+
sourceNodeId: string().nullable(),
|
|
18434
18596
|
pinned: object({
|
|
18435
18597
|
detection: boolean(),
|
|
18436
18598
|
decoder: boolean(),
|
|
@@ -18563,7 +18725,7 @@ method(object({
|
|
|
18563
18725
|
}), object({ success: literal(true) }), {
|
|
18564
18726
|
kind: "mutation",
|
|
18565
18727
|
auth: "admin"
|
|
18566
|
-
}), method(object({
|
|
18728
|
+
}), method(_void(), IngestOwnerSchema), method(object({
|
|
18567
18729
|
deviceId: number(),
|
|
18568
18730
|
nodeId: string()
|
|
18569
18731
|
}), _void(), {
|
|
@@ -18632,6 +18794,12 @@ method(object({
|
|
|
18632
18794
|
}), object({ success: literal(true) }), {
|
|
18633
18795
|
kind: "mutation",
|
|
18634
18796
|
auth: "admin"
|
|
18797
|
+
}), method(object({
|
|
18798
|
+
agentNodeId: string(),
|
|
18799
|
+
reachableHost: string().nullable()
|
|
18800
|
+
}), object({ success: literal(true) }), {
|
|
18801
|
+
kind: "mutation",
|
|
18802
|
+
auth: "admin"
|
|
18635
18803
|
}), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
|
|
18636
18804
|
deviceId: number(),
|
|
18637
18805
|
addonId: string(),
|
|
@@ -18676,22 +18844,6 @@ method(object({
|
|
|
18676
18844
|
kind: "mutation",
|
|
18677
18845
|
auth: "admin"
|
|
18678
18846
|
});
|
|
18679
|
-
var RegisteredStreamSchema = object({
|
|
18680
|
-
streamId: string(),
|
|
18681
|
-
label: string().optional(),
|
|
18682
|
-
codec: string(),
|
|
18683
|
-
type: _enum(["video", "audio"]),
|
|
18684
|
-
sourceUrl: string()
|
|
18685
|
-
});
|
|
18686
|
-
var ExposedResourceSchema = object({
|
|
18687
|
-
streamId: string(),
|
|
18688
|
-
format: string(),
|
|
18689
|
-
value: string()
|
|
18690
|
-
});
|
|
18691
|
-
method(object({
|
|
18692
|
-
deviceId: number(),
|
|
18693
|
-
streams: array(RegisteredStreamSchema).readonly()
|
|
18694
|
-
}), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(ExposedResourceSchema).readonly());
|
|
18695
18847
|
/**
|
|
18696
18848
|
* Query filter for settings-store collections.
|
|
18697
18849
|
*/
|
|
@@ -18844,9 +18996,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
|
|
|
18844
18996
|
/**
|
|
18845
18997
|
* A single device snapshot returned as base64 JPEG/PNG.
|
|
18846
18998
|
*
|
|
18847
|
-
*
|
|
18848
|
-
*
|
|
18849
|
-
*
|
|
18999
|
+
* The `SnapshotAddon` wrapper returns this shape whether the frame came from
|
|
19000
|
+
* the device-native provider (onboard capture) or from the stream-broker
|
|
19001
|
+
* prebuffer fallback.
|
|
18850
19002
|
*/
|
|
18851
19003
|
var SnapshotImageSchema = object({
|
|
18852
19004
|
base64: string(),
|
|
@@ -18921,10 +19073,6 @@ var snapshotCapability = {
|
|
|
18921
19073
|
kind: "poll"
|
|
18922
19074
|
}
|
|
18923
19075
|
};
|
|
18924
|
-
method(object({ deviceId: number() }), boolean()), method(object({
|
|
18925
|
-
deviceId: number(),
|
|
18926
|
-
streamId: string().optional()
|
|
18927
|
-
}), SnapshotImageSchema.nullable());
|
|
18928
19076
|
/**
|
|
18929
19077
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
|
18930
19078
|
* providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
|
|
@@ -19285,9 +19433,10 @@ method(object({
|
|
|
19285
19433
|
auth: "admin"
|
|
19286
19434
|
});
|
|
19287
19435
|
/**
|
|
19288
|
-
* Optional client-side hints sent at session creation to help the
|
|
19289
|
-
*
|
|
19290
|
-
*
|
|
19436
|
+
* Optional client-side hints sent at session creation to help the provider
|
|
19437
|
+
* pick the best native source. All fields optional — a viewer that knows
|
|
19438
|
+
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
19439
|
+
* collection cap; this `webrtc-session` cap is the live signaling surface.)
|
|
19291
19440
|
*/
|
|
19292
19441
|
var webrtcClientHintsSchema = object({
|
|
19293
19442
|
viewportWidth: number().int().positive().optional(),
|
|
@@ -19298,22 +19447,6 @@ var webrtcClientHintsSchema = object({
|
|
|
19298
19447
|
/** Hard tier override; takes precedence over scoring when registered. */
|
|
19299
19448
|
prefersTier: string().optional()
|
|
19300
19449
|
}).partial();
|
|
19301
|
-
method(object({
|
|
19302
|
-
streamId: string(),
|
|
19303
|
-
sdpOffer: string()
|
|
19304
|
-
}), string(), { kind: "mutation" }), method(object({ streamId: string() }), boolean()), method(object({
|
|
19305
|
-
streamId: string(),
|
|
19306
|
-
codec: string()
|
|
19307
|
-
}), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
19308
|
-
streamId: string(),
|
|
19309
|
-
hints: webrtcClientHintsSchema.optional()
|
|
19310
|
-
}), object({
|
|
19311
|
-
sessionId: string(),
|
|
19312
|
-
sdpOffer: string()
|
|
19313
|
-
}), { kind: "mutation" }), method(object({
|
|
19314
|
-
sessionId: string(),
|
|
19315
|
-
sdpAnswer: string()
|
|
19316
|
-
}), _void(), { kind: "mutation" }), method(object({ sessionId: string() }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), boolean());
|
|
19317
19450
|
/**
|
|
19318
19451
|
* Discriminated target for a WebRTC session. The client sends this
|
|
19319
19452
|
* structured object instead of building / parsing brokerId strings;
|
|
@@ -24731,6 +24864,12 @@ Object.freeze({
|
|
|
24731
24864
|
addonId: null,
|
|
24732
24865
|
access: "create"
|
|
24733
24866
|
},
|
|
24867
|
+
"pipelineExecutor.resetToDefault": {
|
|
24868
|
+
capName: "pipeline-executor",
|
|
24869
|
+
capScope: "system",
|
|
24870
|
+
addonId: null,
|
|
24871
|
+
access: "delete"
|
|
24872
|
+
},
|
|
24734
24873
|
"pipelineExecutor.runAudioTest": {
|
|
24735
24874
|
capName: "pipeline-executor",
|
|
24736
24875
|
capScope: "system",
|
|
@@ -24779,6 +24918,12 @@ Object.freeze({
|
|
|
24779
24918
|
addonId: null,
|
|
24780
24919
|
access: "create"
|
|
24781
24920
|
},
|
|
24921
|
+
"pipelineExecutor.validatePipeline": {
|
|
24922
|
+
capName: "pipeline-executor",
|
|
24923
|
+
capScope: "system",
|
|
24924
|
+
addonId: null,
|
|
24925
|
+
access: "view"
|
|
24926
|
+
},
|
|
24782
24927
|
"pipelineOrchestrator.assignAudio": {
|
|
24783
24928
|
capName: "pipeline-orchestrator",
|
|
24784
24929
|
capScope: "system",
|
|
@@ -24887,6 +25032,12 @@ Object.freeze({
|
|
|
24887
25032
|
addonId: null,
|
|
24888
25033
|
access: "view"
|
|
24889
25034
|
},
|
|
25035
|
+
"pipelineOrchestrator.getIngestOwner": {
|
|
25036
|
+
capName: "pipeline-orchestrator",
|
|
25037
|
+
capScope: "system",
|
|
25038
|
+
addonId: null,
|
|
25039
|
+
access: "view"
|
|
25040
|
+
},
|
|
24890
25041
|
"pipelineOrchestrator.getPipelineAssignment": {
|
|
24891
25042
|
capName: "pipeline-orchestrator",
|
|
24892
25043
|
capScope: "system",
|
|
@@ -24959,6 +25110,12 @@ Object.freeze({
|
|
|
24959
25110
|
addonId: null,
|
|
24960
25111
|
access: "create"
|
|
24961
25112
|
},
|
|
25113
|
+
"pipelineOrchestrator.setAgentReachableHost": {
|
|
25114
|
+
capName: "pipeline-orchestrator",
|
|
25115
|
+
capScope: "system",
|
|
25116
|
+
addonId: null,
|
|
25117
|
+
access: "create"
|
|
25118
|
+
},
|
|
24962
25119
|
"pipelineOrchestrator.setCameraPipelineForAgent": {
|
|
24963
25120
|
capName: "pipeline-orchestrator",
|
|
24964
25121
|
capScope: "system",
|
|
@@ -25289,24 +25446,6 @@ Object.freeze({
|
|
|
25289
25446
|
addonId: null,
|
|
25290
25447
|
access: "create"
|
|
25291
25448
|
},
|
|
25292
|
-
"restreamer.getExposedResources": {
|
|
25293
|
-
capName: "restreamer",
|
|
25294
|
-
capScope: "system",
|
|
25295
|
-
addonId: null,
|
|
25296
|
-
access: "view"
|
|
25297
|
-
},
|
|
25298
|
-
"restreamer.registerDevice": {
|
|
25299
|
-
capName: "restreamer",
|
|
25300
|
-
capScope: "system",
|
|
25301
|
-
addonId: null,
|
|
25302
|
-
access: "create"
|
|
25303
|
-
},
|
|
25304
|
-
"restreamer.unregisterDevice": {
|
|
25305
|
-
capName: "restreamer",
|
|
25306
|
-
capScope: "system",
|
|
25307
|
-
addonId: null,
|
|
25308
|
-
access: "delete"
|
|
25309
|
-
},
|
|
25310
25449
|
"scriptRunner.run": {
|
|
25311
25450
|
capName: "script-runner",
|
|
25312
25451
|
capScope: "device",
|
|
@@ -25409,18 +25548,6 @@ Object.freeze({
|
|
|
25409
25548
|
addonId: null,
|
|
25410
25549
|
access: "create"
|
|
25411
25550
|
},
|
|
25412
|
-
"snapshotProvider.getSnapshot": {
|
|
25413
|
-
capName: "snapshot-provider",
|
|
25414
|
-
capScope: "system",
|
|
25415
|
-
addonId: null,
|
|
25416
|
-
access: "view"
|
|
25417
|
-
},
|
|
25418
|
-
"snapshotProvider.supportsDevice": {
|
|
25419
|
-
capName: "snapshot-provider",
|
|
25420
|
-
capScope: "system",
|
|
25421
|
-
addonId: null,
|
|
25422
|
-
access: "view"
|
|
25423
|
-
},
|
|
25424
25551
|
"ssoBridge.signBridgeToken": {
|
|
25425
25552
|
capName: "sso-bridge",
|
|
25426
25553
|
capScope: "system",
|
|
@@ -25847,30 +25974,6 @@ Object.freeze({
|
|
|
25847
25974
|
addonId: null,
|
|
25848
25975
|
access: "view"
|
|
25849
25976
|
},
|
|
25850
|
-
"streamingEngine.getStreamUrl": {
|
|
25851
|
-
capName: "streaming-engine",
|
|
25852
|
-
capScope: "system",
|
|
25853
|
-
addonId: null,
|
|
25854
|
-
access: "view"
|
|
25855
|
-
},
|
|
25856
|
-
"streamingEngine.listStreams": {
|
|
25857
|
-
capName: "streaming-engine",
|
|
25858
|
-
capScope: "system",
|
|
25859
|
-
addonId: null,
|
|
25860
|
-
access: "view"
|
|
25861
|
-
},
|
|
25862
|
-
"streamingEngine.registerStream": {
|
|
25863
|
-
capName: "streaming-engine",
|
|
25864
|
-
capScope: "system",
|
|
25865
|
-
addonId: null,
|
|
25866
|
-
access: "create"
|
|
25867
|
-
},
|
|
25868
|
-
"streamingEngine.unregisterStream": {
|
|
25869
|
-
capName: "streaming-engine",
|
|
25870
|
-
capScope: "system",
|
|
25871
|
-
addonId: null,
|
|
25872
|
-
access: "delete"
|
|
25873
|
-
},
|
|
25874
25977
|
"streamParams.getConfigSchema": {
|
|
25875
25978
|
capName: "stream-params",
|
|
25876
25979
|
capScope: "device",
|
|
@@ -26237,54 +26340,6 @@ Object.freeze({
|
|
|
26237
26340
|
addonId: null,
|
|
26238
26341
|
access: "create"
|
|
26239
26342
|
},
|
|
26240
|
-
"webrtc.closeSession": {
|
|
26241
|
-
capName: "webrtc",
|
|
26242
|
-
capScope: "system",
|
|
26243
|
-
addonId: null,
|
|
26244
|
-
access: "create"
|
|
26245
|
-
},
|
|
26246
|
-
"webrtc.createSession": {
|
|
26247
|
-
capName: "webrtc",
|
|
26248
|
-
capScope: "system",
|
|
26249
|
-
addonId: null,
|
|
26250
|
-
access: "create"
|
|
26251
|
-
},
|
|
26252
|
-
"webrtc.handleAnswer": {
|
|
26253
|
-
capName: "webrtc",
|
|
26254
|
-
capScope: "system",
|
|
26255
|
-
addonId: null,
|
|
26256
|
-
access: "create"
|
|
26257
|
-
},
|
|
26258
|
-
"webrtc.handleOffer": {
|
|
26259
|
-
capName: "webrtc",
|
|
26260
|
-
capScope: "system",
|
|
26261
|
-
addonId: null,
|
|
26262
|
-
access: "create"
|
|
26263
|
-
},
|
|
26264
|
-
"webrtc.hasAdaptiveBitrate": {
|
|
26265
|
-
capName: "webrtc",
|
|
26266
|
-
capScope: "system",
|
|
26267
|
-
addonId: null,
|
|
26268
|
-
access: "view"
|
|
26269
|
-
},
|
|
26270
|
-
"webrtc.registerStream": {
|
|
26271
|
-
capName: "webrtc",
|
|
26272
|
-
capScope: "system",
|
|
26273
|
-
addonId: null,
|
|
26274
|
-
access: "create"
|
|
26275
|
-
},
|
|
26276
|
-
"webrtc.supportsStream": {
|
|
26277
|
-
capName: "webrtc",
|
|
26278
|
-
capScope: "system",
|
|
26279
|
-
addonId: null,
|
|
26280
|
-
access: "view"
|
|
26281
|
-
},
|
|
26282
|
-
"webrtc.unregisterStream": {
|
|
26283
|
-
capName: "webrtc",
|
|
26284
|
-
capScope: "system",
|
|
26285
|
-
addonId: null,
|
|
26286
|
-
access: "delete"
|
|
26287
|
-
},
|
|
26288
26343
|
"webrtcSession.addIceCandidate": {
|
|
26289
26344
|
capName: "webrtc-session",
|
|
26290
26345
|
capScope: "device",
|
|
@@ -30350,6 +30405,10 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
|
|
|
30350
30405
|
* universal overlay UI. */
|
|
30351
30406
|
osdPollTimer = null;
|
|
30352
30407
|
static OSD_POLL_INTERVAL_MS = 3e5;
|
|
30408
|
+
/** Control-plane reachability poll — drives `device.online` from ISAPI
|
|
30409
|
+
* `getDeviceInfo` liveness, decoupled from stream-broker video health.
|
|
30410
|
+
* Started in `onActivate`, stopped in `removeDevice`. */
|
|
30411
|
+
reachabilityPoll = null;
|
|
30353
30412
|
constructor(ctx) {
|
|
30354
30413
|
super(ctx, hikvisionCameraSchema, { type: DeviceType.Camera });
|
|
30355
30414
|
this.registerNativeCapabilities();
|
|
@@ -30834,6 +30893,25 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
|
|
|
30834
30893
|
if (this.osdPollTimer === null) this.osdPollTimer = setInterval(() => {
|
|
30835
30894
|
this.refreshOsdSnapshot();
|
|
30836
30895
|
}, HikvisionCamera.OSD_POLL_INTERVAL_MS);
|
|
30896
|
+
this.startReachabilityPolling();
|
|
30897
|
+
}
|
|
30898
|
+
/** Start the control-plane reachability poll: an ISAPI `getDeviceInfo`
|
|
30899
|
+
* round-trip every 30s drives `device.online`, with hysteresis. This
|
|
30900
|
+
* replaces the old stream-health→online mirror so an on-demand (idle)
|
|
30901
|
+
* camera that is reachable still reports ONLINE. Idempotent. */
|
|
30902
|
+
startReachabilityPolling() {
|
|
30903
|
+
if (this.reachabilityPoll) return;
|
|
30904
|
+
this.reachabilityPoll = startReachabilityPoll({
|
|
30905
|
+
probe: async () => {
|
|
30906
|
+
await this.ensureClient().getDeviceInfo();
|
|
30907
|
+
return true;
|
|
30908
|
+
},
|
|
30909
|
+
setOnline: (online) => {
|
|
30910
|
+
this.markOnline(online);
|
|
30911
|
+
},
|
|
30912
|
+
isEnabled: () => !this.disabled,
|
|
30913
|
+
logger: this.ctx.logger
|
|
30914
|
+
});
|
|
30837
30915
|
}
|
|
30838
30916
|
/** Single-flight OSD config fetch; updates the in-memory snapshot
|
|
30839
30917
|
* consumed by the readonly OSD section in `getSettingsUISchema`. */
|
|
@@ -33226,6 +33304,8 @@ var HikvisionCamera = class HikvisionCamera extends BaseDevice {
|
|
|
33226
33304
|
clearInterval(this.osdPollTimer);
|
|
33227
33305
|
this.osdPollTimer = null;
|
|
33228
33306
|
}
|
|
33307
|
+
this.reachabilityPoll?.stop();
|
|
33308
|
+
this.reachabilityPoll = null;
|
|
33229
33309
|
await this.disconnectAll();
|
|
33230
33310
|
for (const camStreamId of this.published.keys()) try {
|
|
33231
33311
|
await this.ctx.api.streamBroker.retractCameraStream.mutate({
|
|
@@ -42588,21 +42668,7 @@ var HikvisionProviderAddon = class extends BaseDeviceProvider {
|
|
|
42588
42668
|
throw new Error(`Hikvision: ${reason}`);
|
|
42589
42669
|
}
|
|
42590
42670
|
async onInitialize() {
|
|
42591
|
-
|
|
42592
|
-
this.subscribe({ category: EventCategory.DeviceStateChanged }, (event) => {
|
|
42593
|
-
const data = event.data;
|
|
42594
|
-
if (data.capName !== "camera-streams") return;
|
|
42595
|
-
const deviceId = data.deviceId;
|
|
42596
|
-
if (typeof deviceId !== "number") return;
|
|
42597
|
-
const registry = this.ctx.kernel.deviceRegistry;
|
|
42598
|
-
if (!registry) return;
|
|
42599
|
-
if (registry.getAddonId(deviceId) !== this.addonId) return;
|
|
42600
|
-
const device = registry.getById(deviceId);
|
|
42601
|
-
if (!device) return;
|
|
42602
|
-
const online = data.slice?.online === true;
|
|
42603
|
-
if (device.online !== online) device.online = online;
|
|
42604
|
-
});
|
|
42605
|
-
return regs;
|
|
42671
|
+
return await super.onInitialize();
|
|
42606
42672
|
}
|
|
42607
42673
|
async supportsDiscovery() {
|
|
42608
42674
|
return true;
|