@camstack/addon-matter-broker 0.2.115 → 0.2.117
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 +1542 -536
- package/dist/addon.mjs +1542 -536
- package/package.json +2 -4
package/dist/addon.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { networkInterfaces, tmpdir, uptime } from "node:os";
|
|
|
11
11
|
import { finished } from "node:stream/promises";
|
|
12
12
|
import { createConnection, createServer as createServer$2 } from "node:net";
|
|
13
13
|
import * as dgram from "node:dgram";
|
|
14
|
-
//#region ../types/dist/event-category-
|
|
14
|
+
//#region ../types/dist/event-category-BGmz_oxW.mjs
|
|
15
15
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
16
16
|
EventCategory["SystemBoot"] = "system.boot";
|
|
17
17
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -544,6 +544,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
544
544
|
*/
|
|
545
545
|
EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
|
|
546
546
|
EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
|
|
547
|
+
/**
|
|
548
|
+
* A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
|
|
549
|
+
* data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
|
|
550
|
+
* consumer is the orchestrator's camera-sensors bridge, which re-emits the
|
|
551
|
+
* camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
|
|
552
|
+
* for a camera with no attached sensor). Providers must not emit
|
|
553
|
+
* `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
|
|
554
|
+
* keeps it so (camera-grid is a named, deferred exception).
|
|
555
|
+
*/
|
|
547
556
|
EventCategory["ProviderMotion"] = "provider.motion";
|
|
548
557
|
EventCategory["ProviderDetection"] = "provider.detection";
|
|
549
558
|
EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
|
|
@@ -5382,7 +5391,7 @@ var ZodIssueCode = {
|
|
|
5382
5391
|
var ZodFirstPartyTypeKind;
|
|
5383
5392
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5384
5393
|
//#endregion
|
|
5385
|
-
//#region ../types/dist/sleep-
|
|
5394
|
+
//#region ../types/dist/sleep-CDCONfkt.mjs
|
|
5386
5395
|
/**
|
|
5387
5396
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5388
5397
|
* window to float samples (D455).
|
|
@@ -7425,23 +7434,74 @@ function errMsg(err) {
|
|
|
7425
7434
|
return String(err);
|
|
7426
7435
|
}
|
|
7427
7436
|
//#endregion
|
|
7428
|
-
//#region ../types/dist/composition-
|
|
7437
|
+
//#region ../types/dist/composition-Bzr7GwgP.mjs
|
|
7429
7438
|
/**
|
|
7430
|
-
*
|
|
7431
|
-
*
|
|
7439
|
+
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
7440
|
+
*
|
|
7441
|
+
* ## Why a download, on every node, including the container
|
|
7442
|
+
*
|
|
7443
|
+
* The version of ffmpeg used to be CODE: baked into the image, changeable only
|
|
7444
|
+
* by rebuilding and rolling it. Now it is DATA — this file states the release,
|
|
7445
|
+
* and a node that boots with a different one downloads it. Changing ffmpeg is a
|
|
7446
|
+
* framework bump, not an image rebuild.
|
|
7447
|
+
*
|
|
7448
|
+
* It also settles the licence question by removing it. FFmpeg's licence is
|
|
7449
|
+
* chosen at compile time: the core is LGPL 2.1+, `--enable-gpl` makes it GPL
|
|
7450
|
+
* (for x264/x265), `--enable-version3` makes that v3, and `--enable-nonfree`
|
|
7451
|
+
* makes the result undistributable. These are GPL v3 builds, and we do not
|
|
7452
|
+
* distribute them: the user's own node fetches the archive from the project
|
|
7453
|
+
* that publishes it, so we convey no GPL work and inherit none of the
|
|
7454
|
+
* obligations that come with conveying one. That is the whole reason the image
|
|
7455
|
+
* no longer installs ffmpeg at all — not a technical preference.
|
|
7456
|
+
*
|
|
7457
|
+
* ## Why jellyfin-ffmpeg
|
|
7432
7458
|
*
|
|
7433
|
-
*
|
|
7434
|
-
*
|
|
7435
|
-
*
|
|
7436
|
-
*
|
|
7437
|
-
*
|
|
7438
|
-
* fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
|
|
7439
|
-
* SPOSTA qui e il doorbell la ri-esporta.
|
|
7459
|
+
* One vendor covering linux-amd64, linux-arm64, darwin-arm64 and darwin-x64
|
|
7460
|
+
* from one release, with the widest hardware surface of anything maintained:
|
|
7461
|
+
* VAAPI, QSV, NVENC/NVDEC, AMF, Vulkan, OpenCL and DRM on amd64, plus Rockchip
|
|
7462
|
+
* MPP on arm64. It reaches the vendor libraries through dlopen trampolines,
|
|
7463
|
+
* so the binary is not linked against a driver stack it may not find.
|
|
7440
7464
|
*
|
|
7441
|
-
*
|
|
7442
|
-
*
|
|
7443
|
-
*
|
|
7444
|
-
*
|
|
7465
|
+
* **What it still needs from the host, measured 2026-09-19.** On the Unraid
|
|
7466
|
+
* HOST, which has no libva, `-vaapi_device` aborts the process outright —
|
|
7467
|
+
* `implib-gen: libva-drm.so.2: failed to load library ... Assertion '0 &&
|
|
7468
|
+
* "Assertion in generated code"' failed`. Inside our container, which installs
|
|
7469
|
+
* libva plus the iHD driver, the same command encodes: verified end to end with
|
|
7470
|
+
* `testsrc → format=nv12,hwupload → h264_vaapi`. So the image drops ffmpeg and
|
|
7471
|
+
* KEEPS the Intel media stack; the drivers are the part a binary cannot bring.
|
|
7472
|
+
*
|
|
7473
|
+
* ## Why each artifact carries a checksum and a claim
|
|
7474
|
+
*
|
|
7475
|
+
* The download is now the only source, so `sha256` is verified before anything
|
|
7476
|
+
* is extracted — jellyfin publishes no checksums on its release assets, so
|
|
7477
|
+
* these are ours, taken at the version bump. And `expectedHwaccels` is what the
|
|
7478
|
+
* build is supposed to be able to do: a binary that probes short of its own
|
|
7479
|
+
* claim is a source that changed under us, which is precisely what went
|
|
7480
|
+
* unnoticed for months when a static build turned out to carry no VAAPI at all
|
|
7481
|
+
* (D536).
|
|
7482
|
+
*/
|
|
7483
|
+
/** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
|
|
7484
|
+
var FFMPEG_RELEASE = "8.1.2-5";
|
|
7485
|
+
var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
|
|
7486
|
+
function portable(target) {
|
|
7487
|
+
return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
|
|
7488
|
+
}
|
|
7489
|
+
portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
|
|
7490
|
+
/**
|
|
7491
|
+
* THE table "which boolean of this device type counts as HIGH", and the
|
|
7492
|
+
* pure evaluator of its EDGE.
|
|
7493
|
+
*
|
|
7494
|
+
* ONE table for everyone who asks "is this device HIGH?": the
|
|
7495
|
+
* recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
|
|
7496
|
+
* sensor markers, the orchestrator's camera-sensors bridge and
|
|
7497
|
+
* the sources of a composite doorbell (`doorbellFeatureSources`, D671).
|
|
7498
|
+
* A second copy would diverge at the first cap added, and the symptom — "the
|
|
7499
|
+
* sensor rings the doorbell but does not record" — is exactly D62.
|
|
7500
|
+
*
|
|
7501
|
+
* ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
|
|
7502
|
+
* two must not be unified: that one answers "what is the state WORD for a
|
|
7503
|
+
* rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
|
|
7504
|
+
* boolean's EDGE counts". Deliberately different vocabularies.
|
|
7445
7505
|
*/
|
|
7446
7506
|
/**
|
|
7447
7507
|
* Known binary / switch source caps → the boolean slice field whose
|
|
@@ -8899,6 +8959,82 @@ var ArchivedDebugNoteQueryInputSchema = object({
|
|
|
8899
8959
|
/** Max rows returned, newest-first. */
|
|
8900
8960
|
limit: number().int().min(1).max(1e3).optional()
|
|
8901
8961
|
});
|
|
8962
|
+
var TrackRelationKindSchema = _enum(["same-subject", "different-subjects"]);
|
|
8963
|
+
var TrackSideSchema = _enum(["before", "after"]);
|
|
8964
|
+
var TrackPurityValueSchema = _enum(["mixed", "not-a-subject"]);
|
|
8965
|
+
var TrackRelationSchema = object({
|
|
8966
|
+
id: string$2(),
|
|
8967
|
+
deviceId: number().int(),
|
|
8968
|
+
leftTrackId: string$2(),
|
|
8969
|
+
rightTrackId: string$2(),
|
|
8970
|
+
leftSide: TrackSideSchema.nullable(),
|
|
8971
|
+
rightSide: TrackSideSchema.nullable(),
|
|
8972
|
+
relation: TrackRelationKindSchema,
|
|
8973
|
+
presence: literal("continuous").nullable(),
|
|
8974
|
+
leftStartedAt: number().int().nullable(),
|
|
8975
|
+
rightStartedAt: number().int().nullable(),
|
|
8976
|
+
createdAt: number().int(),
|
|
8977
|
+
updatedAt: number().int(),
|
|
8978
|
+
author: string$2().nullable()
|
|
8979
|
+
});
|
|
8980
|
+
var TrackPuritySchema = object({
|
|
8981
|
+
id: string$2(),
|
|
8982
|
+
deviceId: number().int(),
|
|
8983
|
+
sourceTrackId: string$2(),
|
|
8984
|
+
purity: TrackPurityValueSchema,
|
|
8985
|
+
switchAtMs: number().int().nullable(),
|
|
8986
|
+
startedAt: number().int().nullable(),
|
|
8987
|
+
createdAt: number().int(),
|
|
8988
|
+
updatedAt: number().int(),
|
|
8989
|
+
author: string$2().nullable()
|
|
8990
|
+
});
|
|
8991
|
+
var SetTrackRelationInputSchema = object({
|
|
8992
|
+
deviceId: number().int(),
|
|
8993
|
+
trackId: string$2().min(1),
|
|
8994
|
+
otherTrackId: string$2().min(1),
|
|
8995
|
+
relation: TrackRelationKindSchema,
|
|
8996
|
+
presence: literal("continuous").optional(),
|
|
8997
|
+
trackSide: TrackSideSchema.optional(),
|
|
8998
|
+
otherSide: TrackSideSchema.optional()
|
|
8999
|
+
});
|
|
9000
|
+
var ClearTrackRelationInputSchema = object({
|
|
9001
|
+
deviceId: number().int(),
|
|
9002
|
+
trackId: string$2().min(1),
|
|
9003
|
+
otherTrackId: string$2().min(1)
|
|
9004
|
+
});
|
|
9005
|
+
var ClearTrackRelationResultSchema = object({ cleared: boolean() });
|
|
9006
|
+
var SetTrackPurityInputSchema = object({
|
|
9007
|
+
deviceId: number().int(),
|
|
9008
|
+
trackId: string$2().min(1),
|
|
9009
|
+
purity: _enum([
|
|
9010
|
+
"pure",
|
|
9011
|
+
"mixed",
|
|
9012
|
+
"not-a-subject"
|
|
9013
|
+
]),
|
|
9014
|
+
switchAtMs: number().int().optional()
|
|
9015
|
+
});
|
|
9016
|
+
/** `null` when `pure` cleared the row. */
|
|
9017
|
+
var SetTrackPurityResultSchema = object({ purity: TrackPuritySchema.nullable() });
|
|
9018
|
+
var ListTrackRelationsInputSchema = object({
|
|
9019
|
+
deviceId: number().int(),
|
|
9020
|
+
trackId: string$2().optional(),
|
|
9021
|
+
since: number().int().optional(),
|
|
9022
|
+
until: number().int().optional(),
|
|
9023
|
+
limit: number().int().min(1).max(5e3).optional()
|
|
9024
|
+
});
|
|
9025
|
+
var ListTrackRelationsResultSchema = object({
|
|
9026
|
+
relations: array(TrackRelationSchema).readonly(),
|
|
9027
|
+
purities: array(TrackPuritySchema).readonly(),
|
|
9028
|
+
truncated: boolean()
|
|
9029
|
+
});
|
|
9030
|
+
_enum([
|
|
9031
|
+
"unknown-track",
|
|
9032
|
+
"cross-device",
|
|
9033
|
+
"self-relation",
|
|
9034
|
+
"contradiction",
|
|
9035
|
+
"switch-outside-track",
|
|
9036
|
+
"switch-needs-mixed"
|
|
9037
|
+
]);
|
|
8902
9038
|
/**
|
|
8903
9039
|
* Ops-log — the durable, append-only operations audit shared by the
|
|
8904
9040
|
* recordings and events management surfaces.
|
|
@@ -8974,22 +9110,22 @@ var CLASS_MAP_MACRO_TARGETS = [
|
|
|
8974
9110
|
"package"
|
|
8975
9111
|
];
|
|
8976
9112
|
/**
|
|
8977
|
-
*
|
|
8978
|
-
*
|
|
9113
|
+
* The FIRST-LEVEL macro classes: those an object detector emits and that
|
|
9114
|
+
* an operator can select.
|
|
8979
9115
|
*
|
|
8980
|
-
*
|
|
9116
|
+
* They are the three offered by the `object-detection` step
|
|
8981
9117
|
* (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
|
|
8982
|
-
* `enabledMacroClasses`). `package`
|
|
8983
|
-
* `MACRO_LABELS` —
|
|
8984
|
-
* `package-detection`,
|
|
8985
|
-
*
|
|
9118
|
+
* `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
|
|
9119
|
+
* `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
|
|
9120
|
+
* `package-detection`, whose enablement is driven by zones, and offering the
|
|
9121
|
+
* same word twice has already made an operator turn on the COCO proxy
|
|
8986
9122
|
* (suitcase/backpack/handbag) lasciando spento il detector dedicato.
|
|
8987
9123
|
*
|
|
8988
|
-
*
|
|
8989
|
-
*
|
|
8990
|
-
* (`types/detection.ts`);
|
|
8991
|
-
* (`RecordingTriggers.objectClasses`)
|
|
8992
|
-
*
|
|
9124
|
+
* ONE list. Before today the same three were hand-written in the step's offer
|
|
9125
|
+
* and a second time as the union `FirstLevelMacro`
|
|
9126
|
+
* (`types/detection.ts`); a third copy for the recording trigger
|
|
9127
|
+
* (`RecordingTriggers.objectClasses`) would have made the later divergence
|
|
9128
|
+
* invisible.
|
|
8993
9129
|
*/
|
|
8994
9130
|
var FIRST_LEVEL_MACRO_CLASSES = [
|
|
8995
9131
|
"person",
|
|
@@ -9054,17 +9190,17 @@ var RecordingStorageModeSchema = _enum([
|
|
|
9054
9190
|
"on-device-decision"
|
|
9055
9191
|
]);
|
|
9056
9192
|
/**
|
|
9057
|
-
*
|
|
9058
|
-
*
|
|
9193
|
+
* The macro classes that can open a recording window — the same
|
|
9194
|
+
* three offered by the `object-detection` step, from ONE list
|
|
9059
9195
|
* ({@link FIRST_LEVEL_MACRO_CLASSES}).
|
|
9060
9196
|
*/
|
|
9061
9197
|
var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
|
|
9062
9198
|
/**
|
|
9063
|
-
* True
|
|
9199
|
+
* True when `values` does not repeat an element.
|
|
9064
9200
|
*
|
|
9065
|
-
*
|
|
9066
|
-
*
|
|
9067
|
-
*
|
|
9201
|
+
* A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
|
|
9202
|
+
* becomes a SOURCE in `bandTriggerSources`, and the same source twice
|
|
9203
|
+
* would count its windows twice in `segmentMissedByMs`.
|
|
9068
9204
|
*/
|
|
9069
9205
|
var noDuplicates = (values) => new Set(values).size === values.length;
|
|
9070
9206
|
/** Which detectors trigger an `events`-mode band. */
|
|
@@ -9072,34 +9208,34 @@ var RecordingTriggersSchema = object({
|
|
|
9072
9208
|
motion: boolean().optional(),
|
|
9073
9209
|
audioThresholdDbfs: number().optional(),
|
|
9074
9210
|
/**
|
|
9075
|
-
*
|
|
9076
|
-
*
|
|
9077
|
-
*
|
|
9078
|
-
*
|
|
9211
|
+
* The macro classes whose detection opens a window. ABSENT = the source
|
|
9212
|
+
* is not listened to; an EMPTY array is rejected, because "events band, object
|
|
9213
|
+
* trigger on, no class" is the same shape "enabled and records
|
|
9214
|
+
* nothing, forever" that `eventsBandCanEverDemand` is written against.
|
|
9079
9215
|
*
|
|
9080
|
-
*
|
|
9081
|
-
*
|
|
9082
|
-
* `minConfidence<Macro>`
|
|
9083
|
-
* (`source: 'onboard'`)
|
|
9084
|
-
*
|
|
9216
|
+
* The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
|
|
9217
|
+
* those that went through `enabledMacroClasses`, the
|
|
9218
|
+
* `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
|
|
9219
|
+
* (`source: 'onboard'`) goes through none of those gates and does NOT open
|
|
9220
|
+
* windows — see `recorder/object-trigger.ts`.
|
|
9085
9221
|
*/
|
|
9086
9222
|
objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
|
|
9087
9223
|
/**
|
|
9088
|
-
*
|
|
9089
|
-
*
|
|
9224
|
+
* The LINKED devices whose RISING EDGE opens a window. Absent = the source
|
|
9225
|
+
* is not listened to; an empty array is rejected for the same reason as
|
|
9090
9226
|
* `objectClasses`.
|
|
9091
9227
|
*
|
|
9092
|
-
*
|
|
9093
|
-
*
|
|
9094
|
-
*
|
|
9095
|
-
*
|
|
9096
|
-
* device (D12) —
|
|
9228
|
+
* These are SOURCE device ids, not cameras: the band names them, so the
|
|
9229
|
+
* hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
|
|
9230
|
+
* does no RPC. The OFFER from which the operator picks them is another question, and
|
|
9231
|
+
* is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
|
|
9232
|
+
* device (D12) — never a global list of caps.
|
|
9097
9233
|
*
|
|
9098
|
-
*
|
|
9099
|
-
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`)
|
|
9100
|
-
*
|
|
9101
|
-
*
|
|
9102
|
-
*
|
|
9234
|
+
* What "high" means depends on the device TYPE and is not decided here:
|
|
9235
|
+
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
|
|
9236
|
+
* the same one as the composite doorbell (D671). And it is the EDGE, not
|
|
9237
|
+
* the level: a contact found already open at runner restart does not
|
|
9238
|
+
* record.
|
|
9103
9239
|
*/
|
|
9104
9240
|
sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
|
|
9105
9241
|
});
|
|
@@ -10176,7 +10312,7 @@ var DecoderSessionConfigSchema = object({
|
|
|
10176
10312
|
* - **VALUE** — at which level, for which scope, until when. That stays ONE
|
|
10177
10313
|
* thing: the logging settings document on the `system` cap. Two authorities
|
|
10178
10314
|
* over the values is the exact defect
|
|
10179
|
-
* `docs/design/plans/2026-08-26-
|
|
10315
|
+
* `docs/design/plans/2026-08-26-per-component-logging.md` was written to
|
|
10180
10316
|
* remove; re-introducing it from the cure side would be grotesque.
|
|
10181
10317
|
*
|
|
10182
10318
|
* Nothing in this file reads a clock, an env var or a store. The registry is
|
|
@@ -11452,6 +11588,68 @@ method(object({
|
|
|
11452
11588
|
password: string$2()
|
|
11453
11589
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string$2() }), string$2()), method(record(string$2(), string$2()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string$2() }), AuthResultSchema.nullable());
|
|
11454
11590
|
/**
|
|
11591
|
+
* How long one snapshot may take end to end: the pinned copy of the whole
|
|
11592
|
+
* database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
|
|
11593
|
+
* disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
|
|
11594
|
+
* generous because a timeout fails the whole backup run.
|
|
11595
|
+
*/
|
|
11596
|
+
var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
|
|
11597
|
+
/**
|
|
11598
|
+
* The databases an owner snapshots — declared by the OWNER, so a caller never
|
|
11599
|
+
* guesses which file is live from what sits beside it (a cleanly closed
|
|
11600
|
+
* database has no sidecars and is just as owned). Paths are absolute on the
|
|
11601
|
+
* owner's host.
|
|
11602
|
+
*/
|
|
11603
|
+
var DatabaseSnapshotTargetsSchema = object({ databases: array(object({ livePath: string$2() })) });
|
|
11604
|
+
/** One b-tree table of the snapshot and the rows it holds. */
|
|
11605
|
+
var DatabaseSnapshotTableSchema = object({
|
|
11606
|
+
name: string$2(),
|
|
11607
|
+
rows: number().int().nonnegative()
|
|
11608
|
+
});
|
|
11609
|
+
/**
|
|
11610
|
+
* What the owner wrote. Every path is ABSOLUTE on the owner's host — the
|
|
11611
|
+
* caller pins the call to its own node, so it can read the file; a caller
|
|
11612
|
+
* that finds the path outside its own data root refuses it rather than
|
|
11613
|
+
* archiving something it cannot place.
|
|
11614
|
+
*/
|
|
11615
|
+
var DatabaseSnapshotResultSchema = object({
|
|
11616
|
+
/** The live database the snapshot copies. Never to be copied as a file. */
|
|
11617
|
+
livePath: string$2(),
|
|
11618
|
+
/** The verified copy: `<livePath>` + {@link DATABASE_SNAPSHOT_SUFFIX}. */
|
|
11619
|
+
snapshotPath: string$2(),
|
|
11620
|
+
sizeBytes: number().int().nonnegative(),
|
|
11621
|
+
pageCount: number().int().nonnegative(),
|
|
11622
|
+
pageSize: number().int().positive(),
|
|
11623
|
+
/**
|
|
11624
|
+
* Every b-tree table with its row count. Read inside the SAME read
|
|
11625
|
+
* transaction the copy was taken from, and found EQUAL on the copy — so
|
|
11626
|
+
* this is the content of the snapshot, not an estimate of the source.
|
|
11627
|
+
*/
|
|
11628
|
+
tables: array(DatabaseSnapshotTableSchema),
|
|
11629
|
+
/** Wall time of the pinned copy (row counts included). */
|
|
11630
|
+
copyMs: number().nonnegative(),
|
|
11631
|
+
/** Wall time of the checks on the copy (`integrity_check`, row counts). */
|
|
11632
|
+
verifyMs: number().nonnegative(),
|
|
11633
|
+
/** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
|
|
11634
|
+
takenAt: number()
|
|
11635
|
+
});
|
|
11636
|
+
/**
|
|
11637
|
+
* A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
|
|
11638
|
+
* the same facts, with both paths relative to the archive root (the node's
|
|
11639
|
+
* data dir), because an archive outlives the host that made it.
|
|
11640
|
+
*/
|
|
11641
|
+
var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
|
|
11642
|
+
/** Archive-relative path of the live database the archive does NOT carry. */
|
|
11643
|
+
livePath: string$2(),
|
|
11644
|
+
/** Archive-relative path of the verified copy it carries in its place. */
|
|
11645
|
+
snapshotPath: string$2()
|
|
11646
|
+
});
|
|
11647
|
+
method(object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }), method(object({}), DatabaseSnapshotResultSchema, {
|
|
11648
|
+
kind: "mutation",
|
|
11649
|
+
auth: "admin",
|
|
11650
|
+
timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
|
|
11651
|
+
});
|
|
11652
|
+
/**
|
|
11455
11653
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
11456
11654
|
* `id = <addonId>:<subId>` from its provider lookup so consumers
|
|
11457
11655
|
* (admin UI, restore flow) see one canonical key.
|
|
@@ -11562,7 +11760,12 @@ var ArchiveManifestSchema = object({
|
|
|
11562
11760
|
locations: array(string$2()),
|
|
11563
11761
|
entries: array(ArchiveEntrySchema),
|
|
11564
11762
|
totalBytes: number(),
|
|
11565
|
-
totalFiles: number()
|
|
11763
|
+
totalFiles: number(),
|
|
11764
|
+
/**
|
|
11765
|
+
* Live SQLite databases this archive carries as their OWNER's verified
|
|
11766
|
+
* snapshot instead of as files (D693). Absent on archives made before.
|
|
11767
|
+
*/
|
|
11768
|
+
sqliteSnapshots: array(ArchiveSqliteSnapshotSchema).optional()
|
|
11566
11769
|
});
|
|
11567
11770
|
var LocationStatSchema = object({
|
|
11568
11771
|
name: string$2(),
|
|
@@ -11820,7 +12023,7 @@ var BrokerStatusEnum = _enum([
|
|
|
11820
12023
|
"unreachable",
|
|
11821
12024
|
"error"
|
|
11822
12025
|
]);
|
|
11823
|
-
var BrokerInfoSchema
|
|
12026
|
+
var BrokerInfoSchema = object({
|
|
11824
12027
|
/** Stable broker id. Persisted; survives addon restarts. */
|
|
11825
12028
|
id: string$2(),
|
|
11826
12029
|
/** Addon id of the provider that OWNS this broker.
|
|
@@ -11963,8 +12166,8 @@ var brokerCapability = {
|
|
|
11963
12166
|
kind: "poll"
|
|
11964
12167
|
},
|
|
11965
12168
|
methods: {
|
|
11966
|
-
list: method(ListInputSchema, array(BrokerInfoSchema
|
|
11967
|
-
get: method(GetInputSchema, BrokerInfoSchema
|
|
12169
|
+
list: method(ListInputSchema, array(BrokerInfoSchema)),
|
|
12170
|
+
get: method(GetInputSchema, BrokerInfoSchema.nullable()),
|
|
11968
12171
|
/** Enumerate which addon provides which broker kind(s) for the
|
|
11969
12172
|
* unified create picker. The auto-mount fans this array across
|
|
11970
12173
|
* every registered `broker` provider (array-output method), so the
|
|
@@ -13137,6 +13340,116 @@ var CompositionBlockStateSchema = object({
|
|
|
13137
13340
|
reason: string$2().optional(),
|
|
13138
13341
|
fields: array(CompositionFieldStateSchema)
|
|
13139
13342
|
});
|
|
13343
|
+
var ComposerBlockSchema = object({
|
|
13344
|
+
id: string$2().min(1),
|
|
13345
|
+
name: string$2().min(1).max(120),
|
|
13346
|
+
enabled: boolean(),
|
|
13347
|
+
updatedAt: number(),
|
|
13348
|
+
composition: CompositionSchema
|
|
13349
|
+
});
|
|
13350
|
+
/**
|
|
13351
|
+
* A stored composition row that no longer PARSES — a schema a release
|
|
13352
|
+
* tightened, a row written by a newer build. Sent by id so the composer keeps
|
|
13353
|
+
* its device as a placeholder and reports the block `failed` naming the parse
|
|
13354
|
+
* error. Leaving it out would read, twice, exactly like a delete (D49).
|
|
13355
|
+
*/
|
|
13356
|
+
var ComposerUnreadableBlockSchema = object({
|
|
13357
|
+
id: string$2().min(1),
|
|
13358
|
+
/** The row's stored name column; null when even that is unreadable (the device keeps the name it has). */
|
|
13359
|
+
name: string$2().nullable(),
|
|
13360
|
+
/** The parse error, in the operator's words. */
|
|
13361
|
+
error: string$2()
|
|
13362
|
+
});
|
|
13363
|
+
method(object({
|
|
13364
|
+
/** The shared Blocks integration; null until `core-blocks` has reconciled it. */
|
|
13365
|
+
integrationId: string$2().nullable(),
|
|
13366
|
+
/** False when the `core_blocks` read failed: then nothing may be withdrawn (D49). */
|
|
13367
|
+
storeLoaded: boolean(),
|
|
13368
|
+
blocks: array(ComposerBlockSchema),
|
|
13369
|
+
/** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
|
|
13370
|
+
restartBlockIds: array(string$2()),
|
|
13371
|
+
/** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
|
|
13372
|
+
unreadableBlocks: array(ComposerUnreadableBlockSchema)
|
|
13373
|
+
}), object({
|
|
13374
|
+
blocks: array(object({
|
|
13375
|
+
blockId: string$2(),
|
|
13376
|
+
status: CompositionRunStatusSchema,
|
|
13377
|
+
reason: string$2().optional()
|
|
13378
|
+
})),
|
|
13379
|
+
/**
|
|
13380
|
+
* False when the composer declared and withdrew NOTHING (store not loaded,
|
|
13381
|
+
* integration unknown, its own rows unread or read empty once). An empty
|
|
13382
|
+
* apply the caller owes is paid off only by one the composer acted on (D49).
|
|
13383
|
+
*/
|
|
13384
|
+
acted: boolean()
|
|
13385
|
+
}), {
|
|
13386
|
+
kind: "mutation",
|
|
13387
|
+
auth: "admin"
|
|
13388
|
+
}), method(object({ blockIds: array(string$2()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
13389
|
+
var NUMBER = {
|
|
13390
|
+
kind: "fixed",
|
|
13391
|
+
result: ["number"]
|
|
13392
|
+
};
|
|
13393
|
+
var BOOLEAN = {
|
|
13394
|
+
kind: "fixed",
|
|
13395
|
+
result: ["boolean"]
|
|
13396
|
+
};
|
|
13397
|
+
Object.freeze({
|
|
13398
|
+
min: NUMBER,
|
|
13399
|
+
max: NUMBER,
|
|
13400
|
+
abs: NUMBER,
|
|
13401
|
+
floor: NUMBER,
|
|
13402
|
+
ceil: NUMBER,
|
|
13403
|
+
sqrt: NUMBER,
|
|
13404
|
+
round: NUMBER,
|
|
13405
|
+
pow: NUMBER,
|
|
13406
|
+
clamp: NUMBER,
|
|
13407
|
+
avg: NUMBER,
|
|
13408
|
+
sum: NUMBER,
|
|
13409
|
+
age: NUMBER,
|
|
13410
|
+
convert: NUMBER,
|
|
13411
|
+
coalesce: { kind: "coalesce" },
|
|
13412
|
+
any: BOOLEAN,
|
|
13413
|
+
all: BOOLEAN,
|
|
13414
|
+
within: BOOLEAN,
|
|
13415
|
+
latest: {
|
|
13416
|
+
kind: "fixed",
|
|
13417
|
+
result: ["number", "null"]
|
|
13418
|
+
},
|
|
13419
|
+
number: {
|
|
13420
|
+
kind: "fixed",
|
|
13421
|
+
result: ["number", "null"]
|
|
13422
|
+
},
|
|
13423
|
+
rose: {
|
|
13424
|
+
kind: "fixed",
|
|
13425
|
+
result: ["number", "null"]
|
|
13426
|
+
},
|
|
13427
|
+
count: NUMBER
|
|
13428
|
+
});
|
|
13429
|
+
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
13430
|
+
/**
|
|
13431
|
+
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
13432
|
+
* device of that type, or an existing one that lacks them, can be given. The
|
|
13433
|
+
* blockers are the validator's own refusal codes, and a spec compares this
|
|
13434
|
+
* listing with `planComposition` for every capability — the editor can never
|
|
13435
|
+
* offer a feature the save would refuse for the same reason.
|
|
13436
|
+
*/
|
|
13437
|
+
var ComposableFieldSchema = object({
|
|
13438
|
+
path: string$2(),
|
|
13439
|
+
kind: CompositionFieldKindSchema,
|
|
13440
|
+
nullable: boolean(),
|
|
13441
|
+
required: boolean(),
|
|
13442
|
+
enumValues: array(string$2()).optional()
|
|
13443
|
+
});
|
|
13444
|
+
var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
13445
|
+
cap: string$2(),
|
|
13446
|
+
fields: array(ComposableFieldSchema),
|
|
13447
|
+
/** Present for an item-array cap (`consumables.items`). */
|
|
13448
|
+
itemArray: object({
|
|
13449
|
+
path: string$2(),
|
|
13450
|
+
keyField: string$2()
|
|
13451
|
+
}).optional()
|
|
13452
|
+
})) });
|
|
13140
13453
|
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
13141
13454
|
* agent is the reason placement is not fixed to the hub. */
|
|
13142
13455
|
var CoreBlockPlacementSchema = union([literal("hub"), string$2().min(1)]);
|
|
@@ -13301,7 +13614,7 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
13301
13614
|
}), method(object({ blockId: string$2() }), CompositionGetReadSchema, { auth: "admin" }), method(object({}), CompositionListReadSchema, { auth: "admin" }), method(object({
|
|
13302
13615
|
addonId: string$2().min(1),
|
|
13303
13616
|
stableId: string$2().min(1)
|
|
13304
|
-
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({
|
|
13617
|
+
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({ deviceType: _enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }), method(object({
|
|
13305
13618
|
composition: CompositionSchema,
|
|
13306
13619
|
blockId: string$2().optional()
|
|
13307
13620
|
}), CompositionValidationSchema, {
|
|
@@ -13309,52 +13622,6 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
13309
13622
|
auth: "admin",
|
|
13310
13623
|
access: "view"
|
|
13311
13624
|
});
|
|
13312
|
-
var ComposerBlockSchema = object({
|
|
13313
|
-
id: string$2().min(1),
|
|
13314
|
-
name: string$2().min(1).max(120),
|
|
13315
|
-
enabled: boolean(),
|
|
13316
|
-
updatedAt: number(),
|
|
13317
|
-
composition: CompositionSchema
|
|
13318
|
-
});
|
|
13319
|
-
/**
|
|
13320
|
-
* A stored composition row that no longer PARSES — a schema a release
|
|
13321
|
-
* tightened, a row written by a newer build. Sent by id so the composer keeps
|
|
13322
|
-
* its device as a placeholder and reports the block `failed` naming the parse
|
|
13323
|
-
* error. Leaving it out would read, twice, exactly like a delete (D49).
|
|
13324
|
-
*/
|
|
13325
|
-
var ComposerUnreadableBlockSchema = object({
|
|
13326
|
-
id: string$2().min(1),
|
|
13327
|
-
/** The row's stored name column; null when even that is unreadable (the device keeps the name it has). */
|
|
13328
|
-
name: string$2().nullable(),
|
|
13329
|
-
/** The parse error, in the operator's words. */
|
|
13330
|
-
error: string$2()
|
|
13331
|
-
});
|
|
13332
|
-
method(object({
|
|
13333
|
-
/** The shared Blocks integration; null until `core-blocks` has reconciled it. */
|
|
13334
|
-
integrationId: string$2().nullable(),
|
|
13335
|
-
/** False when the `core_blocks` read failed: then nothing may be withdrawn (D49). */
|
|
13336
|
-
storeLoaded: boolean(),
|
|
13337
|
-
blocks: array(ComposerBlockSchema),
|
|
13338
|
-
/** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
|
|
13339
|
-
restartBlockIds: array(string$2()),
|
|
13340
|
-
/** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
|
|
13341
|
-
unreadableBlocks: array(ComposerUnreadableBlockSchema)
|
|
13342
|
-
}), object({
|
|
13343
|
-
blocks: array(object({
|
|
13344
|
-
blockId: string$2(),
|
|
13345
|
-
status: CompositionRunStatusSchema,
|
|
13346
|
-
reason: string$2().optional()
|
|
13347
|
-
})),
|
|
13348
|
-
/**
|
|
13349
|
-
* False when the composer declared and withdrew NOTHING (store not loaded,
|
|
13350
|
-
* integration unknown, its own rows unread or read empty once). An empty
|
|
13351
|
-
* apply the caller owes is paid off only by one the composer acted on (D49).
|
|
13352
|
-
*/
|
|
13353
|
-
acted: boolean()
|
|
13354
|
-
}), {
|
|
13355
|
-
kind: "mutation",
|
|
13356
|
-
auth: "admin"
|
|
13357
|
-
}), method(object({ blockIds: array(string$2()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
13358
13625
|
/**
|
|
13359
13626
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
13360
13627
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -13649,7 +13916,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
13649
13916
|
*
|
|
13650
13917
|
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
13651
13918
|
* was wrong — corrected 2026-08-26 after the hop map
|
|
13652
|
-
* (`docs/design/2026-08-26-
|
|
13919
|
+
* (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
|
|
13653
13920
|
* There is **no Zod parse at all** between the door and the engine: the
|
|
13654
13921
|
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
13655
13922
|
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
@@ -14529,7 +14796,17 @@ var SiteZoneSchema = object({
|
|
|
14529
14796
|
var ProviderStatusSchema = object({
|
|
14530
14797
|
connected: boolean(),
|
|
14531
14798
|
deviceCount: number(),
|
|
14532
|
-
error: string$2().optional()
|
|
14799
|
+
error: string$2().optional(),
|
|
14800
|
+
/**
|
|
14801
|
+
* `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
|
|
14802
|
+
* — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
|
|
14803
|
+
* which every provider bundles, so only a provider BUILT from D696-amended
|
|
14804
|
+
* code says it. ABSENT means an older provider that may still write it (raw
|
|
14805
|
+
* VMD writes, a boot seed), and the orchestrator's provider gate keeps that
|
|
14806
|
+
* provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
|
|
14807
|
+
* — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
|
|
14808
|
+
*/
|
|
14809
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
14533
14810
|
});
|
|
14534
14811
|
object({
|
|
14535
14812
|
externalId: string$2(),
|
|
@@ -15408,6 +15685,121 @@ method(object({
|
|
|
15408
15685
|
deviceIds: array(number()).readonly(),
|
|
15409
15686
|
caps: array(string$2()).readonly().optional()
|
|
15410
15687
|
}), record(string$2(), record(string$2(), unknown().nullable())));
|
|
15688
|
+
var ExtensionSlotIdSchema = _enum(["linked-devices"]);
|
|
15689
|
+
DeviceType.Camera;
|
|
15690
|
+
/** A slot's editable value, discriminated on `slot`. */
|
|
15691
|
+
var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
15692
|
+
DeviceType.Camera;
|
|
15693
|
+
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
15694
|
+
state: literal("unreachable"),
|
|
15695
|
+
reason: string$2()
|
|
15696
|
+
})]);
|
|
15697
|
+
/** One provider of slots — the D554 source-listing row. */
|
|
15698
|
+
var ExtensionSourceSchema = object({
|
|
15699
|
+
/** The routing prefix of every `slotRef` this provider serves. */
|
|
15700
|
+
source: string$2(),
|
|
15701
|
+
label: string$2(),
|
|
15702
|
+
/** Stamped by the dispatcher from the registry (D557). */
|
|
15703
|
+
addonId: string$2().optional(),
|
|
15704
|
+
availability: ExtensionSourceAvailabilitySchema
|
|
15705
|
+
});
|
|
15706
|
+
/**
|
|
15707
|
+
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
15708
|
+
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
15709
|
+
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
15710
|
+
* valid source now (a container, which is never a pick). A source in any of
|
|
15711
|
+
* these states is SHOWN, never silently dropped or re-pointed.
|
|
15712
|
+
*/
|
|
15713
|
+
var ExtensionSourceHealthSchema = _enum([
|
|
15714
|
+
"ok",
|
|
15715
|
+
"missing",
|
|
15716
|
+
"foreign",
|
|
15717
|
+
"unavailable"
|
|
15718
|
+
]);
|
|
15719
|
+
var ExtensionSlotSourceSchema = object({
|
|
15720
|
+
deviceId: number().int(),
|
|
15721
|
+
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
15722
|
+
name: string$2().nullable(),
|
|
15723
|
+
health: ExtensionSourceHealthSchema,
|
|
15724
|
+
detail: string$2().optional()
|
|
15725
|
+
});
|
|
15726
|
+
/**
|
|
15727
|
+
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
15728
|
+
* reported read-only, named, never written through this contract (D62) — e.g.
|
|
15729
|
+
* a slot whose sources act only while a wrapper is bound to the host, a
|
|
15730
|
+
* binding that belongs to `deviceManager.setWrapperActive`. No slot reports
|
|
15731
|
+
* one today (`linked-devices` answers `null`). `unknown` means the gate could
|
|
15732
|
+
* not be read; it is not "inactive" (D315).
|
|
15733
|
+
*/
|
|
15734
|
+
var ExtensionSlotActivationSchema = object({
|
|
15735
|
+
state: _enum([
|
|
15736
|
+
"active",
|
|
15737
|
+
"inactive",
|
|
15738
|
+
"unknown"
|
|
15739
|
+
]),
|
|
15740
|
+
authority: string$2(),
|
|
15741
|
+
detail: string$2().optional()
|
|
15742
|
+
});
|
|
15743
|
+
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
15744
|
+
state: literal("ok"),
|
|
15745
|
+
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
15746
|
+
slotRef: string$2(),
|
|
15747
|
+
slot: ExtensionSlotIdSchema,
|
|
15748
|
+
/** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
|
|
15749
|
+
authority: string$2(),
|
|
15750
|
+
activation: ExtensionSlotActivationSchema.nullable(),
|
|
15751
|
+
value: ExtensionSlotValueSchema,
|
|
15752
|
+
sources: array(ExtensionSlotSourceSchema),
|
|
15753
|
+
/**
|
|
15754
|
+
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
15755
|
+
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
15756
|
+
* the child a picked container stands for (D356 — a container is never a
|
|
15757
|
+
* pick, its children are). Read-only; the editor shows them and may offer
|
|
15758
|
+
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
15759
|
+
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
15760
|
+
* older than D655.
|
|
15761
|
+
*/
|
|
15762
|
+
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
15763
|
+
}), object({
|
|
15764
|
+
state: literal("unreachable"),
|
|
15765
|
+
addonId: string$2(),
|
|
15766
|
+
reason: string$2()
|
|
15767
|
+
})]);
|
|
15768
|
+
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
15769
|
+
deviceId: number().int(),
|
|
15770
|
+
name: string$2(),
|
|
15771
|
+
type: string$2(),
|
|
15772
|
+
location: string$2().nullable(),
|
|
15773
|
+
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
15774
|
+
parentName: string$2().nullable(),
|
|
15775
|
+
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
15776
|
+
suggested: boolean(),
|
|
15777
|
+
/** Why it is suggested ("same location"), null when it is not. */
|
|
15778
|
+
reason: string$2().nullable()
|
|
15779
|
+
})) });
|
|
15780
|
+
/**
|
|
15781
|
+
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
15782
|
+
* reloaded the host (or, for an accessory child, its parent) because the
|
|
15783
|
+
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
15784
|
+
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
15785
|
+
*/
|
|
15786
|
+
var ExtensionSetResultSchema = object({
|
|
15787
|
+
applied: literal(true),
|
|
15788
|
+
reload: _enum([
|
|
15789
|
+
"none",
|
|
15790
|
+
"host",
|
|
15791
|
+
"parent"
|
|
15792
|
+
])
|
|
15793
|
+
});
|
|
15794
|
+
var ExtensionSlotRefInputSchema = object({
|
|
15795
|
+
deviceId: number().int(),
|
|
15796
|
+
slotRef: string$2().min(1)
|
|
15797
|
+
});
|
|
15798
|
+
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
15799
|
+
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
15800
|
+
kind: "mutation",
|
|
15801
|
+
auth: "admin"
|
|
15802
|
+
});
|
|
15411
15803
|
/**
|
|
15412
15804
|
* Per-field ownership (D663). A composition may CLAIM fields of a native
|
|
15413
15805
|
* cap's runtime-state slice on an existing device: `replace` overlays the
|
|
@@ -15631,7 +16023,7 @@ method(object({
|
|
|
15631
16023
|
* per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
|
|
15632
16024
|
* ends in a log line, and a log line is the thing the operator asked to stop
|
|
15633
16025
|
* needing: *"possiamo armare questi errori intanto? Così al prossimo giro
|
|
15634
|
-
* ricontrolliamo tutti questi punti"
|
|
16026
|
+
* ricontrolliamo tutti questi punti"* [can we instrument these errors in the meantime? That way next round we recheck all these points]. Reading them meant grepping Loki and
|
|
15635
16027
|
* hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
|
|
15636
16028
|
* media blackout were both diagnosed. The counters stay; this is where they can
|
|
15637
16029
|
* be READ.
|
|
@@ -17007,7 +17399,7 @@ var BrokerStatusSchema$1 = _enum([
|
|
|
17007
17399
|
"unreachable",
|
|
17008
17400
|
"tls-error"
|
|
17009
17401
|
]);
|
|
17010
|
-
var BrokerInfoSchema = object({
|
|
17402
|
+
var BrokerInfoSchema$1 = object({
|
|
17011
17403
|
id: string$2(),
|
|
17012
17404
|
name: string$2(),
|
|
17013
17405
|
url: string$2(),
|
|
@@ -17070,7 +17462,7 @@ var StatusSchema = object({
|
|
|
17070
17462
|
brokerCount: number(),
|
|
17071
17463
|
embeddedRunning: boolean()
|
|
17072
17464
|
});
|
|
17073
|
-
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17465
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17074
17466
|
kind: "mutation",
|
|
17075
17467
|
auth: "admin"
|
|
17076
17468
|
}), method(IdInputSchema, _void(), {
|
|
@@ -18418,17 +18810,25 @@ var NcScheduleSchema = object({
|
|
|
18418
18810
|
*/
|
|
18419
18811
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
18420
18812
|
/**
|
|
18813
|
+
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
18814
|
+
* every section; `section` = one notification per section with something to
|
|
18815
|
+
* say (an unavailable section included), each titled by its section.
|
|
18816
|
+
*/
|
|
18817
|
+
var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
18818
|
+
/**
|
|
18421
18819
|
* `summary`: the rule sends NOTHING per event. When a window of `schedule`
|
|
18422
18820
|
* CLOSES, it sends one notification with the current state of its kinds
|
|
18423
18821
|
* (low batteries, consumables to replace, devices offline, updates
|
|
18424
|
-
* available, ...), after its own filters
|
|
18822
|
+
* available, ...), after its own filters — or, with `split: 'section'`
|
|
18823
|
+
* (D698), one notification per section. Nothing to report sends nothing.
|
|
18425
18824
|
* The schedule is the ordinary `NcSchedule` (weekly windows, IANA timezone,
|
|
18426
18825
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
18427
18826
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
18428
18827
|
*/
|
|
18429
18828
|
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [object({ mode: literal("instant") }), object({
|
|
18430
18829
|
mode: literal("summary"),
|
|
18431
|
-
schedule: NcScheduleSchema
|
|
18830
|
+
schedule: NcScheduleSchema,
|
|
18831
|
+
split: NcStateSummarySplitSchema.optional()
|
|
18432
18832
|
})]);
|
|
18433
18833
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
18434
18834
|
var NcPlateMatcherSchema = object({
|
|
@@ -18568,8 +18968,14 @@ var NcSensorTransitionSchema = _enum(["raised", "cleared"]);
|
|
|
18568
18968
|
/** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
|
|
18569
18969
|
var NcZoneConditionSchema = object({
|
|
18570
18970
|
ids: array(string$2().min(1)).min(1),
|
|
18571
|
-
/**
|
|
18572
|
-
|
|
18971
|
+
/**
|
|
18972
|
+
* LEGACY quantifier over `ids`. Absent = `any` (at least one visited), which
|
|
18973
|
+
* is what both editors mean and all they write since D690: "all of" was
|
|
18974
|
+
* removed from the editors because on an immediate rule it asked one
|
|
18975
|
+
* detection to stand in every zone at once. Still ACCEPTED, and `all` still
|
|
18976
|
+
* evaluated, so a stored rule keeps parsing and meaning what it meant.
|
|
18977
|
+
*/
|
|
18978
|
+
match: _enum(["any", "all"]).optional()
|
|
18573
18979
|
});
|
|
18574
18980
|
/**
|
|
18575
18981
|
* The P1 condition set — a flat AND of groups; absent group = pass;
|
|
@@ -19073,10 +19479,12 @@ var NcMediaPolicySchema = object({
|
|
|
19073
19479
|
/**
|
|
19074
19480
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
19075
19481
|
* notification suppresses.
|
|
19076
|
-
* - `
|
|
19077
|
-
*
|
|
19078
|
-
*
|
|
19079
|
-
*
|
|
19482
|
+
* - `per-class` (default, and the absent value since 2026-10-01 — D36) — an
|
|
19483
|
+
* independent window per detected class: cat→dog fires at once, cat→cat
|
|
19484
|
+
* still waits.
|
|
19485
|
+
* - `shared` — one window for the whole rule/scope: a cat silences the next
|
|
19486
|
+
* dog for `cooldownSec`. Only written when an operator picks it; it is no
|
|
19487
|
+
* longer what an unset rule means.
|
|
19080
19488
|
*
|
|
19081
19489
|
* AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
|
|
19082
19490
|
* must not be swallowed by a bark's window (the precedent this generalizes —
|
|
@@ -19091,8 +19499,11 @@ var NcThrottleSchema = object({
|
|
|
19091
19499
|
/**
|
|
19092
19500
|
* Class granularity of the cooldown key. Optional rather than defaulted:
|
|
19093
19501
|
* a Zod default does NOT run on the addon→addon cap path, so a persisted
|
|
19094
|
-
* rule authored before this field simply carries none
|
|
19095
|
-
*
|
|
19502
|
+
* rule authored before this field simply carries none. The engine used to
|
|
19503
|
+
* read absent as `shared` (D36); since 2026-10-01 it reads absent as
|
|
19504
|
+
* `per-class` — the operator's default — and only an explicit `shared`
|
|
19505
|
+
* still means `shared`. See `cooldownKey` / `keysPerClass` in the rule
|
|
19506
|
+
* engine, and D36's dated note.
|
|
19096
19507
|
*/
|
|
19097
19508
|
granularity: NcThrottleGranularitySchema.optional()
|
|
19098
19509
|
});
|
|
@@ -19265,78 +19676,16 @@ var NcRuleInputSchema = object({
|
|
|
19265
19676
|
*/
|
|
19266
19677
|
confirm: NcConfirmSchema.optional(),
|
|
19267
19678
|
/**
|
|
19268
|
-
*
|
|
19269
|
-
*
|
|
19270
|
-
*
|
|
19271
|
-
*
|
|
19272
|
-
*
|
|
19273
|
-
*
|
|
19274
|
-
*
|
|
19275
|
-
*
|
|
19276
|
-
*
|
|
19277
|
-
* Only two honest answers exist, and this flag picks between them. It has
|
|
19278
|
-
* effect ONLY on a rule that declares a recognition scope
|
|
19279
|
-
* ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
|
|
19280
|
-
* other rule there is nothing to wait for and the flag is inert.
|
|
19281
|
-
*
|
|
19282
|
-
* | value | what happens |
|
|
19283
|
-
* | --- | --- |
|
|
19284
|
-
* | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
|
|
19285
|
-
* | absent / `false` | it fires at once WITHOUT the name, and if recognition lands before the track closes a SECOND, "…is Gianluca" notification follows (one per track, per rule, per target) |
|
|
19286
|
-
*
|
|
19287
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19288
|
-
* on the addon cap path, and absent has to keep meaning exactly what every
|
|
19289
|
-
* rule authored before this field meant.
|
|
19290
|
-
*
|
|
19291
|
-
* The cost of `true` is stated here because the editor states it too: a rule
|
|
19292
|
-
* that waits also inherits track-close SEMANTICS — its `zones` condition
|
|
19293
|
-
* tests every zone the track visited and a `crossing` condition can no longer
|
|
19294
|
-
* be satisfied, because a closed track carries no crossing.
|
|
19295
|
-
*/
|
|
19296
|
-
waitForEnhancement: boolean().optional(),
|
|
19297
|
-
/**
|
|
19298
|
-
* GROUP a burst of subjects into ONE notification that grows.
|
|
19299
|
-
*
|
|
19300
|
-
* Seconds of quiet after the last matching subject before the burst is
|
|
19301
|
-
* considered over. While it is open, the first subject enqueues immediately —
|
|
19302
|
-
* **exactly as today, with no added latency** — and every real growth (a new
|
|
19303
|
-
* subject, or a name confirmed on one already in it) REPLACES that
|
|
19304
|
-
* notification with an updated one naming everybody. The push carries the
|
|
19305
|
-
* group's own coalescing tag, so the phone replaces rather than stacks.
|
|
19306
|
-
*
|
|
19307
|
-
* `0` / absent = off, and off is today's behaviour byte for byte.
|
|
19308
|
-
*
|
|
19309
|
-
* ### Why an idle cutoff and not a window
|
|
19310
|
-
*
|
|
19311
|
-
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
19312
|
-
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
19313
|
-
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
19314
|
-
* 30 s is a widely shipped value for the same decision.
|
|
19315
|
-
*
|
|
19316
|
-
* ### What it replaces
|
|
19317
|
-
*
|
|
19318
|
-
* The blind cooldown, which collapses a burst by DISCARDING it. Measured on
|
|
19319
|
-
* device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
|
|
19320
|
-
* notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
|
|
19321
|
-
* track that did fire and 7 carrying a confirmed identity nobody heard about.
|
|
19322
|
-
* A group collapses the same volume by MERGING, so the cooldown becomes a
|
|
19323
|
-
* budget over GROUPS — which is what it always meant — and a growth is never
|
|
19324
|
-
* throttled by the window its own first member spent.
|
|
19325
|
-
*
|
|
19326
|
-
* ### Interaction with {@link waitForEnhancement}
|
|
19327
|
-
*
|
|
19328
|
-
* They compose, and the order matters. `waitForEnhancement` defers the rule to
|
|
19329
|
-
* TRACK CLOSE, so with both set the group is opened by the first member to
|
|
19330
|
-
* CLOSE — already carrying its name — and grows as later members close. That
|
|
19331
|
-
* is later, and complete. With grouping alone the group opens on the first
|
|
19332
|
-
* object event and picks up names as they are confirmed, through the growth
|
|
19333
|
-
* path. Neither combination fires twice for one subject.
|
|
19334
|
-
*
|
|
19335
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19336
|
-
* on the addon cap path, so absent must keep meaning what it meant before this
|
|
19337
|
-
* field existed.
|
|
19679
|
+
* IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
|
|
19680
|
+
* seconds; the rule sends ONE message when the window closes — early, once every
|
|
19681
|
+
* subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
|
|
19682
|
+
* the rule matched, with one mosaic tile per subject.
|
|
19683
|
+
* Absent = plain immediate (one message per track, at the first match).
|
|
19684
|
+
* Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
|
|
19685
|
+
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
19686
|
+
* path does not run Zod defaults.
|
|
19338
19687
|
*/
|
|
19339
|
-
|
|
19688
|
+
groupingSec: number().int().min(5).max(60).optional()
|
|
19340
19689
|
});
|
|
19341
19690
|
/**
|
|
19342
19691
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -19384,9 +19733,10 @@ var NcRuleClearableKeySchema = _enum([
|
|
|
19384
19733
|
"targetUsers",
|
|
19385
19734
|
"snoozeOptions",
|
|
19386
19735
|
"snoozeAllowGlobal",
|
|
19387
|
-
"waitForEnhancement",
|
|
19388
19736
|
"actions",
|
|
19389
19737
|
"confirm",
|
|
19738
|
+
"groupingSec",
|
|
19739
|
+
"waitForEnhancement",
|
|
19390
19740
|
"groupIdleSec"
|
|
19391
19741
|
]);
|
|
19392
19742
|
var NcRuleUpdateInputSchema = object({
|
|
@@ -19408,19 +19758,47 @@ var NcRuleSchema = NcRuleInputSchema.extend({
|
|
|
19408
19758
|
*/
|
|
19409
19759
|
disabledTargetIds: array(string$2()).default([])
|
|
19410
19760
|
});
|
|
19761
|
+
/**
|
|
19762
|
+
* The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
|
|
19763
|
+
* still-true state. `backups-exports` and `alarm` are not sections — a completed
|
|
19764
|
+
* job is not an open state, and the alarm stays instant.
|
|
19765
|
+
*/
|
|
19766
|
+
var NcStateSummarySectionIdSchema = _enum([
|
|
19767
|
+
"device-state",
|
|
19768
|
+
"streams",
|
|
19769
|
+
"battery",
|
|
19770
|
+
"consumables",
|
|
19771
|
+
"tanks",
|
|
19772
|
+
"detection-blind",
|
|
19773
|
+
"nodes",
|
|
19774
|
+
"addons",
|
|
19775
|
+
"updates"
|
|
19776
|
+
]);
|
|
19411
19777
|
/** One section of a previewed state summary. `unavailable` = its state could not be read. */
|
|
19412
19778
|
var NcStateSummaryPreviewSectionSchema = object({
|
|
19413
|
-
id:
|
|
19779
|
+
id: NcStateSummarySectionIdSchema,
|
|
19414
19780
|
status: _enum(["read", "unavailable"]),
|
|
19415
19781
|
items: number().int().nonnegative(),
|
|
19416
19782
|
reason: string$2().optional()
|
|
19417
19783
|
});
|
|
19418
19784
|
/**
|
|
19785
|
+
* One notification a previewed summary would send (D698): the whole summary on
|
|
19786
|
+
* a `rule` split (no `section`), one section's on a `section` split.
|
|
19787
|
+
*/
|
|
19788
|
+
var NcStateSummaryPreviewRowSchema = object({
|
|
19789
|
+
section: NcStateSummarySectionIdSchema.optional(),
|
|
19790
|
+
/** The section's name on a per-section row; every reported section's, joined, on a combined one. */
|
|
19791
|
+
title: string$2(),
|
|
19792
|
+
text: string$2(),
|
|
19793
|
+
count: number().int().nonnegative()
|
|
19794
|
+
});
|
|
19795
|
+
/**
|
|
19419
19796
|
* The summary a rule would send now. `empty` = nothing to report and every
|
|
19420
19797
|
* section read: such a summary is NOT sent. `dropped` counts the open states
|
|
19421
19798
|
* the rule's own filters (or a camera mute) left out, by reason.
|
|
19422
19799
|
* `excludedGroups` names the kind groups selected that have no state to report
|
|
19423
|
-
* (backups & exports).
|
|
19800
|
+
* (backups & exports). `split` and `rows` (D698) say how it would be sent —
|
|
19801
|
+
* optional, so an older hub's answer still parses.
|
|
19424
19802
|
*/
|
|
19425
19803
|
var NcStateSummaryPreviewSchema = object({
|
|
19426
19804
|
empty: boolean(),
|
|
@@ -19428,7 +19806,9 @@ var NcStateSummaryPreviewSchema = object({
|
|
|
19428
19806
|
text: string$2(),
|
|
19429
19807
|
sections: array(NcStateSummaryPreviewSectionSchema),
|
|
19430
19808
|
dropped: record(string$2(), number().int().nonnegative()),
|
|
19431
|
-
excludedGroups: array(string$2())
|
|
19809
|
+
excludedGroups: array(string$2()),
|
|
19810
|
+
split: NcStateSummarySplitSchema.optional(),
|
|
19811
|
+
rows: array(NcStateSummaryPreviewRowSchema).optional()
|
|
19432
19812
|
});
|
|
19433
19813
|
var NcTestResultSchema = object({
|
|
19434
19814
|
recordId: string$2(),
|
|
@@ -19843,6 +20223,29 @@ object({
|
|
|
19843
20223
|
firstAt: number(),
|
|
19844
20224
|
lastAt: number()
|
|
19845
20225
|
});
|
|
20226
|
+
var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
|
|
20227
|
+
var NcAlarmDelaySecSchema = number().int().min(0).max(600);
|
|
20228
|
+
var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
|
|
20229
|
+
var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
|
|
20230
|
+
var NcAlarmModeDelaysListSchema = array(object({
|
|
20231
|
+
mode: AlarmArmModeSchema,
|
|
20232
|
+
exitDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20233
|
+
entryDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20234
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
|
|
20235
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
20236
|
+
var NcAlarmModeDelaysEditListSchema = array(object({
|
|
20237
|
+
mode: AlarmArmModeSchema,
|
|
20238
|
+
exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20239
|
+
entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20240
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
|
|
20241
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
20242
|
+
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
20243
|
+
var NcAlarmNonBlockingEditSchema = object({
|
|
20244
|
+
mode: AlarmArmModeSchema,
|
|
20245
|
+
deviceId: number().int().positive(),
|
|
20246
|
+
/** true = on the list (may be open, does not block); false = off the list (blocks). */
|
|
20247
|
+
nonBlocking: boolean()
|
|
20248
|
+
});
|
|
19846
20249
|
/**
|
|
19847
20250
|
* The per-mode lists, at most one per mode. Two lists for one mode have no
|
|
19848
20251
|
* meaning a reader could agree on (union? the last one?), so they are refused
|
|
@@ -19851,10 +20254,10 @@ object({
|
|
|
19851
20254
|
var NcAlarmNonBlockingListSchema = array(object({
|
|
19852
20255
|
mode: AlarmArmModeSchema,
|
|
19853
20256
|
deviceIds: array(number().int()).max(200)
|
|
19854
|
-
})).max(8).refine(
|
|
20257
|
+
})).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
|
|
19855
20258
|
/**
|
|
19856
|
-
* The three durations
|
|
19857
|
-
* transitions, and which openings each mode tolerates.
|
|
20259
|
+
* The three durations — global, and per mode since D697 — the panel's state
|
|
20260
|
+
* machine runs on, who hears about its transitions, and which openings each mode tolerates.
|
|
19858
20261
|
*
|
|
19859
20262
|
* They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
|
|
19860
20263
|
* `alarm-panel` is `deviceNative` and its other provider mirrors somebody
|
|
@@ -19864,15 +20267,15 @@ var NcAlarmNonBlockingListSchema = array(object({
|
|
|
19864
20267
|
*/
|
|
19865
20268
|
var NcAlarmSettingsSchema = object({
|
|
19866
20269
|
/** Grace period between arming and the mode taking effect. 0 = immediate. */
|
|
19867
|
-
exitDelaySec:
|
|
20270
|
+
exitDelaySec: NcAlarmDelaySecSchema,
|
|
19868
20271
|
/** Grace period between a trigger and the alarm firing. 0 = immediate. */
|
|
19869
|
-
entryDelaySec:
|
|
20272
|
+
entryDelaySec: NcAlarmDelaySecSchema,
|
|
19870
20273
|
/**
|
|
19871
20274
|
* How long `triggered` lasts before the panel re-arms itself.
|
|
19872
20275
|
* **0 = until an operator disarms it** — the behaviour before this field
|
|
19873
20276
|
* existed, and therefore what an untouched install keeps doing.
|
|
19874
20277
|
*/
|
|
19875
|
-
triggeredDurationSec:
|
|
20278
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema,
|
|
19876
20279
|
/**
|
|
19877
20280
|
* Deprecated by D630 — every transition is announced. Parsed, never read;
|
|
19878
20281
|
* remove after one release. Optional so an older admin's patch (which still
|
|
@@ -19895,17 +20298,30 @@ var NcAlarmSettingsSchema = object({
|
|
|
19895
20298
|
* per mode is meaningful. Defaulted to `[]` so a blob stored before D630
|
|
19896
20299
|
* parses as "every opening blocks" — the behaviour it was written under.
|
|
19897
20300
|
*/
|
|
19898
|
-
nonBlocking: NcAlarmNonBlockingListSchema.default([])
|
|
20301
|
+
nonBlocking: NcAlarmNonBlockingListSchema.default([]),
|
|
20302
|
+
/**
|
|
20303
|
+
* Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
|
|
20304
|
+
* without a field, uses the global value above — so `[]`, the default, is exactly the
|
|
20305
|
+
* behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
|
|
20306
|
+
*/
|
|
20307
|
+
modeDelays: NcAlarmModeDelaysListSchema.default([])
|
|
19899
20308
|
});
|
|
19900
20309
|
/**
|
|
19901
20310
|
* Every field optional — a tab edits one control at a time.
|
|
19902
20311
|
*
|
|
19903
|
-
* `nonBlocking`
|
|
19904
|
-
* remove an inner `.default()`, so a patch that never
|
|
19905
|
-
* parse to `
|
|
19906
|
-
* (the same trap {@link NcRulePatchSchema} documents).
|
|
20312
|
+
* `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
|
|
20313
|
+
* `.partial()` does not remove an inner `.default()`, so a patch that never
|
|
20314
|
+
* named the field would parse to `[]` and wipe every mode's list on an
|
|
20315
|
+
* unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
|
|
20316
|
+
* `modeDelays` means EDITS, not the stored overrides.
|
|
19907
20317
|
*/
|
|
19908
|
-
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20318
|
+
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20319
|
+
nonBlocking: NcAlarmNonBlockingListSchema,
|
|
20320
|
+
/** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
|
|
20321
|
+
modeDelays: NcAlarmModeDelaysEditListSchema,
|
|
20322
|
+
/** ONE membership change; the panel applies it to the list it holds at its turn. */
|
|
20323
|
+
nonBlockingEdit: NcAlarmNonBlockingEditSchema
|
|
20324
|
+
}).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
|
|
19909
20325
|
/**
|
|
19910
20326
|
* What one arm mode actually arms, DERIVED from the enabled rules gated on it.
|
|
19911
20327
|
* Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
|
|
@@ -20005,6 +20421,28 @@ var NcAlarmConfigSchema = object({
|
|
|
20005
20421
|
*/
|
|
20006
20422
|
live: NcAlarmLiveSchema.optional()
|
|
20007
20423
|
});
|
|
20424
|
+
var NcAlarmSensorReadingSchema = _enum([
|
|
20425
|
+
"open",
|
|
20426
|
+
"closed",
|
|
20427
|
+
"unknown",
|
|
20428
|
+
"not-opening"
|
|
20429
|
+
]);
|
|
20430
|
+
/** One device's state as the alarm reads it — the classifier the arm check uses. */
|
|
20431
|
+
var NcAlarmSensorStateSchema = object({
|
|
20432
|
+
deviceId: number().int().positive(),
|
|
20433
|
+
reading: NcAlarmSensorReadingSchema,
|
|
20434
|
+
/** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
|
|
20435
|
+
state: string$2().nullable(),
|
|
20436
|
+
/** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
|
|
20437
|
+
unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
|
|
20438
|
+
/** The device manager's liveness as the centre mirrors it; null = not known. */
|
|
20439
|
+
online: boolean().nullable()
|
|
20440
|
+
});
|
|
20441
|
+
var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
|
|
20442
|
+
var NcAlarmSensorsSchema = object({
|
|
20443
|
+
sensors: array(NcAlarmSensorStateSchema),
|
|
20444
|
+
readAt: number().int().nonnegative()
|
|
20445
|
+
});
|
|
20008
20446
|
/**
|
|
20009
20447
|
* ONE rule's demand on ONE camera's clip ring.
|
|
20010
20448
|
*
|
|
@@ -20095,7 +20533,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
|
|
|
20095
20533
|
}), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
|
|
20096
20534
|
kind: "mutation",
|
|
20097
20535
|
auth: "admin"
|
|
20098
|
-
});
|
|
20536
|
+
}), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
|
|
20099
20537
|
/**
|
|
20100
20538
|
* Zod schemas for persisted record types.
|
|
20101
20539
|
*
|
|
@@ -20442,12 +20880,26 @@ var CameraSensorRefSchema = object({
|
|
|
20442
20880
|
function cameraSensorRefKey(ref) {
|
|
20443
20881
|
return `${ref.addonId}/${ref.stableId}`;
|
|
20444
20882
|
}
|
|
20445
|
-
/**
|
|
20446
|
-
|
|
20447
|
-
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20883
|
+
/**
|
|
20884
|
+
* A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
|
|
20885
|
+
* `replace`: its motion is the camera's, and while one is READY the camera's
|
|
20886
|
+
* own motion no longer counts on its own. `confirm`: while one is READY the
|
|
20887
|
+
* camera's own motion counts only while a confirm sensor is active — with or
|
|
20888
|
+
* without a replace sensor (spec C2, the controller's ruling on Q1).
|
|
20889
|
+
*/
|
|
20890
|
+
var CameraSensorModeSchema = _enum([
|
|
20891
|
+
"in-addition",
|
|
20892
|
+
"confirm",
|
|
20893
|
+
"replace"
|
|
20894
|
+
]);
|
|
20895
|
+
/** A stored sensor with no mode — every CS-1 row — is in addition. */
|
|
20896
|
+
var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
|
|
20897
|
+
/**
|
|
20898
|
+
* A camera's attached sensors. A CS-1 row carried an envelope
|
|
20899
|
+
* `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
|
|
20900
|
+
* what the write stores (D672 rule 3), so it is never written again.
|
|
20901
|
+
*/
|
|
20902
|
+
var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
|
|
20451
20903
|
const seen = /* @__PURE__ */ new Set();
|
|
20452
20904
|
value.sensors.forEach((ref, index) => {
|
|
20453
20905
|
const key = cameraSensorRefKey(ref);
|
|
@@ -20459,39 +20911,41 @@ object({
|
|
|
20459
20911
|
seen.add(key);
|
|
20460
20912
|
});
|
|
20461
20913
|
});
|
|
20462
|
-
|
|
20914
|
+
/** Every attachment names its mode; an older orchestrator that does not is in addition. */
|
|
20915
|
+
var AttachmentFields = {
|
|
20463
20916
|
addonId: string$2(),
|
|
20464
|
-
stableId: string$2()
|
|
20917
|
+
stableId: string$2(),
|
|
20918
|
+
mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
|
|
20465
20919
|
};
|
|
20466
20920
|
var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
20467
20921
|
object({
|
|
20468
|
-
...
|
|
20922
|
+
...AttachmentFields,
|
|
20469
20923
|
state: literal("ready"),
|
|
20470
20924
|
deviceId: number(),
|
|
20471
20925
|
name: string$2(),
|
|
20472
20926
|
caps: array(string$2()).readonly()
|
|
20473
20927
|
}),
|
|
20474
20928
|
object({
|
|
20475
|
-
...
|
|
20929
|
+
...AttachmentFields,
|
|
20476
20930
|
state: literal("offline"),
|
|
20477
20931
|
deviceId: number(),
|
|
20478
20932
|
name: string$2(),
|
|
20479
20933
|
reason: _enum(["offline", "disabled"])
|
|
20480
20934
|
}),
|
|
20481
20935
|
object({
|
|
20482
|
-
...
|
|
20936
|
+
...AttachmentFields,
|
|
20483
20937
|
state: literal("missing"),
|
|
20484
20938
|
reason: string$2()
|
|
20485
20939
|
}),
|
|
20486
20940
|
object({
|
|
20487
|
-
...
|
|
20941
|
+
...AttachmentFields,
|
|
20488
20942
|
state: literal("unsupported"),
|
|
20489
20943
|
deviceId: number(),
|
|
20490
20944
|
name: string$2(),
|
|
20491
20945
|
reason: string$2()
|
|
20492
20946
|
}),
|
|
20493
20947
|
object({
|
|
20494
|
-
...
|
|
20948
|
+
...AttachmentFields,
|
|
20495
20949
|
state: literal("unreadable"),
|
|
20496
20950
|
reason: string$2()
|
|
20497
20951
|
})
|
|
@@ -20504,17 +20958,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
|
20504
20958
|
* say.
|
|
20505
20959
|
*/
|
|
20506
20960
|
var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
|
|
20961
|
+
/** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
|
|
20962
|
+
var CameraOwnMotionSchema = _enum([
|
|
20963
|
+
"always",
|
|
20964
|
+
"when-confirmed",
|
|
20965
|
+
"never"
|
|
20966
|
+
]);
|
|
20967
|
+
/** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
|
|
20968
|
+
var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
|
|
20969
|
+
/**
|
|
20970
|
+
* The camera's OWN onboard motion (D696): the raw input the bridge combines,
|
|
20971
|
+
* never the effective value. The camera's `motion` slice is the effective one,
|
|
20972
|
+
* so a view of the camera's own row reads this.
|
|
20973
|
+
* - `atMs`: when the bridge received the camera's last own edge.
|
|
20974
|
+
* - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
|
|
20975
|
+
* AND it is younger than the window the bridge counts the camera's own motion
|
|
20976
|
+
* for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
|
|
20977
|
+
* sends a clear (heartbeats only) therefore reads `false` once no push came
|
|
20978
|
+
* within the window; a status read is a snapshot, so a live view re-asks.
|
|
20979
|
+
* Absent = this orchestrator has not received the camera's own motion since it
|
|
20980
|
+
* started (unknown, never "quiet"), or an orchestrator older than D696.
|
|
20981
|
+
*/
|
|
20982
|
+
var CameraRawLevelSchema = object({
|
|
20983
|
+
detected: boolean(),
|
|
20984
|
+
atMs: number()
|
|
20985
|
+
});
|
|
20507
20986
|
var CameraSensorsStatusSchema = discriminatedUnion("state", [
|
|
20508
|
-
object({
|
|
20987
|
+
object({
|
|
20988
|
+
state: literal("not-configured"),
|
|
20989
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20990
|
+
}),
|
|
20509
20991
|
object({
|
|
20510
20992
|
state: literal("unreadable"),
|
|
20511
|
-
reason: string$2()
|
|
20993
|
+
reason: string$2(),
|
|
20994
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20512
20995
|
}),
|
|
20513
20996
|
object({
|
|
20514
20997
|
state: literal("configured"),
|
|
20515
|
-
|
|
20998
|
+
cameraLevel: CameraRawLevelSchema.optional(),
|
|
20516
20999
|
sensors: array(CameraSensorAttachmentSchema).readonly(),
|
|
20517
|
-
|
|
21000
|
+
/** Absent = an orchestrator older than CS-2: it does not say (D315). */
|
|
21001
|
+
cameraMotion: CameraOwnMotionSchema.optional(),
|
|
21002
|
+
notForwarded: CameraSensorsNotForwardedSchema.optional(),
|
|
21003
|
+
notEnforced: CameraSensorsNotEnforcedSchema.optional()
|
|
20518
21004
|
})
|
|
20519
21005
|
]);
|
|
20520
21006
|
Object.freeze({
|
|
@@ -21199,14 +21685,14 @@ var TrackSchema = object({
|
|
|
21199
21685
|
* `derive-returned-null tile=standin`,
|
|
21200
21686
|
* `native-tile tile=native no-key-frame-at-close`, …) written at close and
|
|
21201
21687
|
* CLEARED by the late-keyFrame upgrade when a native tile lands after all.
|
|
21202
|
-
* The operator-facing answer to "perché manca l'immagine?" on a track whose
|
|
21688
|
+
* The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
|
|
21203
21689
|
* tile is a face/plate stand-in, a raster crop, or an icon.
|
|
21204
21690
|
*
|
|
21205
21691
|
* **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
|
|
21206
21692
|
* the TILE ranked below native, so a track whose thumbnail landed natively
|
|
21207
21693
|
* while its key frame missed carried no reason at all — three of the four
|
|
21208
21694
|
* `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
|
|
21209
|
-
* that shape, and their "niente ultimo" had no cause anywhere on the row.
|
|
21695
|
+
* that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
|
|
21210
21696
|
* The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
|
|
21211
21697
|
* lastFrame copy source`), so its absence is now on this line whatever the
|
|
21212
21698
|
* tile ended up being.
|
|
@@ -21293,7 +21779,7 @@ var MotionEventSchema = object({
|
|
|
21293
21779
|
/**
|
|
21294
21780
|
* Ms offsets from `timestamp` (the episode's own first rising edge, so the
|
|
21295
21781
|
* first entry is always `0`) of every genuine off→on transition the
|
|
21296
|
-
* episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
|
|
21782
|
+
* episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
|
|
21297
21783
|
* push: a firmware source that keepalives at ~1 Hz for the whole burst
|
|
21298
21784
|
* (Reolink, Hikvision) produces exactly one edge; a source that reports an
|
|
21299
21785
|
* explicit `false` mid-episode and then resumes before the quiet window
|
|
@@ -21817,6 +22303,7 @@ var KeyEventSchema = object({
|
|
|
21817
22303
|
bestEventId: string$2(),
|
|
21818
22304
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
21819
22305
|
windowMs: number().optional(),
|
|
22306
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
21820
22307
|
...TrackFlagFields,
|
|
21821
22308
|
...TrackRetrainFields
|
|
21822
22309
|
});
|
|
@@ -22349,7 +22836,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
22349
22836
|
trackIds: array(string$2()).min(1)
|
|
22350
22837
|
}), object({
|
|
22351
22838
|
deleted: number().int(),
|
|
22352
|
-
failed: array(string$2()).readonly()
|
|
22839
|
+
failed: array(string$2()).readonly(),
|
|
22840
|
+
sparedMediaIds: array(number().int()).readonly().optional()
|
|
22353
22841
|
}), {
|
|
22354
22842
|
kind: "mutation",
|
|
22355
22843
|
auth: "admin"
|
|
@@ -22358,7 +22846,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
22358
22846
|
deviceId: number(),
|
|
22359
22847
|
trackId: string$2(),
|
|
22360
22848
|
flags: TrackFlagsPatchSchema
|
|
22361
|
-
}), TrackFlagsSchema, { kind: "mutation" }), method(ArchivedDebugNoteQueryInputSchema, array(ArchivedDebugNoteSchema).readonly(), { kind: "query" }), method(BirthDecisionQueryInputSchema, array(BirthDecisionRecordSchema).readonly(), { kind: "query" }), method(object({}), EventStoreFootprintSchema, {
|
|
22849
|
+
}), TrackFlagsSchema, { kind: "mutation" }), method(ArchivedDebugNoteQueryInputSchema, array(ArchivedDebugNoteSchema).readonly(), { kind: "query" }), method(SetTrackRelationInputSchema, TrackRelationSchema, { kind: "mutation" }), method(ClearTrackRelationInputSchema, ClearTrackRelationResultSchema, { kind: "mutation" }), method(SetTrackPurityInputSchema, SetTrackPurityResultSchema, { kind: "mutation" }), method(ListTrackRelationsInputSchema, ListTrackRelationsResultSchema, { kind: "query" }), method(BirthDecisionQueryInputSchema, array(BirthDecisionRecordSchema).readonly(), { kind: "query" }), method(object({}), EventStoreFootprintSchema, {
|
|
22362
22850
|
kind: "query",
|
|
22363
22851
|
auth: "admin"
|
|
22364
22852
|
}), method(object({ deviceId: number().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
@@ -23744,8 +24232,10 @@ var RunnerCameraConfigSchema = object({
|
|
|
23744
24232
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
23745
24233
|
* analyzer providers) running on decoded frames in this runner.
|
|
23746
24234
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
23747
|
-
* analytics). The provider emits ProviderMotion
|
|
23748
|
-
*
|
|
24235
|
+
* analytics). The provider emits its raw push as `ProviderMotion`
|
|
24236
|
+
* (D673); the orchestrator's camera-sensors bridge re-emits the camera's
|
|
24237
|
+
* effective motion as `MotionOnMotionChanged`, which is what reaches
|
|
24238
|
+
* `reportMotion`.
|
|
23749
24239
|
*/
|
|
23750
24240
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
23751
24241
|
/**
|
|
@@ -23922,7 +24412,15 @@ var RunnerLocalLoadSchema = object({
|
|
|
23922
24412
|
hasGpu: boolean(),
|
|
23923
24413
|
inferenceBackend: string$2().optional(),
|
|
23924
24414
|
cpuCores: number().optional()
|
|
23925
|
-
})
|
|
24415
|
+
}),
|
|
24416
|
+
/**
|
|
24417
|
+
* Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
|
|
24418
|
+
* runner never writes it. ABSENT = a runner older than D696, which still
|
|
24419
|
+
* writes the slice from its phase machine; the orchestrator does not write
|
|
24420
|
+
* while any runner node is absent-or-unanswered, so one slice never has two
|
|
24421
|
+
* writers.
|
|
24422
|
+
*/
|
|
24423
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
23926
24424
|
});
|
|
23927
24425
|
/**
|
|
23928
24426
|
* Aggregate runtime metrics for the runner's whole local pool. Mirrors the
|
|
@@ -24556,7 +25054,64 @@ var NodeInferenceDevicesSchema = object({
|
|
|
24556
25054
|
reachable: boolean(),
|
|
24557
25055
|
devices: array(NodeInferenceDeviceSchema).readonly()
|
|
24558
25056
|
});
|
|
24559
|
-
|
|
25057
|
+
/**
|
|
25058
|
+
* Pipeline Orchestrator capability — global load balancer + camera dispatcher.
|
|
25059
|
+
*
|
|
25060
|
+
* Lives on the hub. Tracks the camera-to-agent assignment map, listens to
|
|
25061
|
+
* device lifecycle events, queries each runner's capacity + hardware
|
|
25062
|
+
* profile, and dispatches `attachCamera` / `detachCamera` cap calls to the
|
|
25063
|
+
* appropriate runner instances. Persists assignments via the multi-level
|
|
25064
|
+
* settings store so they survive hub restarts.
|
|
25065
|
+
*
|
|
25066
|
+
* Strictly the control plane: never sees a frame, never calls inference,
|
|
25067
|
+
* never drains queues. The runner does that work locally on each agent.
|
|
25068
|
+
*/
|
|
25069
|
+
/**
|
|
25070
|
+
* The input of `setCameraSensors` (G5, D676): the ONE typed write path of a
|
|
25071
|
+
* camera's attached sensors (D672). `config: null` removes the attachment —
|
|
25072
|
+
* the camera reads `not-configured` again, never `unreadable`.
|
|
25073
|
+
*/
|
|
25074
|
+
var SetCameraSensorsInputSchema = object({
|
|
25075
|
+
deviceId: number().int().nonnegative(),
|
|
25076
|
+
/** `null` removes the attachment: the camera goes back to `not-configured`. */
|
|
25077
|
+
config: CameraSensorsConfigSchema.nullable()
|
|
25078
|
+
});
|
|
25079
|
+
/**
|
|
25080
|
+
* Why an early occupancy look (D691) was not scheduled.
|
|
25081
|
+
*
|
|
25082
|
+
* - `unknown-camera` — no session was ever dispatched for it, so there is no
|
|
25083
|
+
* node and no config to attach a burst with.
|
|
25084
|
+
* - `out-of-range` — the ask is negative or further out than the orchestrator
|
|
25085
|
+
* will hold a timer for; the parked-object cadence is the answer there.
|
|
25086
|
+
* - `no-burst-producer` — this build has no burst producer at all.
|
|
25087
|
+
* - `already-looked` — this camera's ONE early look since its last session has
|
|
25088
|
+
* been spent. A look's own burst can re-arm a flickering flip, and a look
|
|
25089
|
+
* per arm would chain a burst every ~30 s forever (review H2); the next
|
|
25090
|
+
* real session re-arms the budget.
|
|
25091
|
+
*/
|
|
25092
|
+
var OccupancyLookRefusalSchema = _enum([
|
|
25093
|
+
"unknown-camera",
|
|
25094
|
+
"out-of-range",
|
|
25095
|
+
"no-burst-producer",
|
|
25096
|
+
"already-looked"
|
|
25097
|
+
]);
|
|
25098
|
+
method(object({
|
|
25099
|
+
deviceId: number().int().nonnegative(),
|
|
25100
|
+
/** How long from NOW until the pending flip's sustain window ends. RELATIVE,
|
|
25101
|
+
* so the caller's clock and the orchestrator's never have to agree. */
|
|
25102
|
+
afterMs: number().finite(),
|
|
25103
|
+
/** Why, for the log. */
|
|
25104
|
+
reason: string$2()
|
|
25105
|
+
}), object({
|
|
25106
|
+
scheduled: boolean(),
|
|
25107
|
+
/** When `scheduled`: how long until the burst is dialled. */
|
|
25108
|
+
dueInMs: number().optional(),
|
|
25109
|
+
/** When not `scheduled`: why. */
|
|
25110
|
+
refusedBecause: OccupancyLookRefusalSchema.optional()
|
|
25111
|
+
}), {
|
|
25112
|
+
kind: "mutation",
|
|
25113
|
+
auth: "admin"
|
|
25114
|
+
}), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
24560
25115
|
kind: "mutation",
|
|
24561
25116
|
auth: "admin"
|
|
24562
25117
|
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
@@ -24710,7 +25265,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
|
24710
25265
|
}), CameraSwitchGroupSchema, {
|
|
24711
25266
|
kind: "mutation",
|
|
24712
25267
|
auth: "admin"
|
|
24713
|
-
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(
|
|
25268
|
+
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(SetCameraSensorsInputSchema, object({ success: literal(true) }), {
|
|
25269
|
+
kind: "mutation",
|
|
25270
|
+
auth: "admin"
|
|
25271
|
+
}), method(_void(), DiskReconcileJobSchema, {
|
|
24714
25272
|
kind: "mutation",
|
|
24715
25273
|
auth: "admin"
|
|
24716
25274
|
}), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
|
|
@@ -26527,7 +27085,7 @@ var ClipPlaybackSchema = object({
|
|
|
26527
27085
|
* **One authorised yes is one wake.** `next-natural` — take the clip the next
|
|
26528
27086
|
* time the camera is awake for its own reasons — is deliberately not a member:
|
|
26529
27087
|
* it was proposed, it is free on the battery, and the operator declined it on
|
|
26530
|
-
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."
|
|
27088
|
+
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
|
|
26531
27089
|
* D558 "Considered and not taken").
|
|
26532
27090
|
*/
|
|
26533
27091
|
var ClipWakeSchema = _enum(["authorised"]);
|
|
@@ -26788,7 +27346,7 @@ DeviceType.Camera, method(object({
|
|
|
26788
27346
|
* It replaced `sources?: string[]`, a VIEW filter over source ids that
|
|
26789
27347
|
* assumed the answer was a fan-out over everything a camera has. The
|
|
26790
27348
|
* operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
|
|
26791
|
-
* solo"* — so the list is asked of one provider at a time and there is
|
|
27349
|
+
* solo"* [there is only one user] — so the list is asked of one provider at a time and there is
|
|
26792
27350
|
* nothing to filter out of it.
|
|
26793
27351
|
*/
|
|
26794
27352
|
provider: string$2().min(1)
|
|
@@ -26916,219 +27474,6 @@ DeviceType.Camera, method(object({
|
|
|
26916
27474
|
auth: "protected"
|
|
26917
27475
|
});
|
|
26918
27476
|
/**
|
|
26919
|
-
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
26920
|
-
* name (same pattern as `snapshot`):
|
|
26921
|
-
*
|
|
26922
|
-
* - **Native** providers: registered per-device by device-driver
|
|
26923
|
-
* addons via `ctx.registerNativeCap` — either on a
|
|
26924
|
-
* `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
|
|
26925
|
-
* or directly on the camera (Reolink registers at camera level).
|
|
26926
|
-
* Emits an `onPressed` event every time the firmware pushes a
|
|
26927
|
-
* ring; status tracks the last press and a pressCount since start
|
|
26928
|
-
* (diagnostic).
|
|
26929
|
-
*
|
|
26930
|
-
* - **Wrapper** provider: the `virtual-doorbell` system builtin
|
|
26931
|
-
* (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
|
|
26932
|
-
* device (contact / switch / event-emitter …) into a doorbell for
|
|
26933
|
-
* a camera. `defaultActive: false` — the operator explicitly binds
|
|
26934
|
-
* it per camera in the device-bindings UI, then picks the source
|
|
26935
|
-
* device + trigger in the per-device settings.
|
|
26936
|
-
*
|
|
26937
|
-
* The DeviceEventPropagator re-emits `onPressed` on the camera parent
|
|
26938
|
-
* — subscribers listening at the camera level receive ring events
|
|
26939
|
-
* with `via[]` populated. No code on the parent needed.
|
|
26940
|
-
*/
|
|
26941
|
-
var DoorbellStatusSchema = object({
|
|
26942
|
-
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
26943
|
-
lastPressedAt: number().nullable(),
|
|
26944
|
-
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
26945
|
-
pressCountSinceStart: number()
|
|
26946
|
-
});
|
|
26947
|
-
var DoorbellPressEventSchema = object({
|
|
26948
|
-
deviceId: number(),
|
|
26949
|
-
timestamp: number()
|
|
26950
|
-
});
|
|
26951
|
-
/**
|
|
26952
|
-
* The `doorbell-source` extension slot's editable value (D648): the camera's
|
|
26953
|
-
* virtual-doorbell trigger devices, exactly what the wrapper's
|
|
26954
|
-
* `doorbellSources` persists (as `{ deviceId }` records).
|
|
26955
|
-
*/
|
|
26956
|
-
var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
|
|
26957
|
-
/**
|
|
26958
|
-
* The `doorbell-source` slot — which devices ring this camera's VIRTUAL
|
|
26959
|
-
* doorbell, owned by the `virtual-doorbell` wrapper over its
|
|
26960
|
-
* `doorbellSources` store (D648). A source rings when one of its
|
|
26961
|
-
* `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
|
|
26962
|
-
* different authority (`deviceManager.setWrapperActive`, D62) — the slot
|
|
26963
|
-
* reports it, it never writes it.
|
|
26964
|
-
*/
|
|
26965
|
-
var DOORBELL_SOURCE_SLOT = {
|
|
26966
|
-
id: "doorbell-source",
|
|
26967
|
-
label: "Doorbell trigger devices",
|
|
26968
|
-
description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
|
|
26969
|
-
shape: "association",
|
|
26970
|
-
hostDeviceTypes: [DeviceType.Camera],
|
|
26971
|
-
sourceCaps: SOURCE_CAPS,
|
|
26972
|
-
cardinality: "many",
|
|
26973
|
-
value: DoorbellSourceSlotValueSchema
|
|
26974
|
-
};
|
|
26975
|
-
var doorbellCapability = {
|
|
26976
|
-
name: "doorbell",
|
|
26977
|
-
scope: "device",
|
|
26978
|
-
deviceNative: true,
|
|
26979
|
-
mode: "singleton",
|
|
26980
|
-
kind: "wrapper",
|
|
26981
|
-
defaultActive: false,
|
|
26982
|
-
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
26983
|
-
extensionSlots: [DOORBELL_SOURCE_SLOT],
|
|
26984
|
-
methods: {},
|
|
26985
|
-
events: {
|
|
26986
|
-
/**
|
|
26987
|
-
* Fires once per physical press. Reolink delivers via Baichuan
|
|
26988
|
-
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
26989
|
-
* release/duration — it's a pulse.
|
|
26990
|
-
*/
|
|
26991
|
-
onPressed: {
|
|
26992
|
-
data: DoorbellPressEventSchema,
|
|
26993
|
-
fromState: {
|
|
26994
|
-
field: "lastPressedAt",
|
|
26995
|
-
on: "advance"
|
|
26996
|
-
}
|
|
26997
|
-
} },
|
|
26998
|
-
status: {
|
|
26999
|
-
schema: DoorbellStatusSchema,
|
|
27000
|
-
kind: "push"
|
|
27001
|
-
},
|
|
27002
|
-
/**
|
|
27003
|
-
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
27004
|
-
* Mirrored by the kernel and readable via
|
|
27005
|
-
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
27006
|
-
* without subscribing.
|
|
27007
|
-
*/
|
|
27008
|
-
runtimeState: DoorbellStatusSchema,
|
|
27009
|
-
/**
|
|
27010
|
-
* Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
|
|
27011
|
-
*
|
|
27012
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
27013
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
27014
|
-
*/
|
|
27015
|
-
durability: "restored"
|
|
27016
|
-
};
|
|
27017
|
-
var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
|
|
27018
|
-
DeviceType.Camera, DeviceType.Camera;
|
|
27019
|
-
/** A slot's editable value, discriminated on `slot`. */
|
|
27020
|
-
var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
27021
|
-
DeviceType.Camera;
|
|
27022
|
-
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
27023
|
-
state: literal("unreachable"),
|
|
27024
|
-
reason: string$2()
|
|
27025
|
-
})]);
|
|
27026
|
-
/** One provider of slots — the D554 source-listing row. */
|
|
27027
|
-
var ExtensionSourceSchema = object({
|
|
27028
|
-
/** The routing prefix of every `slotRef` this provider serves. */
|
|
27029
|
-
source: string$2(),
|
|
27030
|
-
label: string$2(),
|
|
27031
|
-
/** Stamped by the dispatcher from the registry (D557). */
|
|
27032
|
-
addonId: string$2().optional(),
|
|
27033
|
-
availability: ExtensionSourceAvailabilitySchema
|
|
27034
|
-
});
|
|
27035
|
-
/**
|
|
27036
|
-
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
27037
|
-
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
27038
|
-
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
27039
|
-
* valid source now (a container, which is never a pick). A source in any of
|
|
27040
|
-
* these states is SHOWN, never silently dropped or re-pointed.
|
|
27041
|
-
*/
|
|
27042
|
-
var ExtensionSourceHealthSchema = _enum([
|
|
27043
|
-
"ok",
|
|
27044
|
-
"missing",
|
|
27045
|
-
"foreign",
|
|
27046
|
-
"unavailable"
|
|
27047
|
-
]);
|
|
27048
|
-
var ExtensionSlotSourceSchema = object({
|
|
27049
|
-
deviceId: number().int(),
|
|
27050
|
-
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
27051
|
-
name: string$2().nullable(),
|
|
27052
|
-
health: ExtensionSourceHealthSchema,
|
|
27053
|
-
detail: string$2().optional()
|
|
27054
|
-
});
|
|
27055
|
-
/**
|
|
27056
|
-
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
27057
|
-
* reported read-only, named, never written through this contract (D62). The
|
|
27058
|
-
* virtual doorbell's sources ring only while the wrapper is bound to the
|
|
27059
|
-
* camera, and that binding belongs to `deviceManager.setWrapperActive`.
|
|
27060
|
-
* `unknown` means the gate could not be read; it is not "inactive" (D315).
|
|
27061
|
-
*/
|
|
27062
|
-
var ExtensionSlotActivationSchema = object({
|
|
27063
|
-
state: _enum([
|
|
27064
|
-
"active",
|
|
27065
|
-
"inactive",
|
|
27066
|
-
"unknown"
|
|
27067
|
-
]),
|
|
27068
|
-
authority: string$2(),
|
|
27069
|
-
detail: string$2().optional()
|
|
27070
|
-
});
|
|
27071
|
-
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
27072
|
-
state: literal("ok"),
|
|
27073
|
-
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
27074
|
-
slotRef: string$2(),
|
|
27075
|
-
slot: ExtensionSlotIdSchema,
|
|
27076
|
-
/** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
|
|
27077
|
-
authority: string$2(),
|
|
27078
|
-
activation: ExtensionSlotActivationSchema.nullable(),
|
|
27079
|
-
value: ExtensionSlotValueSchema,
|
|
27080
|
-
sources: array(ExtensionSlotSourceSchema),
|
|
27081
|
-
/**
|
|
27082
|
-
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
27083
|
-
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
27084
|
-
* the child a picked container stands for (D356 — a container is never a
|
|
27085
|
-
* pick, its children are). Read-only; the editor shows them and may offer
|
|
27086
|
-
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
27087
|
-
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
27088
|
-
* older than D655.
|
|
27089
|
-
*/
|
|
27090
|
-
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
27091
|
-
}), object({
|
|
27092
|
-
state: literal("unreachable"),
|
|
27093
|
-
addonId: string$2(),
|
|
27094
|
-
reason: string$2()
|
|
27095
|
-
})]);
|
|
27096
|
-
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
27097
|
-
deviceId: number().int(),
|
|
27098
|
-
name: string$2(),
|
|
27099
|
-
type: string$2(),
|
|
27100
|
-
location: string$2().nullable(),
|
|
27101
|
-
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
27102
|
-
parentName: string$2().nullable(),
|
|
27103
|
-
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
27104
|
-
suggested: boolean(),
|
|
27105
|
-
/** Why it is suggested ("same location"), null when it is not. */
|
|
27106
|
-
reason: string$2().nullable()
|
|
27107
|
-
})) });
|
|
27108
|
-
/**
|
|
27109
|
-
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
27110
|
-
* reloaded the host (or, for an accessory child, its parent) because the
|
|
27111
|
-
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
27112
|
-
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
27113
|
-
*/
|
|
27114
|
-
var ExtensionSetResultSchema = object({
|
|
27115
|
-
applied: literal(true),
|
|
27116
|
-
reload: _enum([
|
|
27117
|
-
"none",
|
|
27118
|
-
"host",
|
|
27119
|
-
"parent"
|
|
27120
|
-
])
|
|
27121
|
-
});
|
|
27122
|
-
var ExtensionSlotRefInputSchema = object({
|
|
27123
|
-
deviceId: number().int(),
|
|
27124
|
-
slotRef: string$2().min(1)
|
|
27125
|
-
});
|
|
27126
|
-
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
27127
|
-
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
27128
|
-
kind: "mutation",
|
|
27129
|
-
auth: "admin"
|
|
27130
|
-
});
|
|
27131
|
-
/**
|
|
27132
27477
|
* Optional client-side hints sent at session creation to help the provider
|
|
27133
27478
|
* pick the best native source. All fields optional — a viewer that knows
|
|
27134
27479
|
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
@@ -29613,6 +29958,70 @@ onStatusChanged: { data: object({
|
|
|
29613
29958
|
* whether persisting is worth a SQLite commit. */
|
|
29614
29959
|
volatileStateFields: ["lastChangedAt"]
|
|
29615
29960
|
};
|
|
29961
|
+
var DoorbellStatusSchema = object({
|
|
29962
|
+
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
29963
|
+
lastPressedAt: number().nullable(),
|
|
29964
|
+
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
29965
|
+
pressCountSinceStart: number()
|
|
29966
|
+
});
|
|
29967
|
+
var DoorbellPressEventSchema = object({
|
|
29968
|
+
deviceId: number(),
|
|
29969
|
+
timestamp: number()
|
|
29970
|
+
});
|
|
29971
|
+
/**
|
|
29972
|
+
* Doorbell button cap. Two kinds of provider serve it, and to every consumer
|
|
29973
|
+
* they are the same cap:
|
|
29974
|
+
*
|
|
29975
|
+
* - **Native** providers, registered per device by a driver addon through
|
|
29976
|
+
* `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
|
|
29977
|
+
* `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
|
|
29978
|
+
* camera level). They emit `onPressed` on every firmware ring.
|
|
29979
|
+
* - **A composed doorbell** (D670, D671): a camera's customization gives it
|
|
29980
|
+
* the cap, its `lastPressedAt` rising from the sources the operator
|
|
29981
|
+
* assigned in Customize → Doorbell, and the composer emits `onPressed`
|
|
29982
|
+
* from that field's advance (`fromState`).
|
|
29983
|
+
*
|
|
29984
|
+
* The DeviceEventPropagator re-emits `onPressed` on the camera parent.
|
|
29985
|
+
*/
|
|
29986
|
+
var doorbellCapability = {
|
|
29987
|
+
name: "doorbell",
|
|
29988
|
+
scope: "device",
|
|
29989
|
+
deviceNative: true,
|
|
29990
|
+
mode: "singleton",
|
|
29991
|
+
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
29992
|
+
methods: {},
|
|
29993
|
+
events: {
|
|
29994
|
+
/**
|
|
29995
|
+
* Fires once per physical press. Reolink delivers via Baichuan
|
|
29996
|
+
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
29997
|
+
* release/duration — it's a pulse.
|
|
29998
|
+
*/
|
|
29999
|
+
onPressed: {
|
|
30000
|
+
data: DoorbellPressEventSchema,
|
|
30001
|
+
fromState: {
|
|
30002
|
+
field: "lastPressedAt",
|
|
30003
|
+
on: "advance"
|
|
30004
|
+
}
|
|
30005
|
+
} },
|
|
30006
|
+
status: {
|
|
30007
|
+
schema: DoorbellStatusSchema,
|
|
30008
|
+
kind: "push"
|
|
30009
|
+
},
|
|
30010
|
+
/**
|
|
30011
|
+
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
30012
|
+
* Mirrored by the kernel and readable via
|
|
30013
|
+
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
30014
|
+
* without subscribing.
|
|
30015
|
+
*/
|
|
30016
|
+
runtimeState: DoorbellStatusSchema,
|
|
30017
|
+
/**
|
|
30018
|
+
* Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
|
|
30019
|
+
*
|
|
30020
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
30021
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
30022
|
+
*/
|
|
30023
|
+
durability: "restored"
|
|
30024
|
+
};
|
|
29616
30025
|
/**
|
|
29617
30026
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
29618
30027
|
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
@@ -31757,9 +32166,9 @@ var MotionStatusSchema = object({
|
|
|
31757
32166
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
31758
32167
|
lastDetectedAt: number().nullable(),
|
|
31759
32168
|
/**
|
|
31760
|
-
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device
|
|
31761
|
-
* `null` while false and on every `Sensor`
|
|
31762
|
-
* constant's doc for the one-authority rule.
|
|
32169
|
+
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
|
|
32170
|
+
* orchestrator writes it, D696), `null` while false and on every `Sensor`
|
|
32171
|
+
* device (D475) — see that constant's doc for the one-authority rule.
|
|
31763
32172
|
*
|
|
31764
32173
|
* ## Reading this field still arms nothing
|
|
31765
32174
|
*
|
|
@@ -31777,34 +32186,31 @@ var MotionStatusSchema = object({
|
|
|
31777
32186
|
* `addon-export-alexa/src/motion-clear-hold.ts` and
|
|
31778
32187
|
* `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
|
|
31779
32188
|
*
|
|
31780
|
-
* ## Who writes it
|
|
31781
|
-
*
|
|
31782
|
-
* - **Cameras** — the
|
|
31783
|
-
*
|
|
31784
|
-
* `
|
|
31785
|
-
* `
|
|
31786
|
-
*
|
|
31787
|
-
*
|
|
31788
|
-
* a
|
|
31789
|
-
*
|
|
31790
|
-
*
|
|
31791
|
-
*
|
|
31792
|
-
*
|
|
31793
|
-
*
|
|
31794
|
-
*
|
|
31795
|
-
*
|
|
31796
|
-
*
|
|
31797
|
-
*
|
|
31798
|
-
* `
|
|
31799
|
-
*
|
|
31800
|
-
*
|
|
31801
|
-
*
|
|
31802
|
-
*
|
|
31803
|
-
*
|
|
31804
|
-
*
|
|
31805
|
-
* This predates D475 and is not fixed there: the fix touches every
|
|
31806
|
-
* camera provider. Recorded in D475's Consequences. Do not restore the
|
|
31807
|
-
* "sole writer" wording without also removing the other writers.
|
|
32189
|
+
* ## Who writes it (D696)
|
|
32190
|
+
*
|
|
32191
|
+
* - **Cameras** — the orchestrator, and nothing else. It writes the camera's
|
|
32192
|
+
* EFFECTIVE motion (`addon-pipeline-orchestrator`
|
|
32193
|
+
* `camera-sensors/motion-slice.ts`), alongside the effective
|
|
32194
|
+
* `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
|
|
32195
|
+
* for a split camera, an unsplit emitter's direct event, the analyzer and
|
|
32196
|
+
* device activity, as the camera's `motionSources` counts them. A source
|
|
32197
|
+
* that never sends a clear falls one window after its last `true`.
|
|
32198
|
+
* `lastDetectedAt` moves only on an effective rise. No camera provider
|
|
32199
|
+
* writes this slice (not even a boot seed), and neither does the runner's
|
|
32200
|
+
* phase machine: its phase is "a session is attached" for every on-motion
|
|
32201
|
+
* session, not motion, and it now has its own `DetectionPhaseTransition`.
|
|
32202
|
+
* A provider's `isDetected` answers from the hub's slice.
|
|
32203
|
+
* - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
|
|
32204
|
+
* imports) — the provider pushes both edges itself, from the upstream
|
|
32205
|
+
* system's own state change. That is the sensor's own fact.
|
|
32206
|
+
*
|
|
32207
|
+
* `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
|
|
32208
|
+
* `motion` slice; each sensor writer is a named exemption.
|
|
32209
|
+
*
|
|
32210
|
+
* This replaces the D475 §4 rule ("the phase machine is the sole writer").
|
|
32211
|
+
* That rule was never true: Hikvision and Amcrest wrote the slice raw beside
|
|
32212
|
+
* it, every provider seeded it at boot, and every session left it
|
|
32213
|
+
* `detected: true` after its detach.
|
|
31808
32214
|
*/
|
|
31809
32215
|
autoClearAfterMs: number().nullable()
|
|
31810
32216
|
});
|
|
@@ -31876,11 +32282,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
31876
32282
|
*/
|
|
31877
32283
|
runtimeState: MotionStatusSchema,
|
|
31878
32284
|
/**
|
|
31879
|
-
* Runtime-state durability: **session** —
|
|
32285
|
+
* Runtime-state durability: **session** — the writer of this slice
|
|
31880
32286
|
* writes only on an EDGE, so a restored `detected: true` would stay
|
|
31881
32287
|
* frozen until the next one instead of being corrected. The next edge
|
|
31882
|
-
* re-publishes the real state
|
|
31883
|
-
*
|
|
32288
|
+
* re-publishes the real state, and the orchestrator re-publishes every
|
|
32289
|
+
* camera when it starts writing (D696; on who writes it, see
|
|
32290
|
+
* `autoClearAfterMs` above).
|
|
31884
32291
|
*
|
|
31885
32292
|
* See `RuntimeStateDurability`. Enforced by
|
|
31886
32293
|
* `scripts/check-runtime-state-durability.ts`.
|
|
@@ -34263,8 +34670,7 @@ var ptzAutotrackCapability = {
|
|
|
34263
34670
|
deviceNative: true,
|
|
34264
34671
|
mode: "singleton",
|
|
34265
34672
|
/**
|
|
34266
|
-
* Two kinds of provider behind one name, the same shape `snapshot`
|
|
34267
|
-
* `doorbell` use:
|
|
34673
|
+
* Two kinds of provider behind one name, the same shape `snapshot` uses:
|
|
34268
34674
|
*
|
|
34269
34675
|
* - **Native**: the camera's own firmware autotrack, registered per device by
|
|
34270
34676
|
* the driver when the probe says it exists (Reolink: yes; Hikvision:
|
|
@@ -34272,7 +34678,7 @@ var ptzAutotrackCapability = {
|
|
|
34272
34678
|
* - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
|
|
34273
34679
|
* which follows a subject with `ptz.move` pulses driven by the detection
|
|
34274
34680
|
* pipeline. `defaultActive: false` — the operator binds it per camera in
|
|
34275
|
-
* the bindings UI
|
|
34681
|
+
* the bindings UI.
|
|
34276
34682
|
*
|
|
34277
34683
|
* The binding chooses WHICH implementation answers; `setEnabled` stays the
|
|
34278
34684
|
* one switch for the function either way. A camera never has both driving its
|
|
@@ -34947,7 +35353,7 @@ var ReadGopBytesResultSchema = object({
|
|
|
34947
35353
|
/**
|
|
34948
35354
|
* A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
|
|
34949
35355
|
* twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
|
|
34950
|
-
* replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-
|
|
35356
|
+
* replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
|
|
34951
35357
|
* a replay needs several seconds of native pixels, not one frame.
|
|
34952
35358
|
*
|
|
34953
35359
|
* `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
|
|
@@ -38311,47 +38717,7 @@ var zoneRulesCapability = {
|
|
|
38311
38717
|
*/
|
|
38312
38718
|
durability: "restored"
|
|
38313
38719
|
};
|
|
38314
|
-
|
|
38315
|
-
kind: "fixed",
|
|
38316
|
-
result: ["number"]
|
|
38317
|
-
};
|
|
38318
|
-
var BOOLEAN = {
|
|
38319
|
-
kind: "fixed",
|
|
38320
|
-
result: ["boolean"]
|
|
38321
|
-
};
|
|
38322
|
-
Object.freeze({
|
|
38323
|
-
min: NUMBER,
|
|
38324
|
-
max: NUMBER,
|
|
38325
|
-
abs: NUMBER,
|
|
38326
|
-
floor: NUMBER,
|
|
38327
|
-
ceil: NUMBER,
|
|
38328
|
-
sqrt: NUMBER,
|
|
38329
|
-
round: NUMBER,
|
|
38330
|
-
pow: NUMBER,
|
|
38331
|
-
clamp: NUMBER,
|
|
38332
|
-
avg: NUMBER,
|
|
38333
|
-
sum: NUMBER,
|
|
38334
|
-
age: NUMBER,
|
|
38335
|
-
convert: NUMBER,
|
|
38336
|
-
coalesce: { kind: "coalesce" },
|
|
38337
|
-
any: BOOLEAN,
|
|
38338
|
-
all: BOOLEAN,
|
|
38339
|
-
within: BOOLEAN,
|
|
38340
|
-
latest: {
|
|
38341
|
-
kind: "fixed",
|
|
38342
|
-
result: ["number", "null"]
|
|
38343
|
-
},
|
|
38344
|
-
number: {
|
|
38345
|
-
kind: "fixed",
|
|
38346
|
-
result: ["number", "null"]
|
|
38347
|
-
},
|
|
38348
|
-
rose: {
|
|
38349
|
-
kind: "fixed",
|
|
38350
|
-
result: ["number", "null"]
|
|
38351
|
-
},
|
|
38352
|
-
count: NUMBER
|
|
38353
|
-
});
|
|
38354
|
-
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
38720
|
+
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
38355
38721
|
/**
|
|
38356
38722
|
* Accessory device helpers — shared across drivers.
|
|
38357
38723
|
*
|
|
@@ -39411,13 +39777,14 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
39411
39777
|
async getStatus() {
|
|
39412
39778
|
const all = await this.ctx.kernel.devices?.getAll() ?? [];
|
|
39413
39779
|
const summary = this.restoreFailureSummary();
|
|
39414
|
-
|
|
39780
|
+
const base = {
|
|
39415
39781
|
connected: true,
|
|
39416
|
-
deviceCount: all.length
|
|
39782
|
+
deviceCount: all.length,
|
|
39783
|
+
motionSliceWriter: "orchestrator"
|
|
39417
39784
|
};
|
|
39785
|
+
if (summary === null) return base;
|
|
39418
39786
|
return {
|
|
39419
|
-
|
|
39420
|
-
deviceCount: all.length,
|
|
39787
|
+
...base,
|
|
39421
39788
|
error: summary
|
|
39422
39789
|
};
|
|
39423
39790
|
}
|
|
@@ -42297,6 +42664,12 @@ Object.freeze({
|
|
|
42297
42664
|
addonId: null,
|
|
42298
42665
|
access: "view"
|
|
42299
42666
|
},
|
|
42667
|
+
"coreBlocks.listComposableCaps": {
|
|
42668
|
+
capName: "core-blocks",
|
|
42669
|
+
capScope: "system",
|
|
42670
|
+
addonId: null,
|
|
42671
|
+
access: "view"
|
|
42672
|
+
},
|
|
42300
42673
|
"coreBlocks.listCompositions": {
|
|
42301
42674
|
capName: "core-blocks",
|
|
42302
42675
|
capScope: "system",
|
|
@@ -42375,6 +42748,18 @@ Object.freeze({
|
|
|
42375
42748
|
addonId: null,
|
|
42376
42749
|
access: "view"
|
|
42377
42750
|
},
|
|
42751
|
+
"databaseSnapshot.listDatabases": {
|
|
42752
|
+
capName: "database-snapshot",
|
|
42753
|
+
capScope: "system",
|
|
42754
|
+
addonId: null,
|
|
42755
|
+
access: "view"
|
|
42756
|
+
},
|
|
42757
|
+
"databaseSnapshot.writeSnapshot": {
|
|
42758
|
+
capName: "database-snapshot",
|
|
42759
|
+
capScope: "system",
|
|
42760
|
+
addonId: null,
|
|
42761
|
+
access: "create"
|
|
42762
|
+
},
|
|
42378
42763
|
"dataStoreProvider.aggregate": {
|
|
42379
42764
|
capName: "data-store-provider",
|
|
42380
42765
|
capScope: "system",
|
|
@@ -44835,6 +45220,12 @@ Object.freeze({
|
|
|
44835
45220
|
addonId: null,
|
|
44836
45221
|
access: "view"
|
|
44837
45222
|
},
|
|
45223
|
+
"notificationRules.getAlarmSensors": {
|
|
45224
|
+
capName: "notification-rules",
|
|
45225
|
+
capScope: "system",
|
|
45226
|
+
addonId: null,
|
|
45227
|
+
access: "view"
|
|
45228
|
+
},
|
|
44838
45229
|
"notificationRules.getClipRetentionAsks": {
|
|
44839
45230
|
capName: "notification-rules",
|
|
44840
45231
|
capScope: "system",
|
|
@@ -45111,6 +45502,12 @@ Object.freeze({
|
|
|
45111
45502
|
addonId: null,
|
|
45112
45503
|
access: "create"
|
|
45113
45504
|
},
|
|
45505
|
+
"pipelineAnalytics.clearTrackRelation": {
|
|
45506
|
+
capName: "pipeline-analytics",
|
|
45507
|
+
capScope: "device",
|
|
45508
|
+
addonId: null,
|
|
45509
|
+
access: "delete"
|
|
45510
|
+
},
|
|
45114
45511
|
"pipelineAnalytics.clearTracks": {
|
|
45115
45512
|
capName: "pipeline-analytics",
|
|
45116
45513
|
capScope: "device",
|
|
@@ -45363,6 +45760,12 @@ Object.freeze({
|
|
|
45363
45760
|
addonId: null,
|
|
45364
45761
|
access: "view"
|
|
45365
45762
|
},
|
|
45763
|
+
"pipelineAnalytics.listTrackRelations": {
|
|
45764
|
+
capName: "pipeline-analytics",
|
|
45765
|
+
capScope: "device",
|
|
45766
|
+
addonId: null,
|
|
45767
|
+
access: "view"
|
|
45768
|
+
},
|
|
45366
45769
|
"pipelineAnalytics.listTracks": {
|
|
45367
45770
|
capName: "pipeline-analytics",
|
|
45368
45771
|
capScope: "device",
|
|
@@ -45477,6 +45880,18 @@ Object.freeze({
|
|
|
45477
45880
|
addonId: null,
|
|
45478
45881
|
access: "create"
|
|
45479
45882
|
},
|
|
45883
|
+
"pipelineAnalytics.setTrackPurity": {
|
|
45884
|
+
capName: "pipeline-analytics",
|
|
45885
|
+
capScope: "device",
|
|
45886
|
+
addonId: null,
|
|
45887
|
+
access: "create"
|
|
45888
|
+
},
|
|
45889
|
+
"pipelineAnalytics.setTrackRelation": {
|
|
45890
|
+
capName: "pipeline-analytics",
|
|
45891
|
+
capScope: "device",
|
|
45892
|
+
addonId: null,
|
|
45893
|
+
access: "create"
|
|
45894
|
+
},
|
|
45480
45895
|
"pipelineAnalytics.startStorageMigrationMove": {
|
|
45481
45896
|
capName: "pipeline-analytics",
|
|
45482
45897
|
capScope: "device",
|
|
@@ -45915,6 +46330,12 @@ Object.freeze({
|
|
|
45915
46330
|
addonId: null,
|
|
45916
46331
|
access: "delete"
|
|
45917
46332
|
},
|
|
46333
|
+
"pipelineOrchestrator.requestOccupancyLook": {
|
|
46334
|
+
capName: "pipeline-orchestrator",
|
|
46335
|
+
capScope: "system",
|
|
46336
|
+
addonId: null,
|
|
46337
|
+
access: "create"
|
|
46338
|
+
},
|
|
45918
46339
|
"pipelineOrchestrator.resetNodePipelineDefaults": {
|
|
45919
46340
|
capName: "pipeline-orchestrator",
|
|
45920
46341
|
capScope: "system",
|
|
@@ -45981,6 +46402,12 @@ Object.freeze({
|
|
|
45981
46402
|
addonId: null,
|
|
45982
46403
|
access: "create"
|
|
45983
46404
|
},
|
|
46405
|
+
"pipelineOrchestrator.setCameraSensors": {
|
|
46406
|
+
capName: "pipeline-orchestrator",
|
|
46407
|
+
capScope: "system",
|
|
46408
|
+
addonId: null,
|
|
46409
|
+
access: "create"
|
|
46410
|
+
},
|
|
45984
46411
|
"pipelineOrchestrator.setCameraStepOverride": {
|
|
45985
46412
|
capName: "pipeline-orchestrator",
|
|
45986
46413
|
capScope: "system",
|
|
@@ -48377,6 +48804,11 @@ Object.freeze({
|
|
|
48377
48804
|
}
|
|
48378
48805
|
});
|
|
48379
48806
|
Object.freeze({
|
|
48807
|
+
"accessories.getStatus": [{
|
|
48808
|
+
name: "deviceId",
|
|
48809
|
+
form: "single",
|
|
48810
|
+
optional: false
|
|
48811
|
+
}],
|
|
48380
48812
|
"accessories.setChildHidden": [{
|
|
48381
48813
|
name: "childDeviceId",
|
|
48382
48814
|
form: "single",
|
|
@@ -48396,6 +48828,11 @@ Object.freeze({
|
|
|
48396
48828
|
form: "single",
|
|
48397
48829
|
optional: false
|
|
48398
48830
|
}],
|
|
48831
|
+
"airQualitySensor.getStatus": [{
|
|
48832
|
+
name: "deviceId",
|
|
48833
|
+
form: "single",
|
|
48834
|
+
optional: false
|
|
48835
|
+
}],
|
|
48399
48836
|
"alarmPanel.arm": [{
|
|
48400
48837
|
name: "deviceId",
|
|
48401
48838
|
form: "single",
|
|
@@ -48406,11 +48843,36 @@ Object.freeze({
|
|
|
48406
48843
|
form: "single",
|
|
48407
48844
|
optional: false
|
|
48408
48845
|
}],
|
|
48846
|
+
"alarmPanel.getStatus": [{
|
|
48847
|
+
name: "deviceId",
|
|
48848
|
+
form: "single",
|
|
48849
|
+
optional: false
|
|
48850
|
+
}],
|
|
48409
48851
|
"alarmPanel.trigger": [{
|
|
48410
48852
|
name: "deviceId",
|
|
48411
48853
|
form: "single",
|
|
48412
48854
|
optional: false
|
|
48413
48855
|
}],
|
|
48856
|
+
"ambientLightSensor.getStatus": [{
|
|
48857
|
+
name: "deviceId",
|
|
48858
|
+
form: "single",
|
|
48859
|
+
optional: false
|
|
48860
|
+
}],
|
|
48861
|
+
"audioAnalysis.applyDeviceSettingsPatch": [{
|
|
48862
|
+
name: "deviceId",
|
|
48863
|
+
form: "single",
|
|
48864
|
+
optional: false
|
|
48865
|
+
}],
|
|
48866
|
+
"audioAnalysis.getDeviceLiveContribution": [{
|
|
48867
|
+
name: "deviceId",
|
|
48868
|
+
form: "single",
|
|
48869
|
+
optional: false
|
|
48870
|
+
}],
|
|
48871
|
+
"audioAnalysis.getDeviceSettingsContribution": [{
|
|
48872
|
+
name: "deviceId",
|
|
48873
|
+
form: "single",
|
|
48874
|
+
optional: false
|
|
48875
|
+
}],
|
|
48414
48876
|
"audioAnalysis.resolveDeviceSettings": [{
|
|
48415
48877
|
name: "deviceId",
|
|
48416
48878
|
form: "single",
|
|
@@ -48451,16 +48913,36 @@ Object.freeze({
|
|
|
48451
48913
|
form: "single",
|
|
48452
48914
|
optional: false
|
|
48453
48915
|
}],
|
|
48916
|
+
"automationControl.getStatus": [{
|
|
48917
|
+
name: "deviceId",
|
|
48918
|
+
form: "single",
|
|
48919
|
+
optional: false
|
|
48920
|
+
}],
|
|
48454
48921
|
"automationControl.trigger": [{
|
|
48455
48922
|
name: "deviceId",
|
|
48456
48923
|
form: "single",
|
|
48457
48924
|
optional: false
|
|
48458
48925
|
}],
|
|
48926
|
+
"battery.getStatus": [{
|
|
48927
|
+
name: "deviceId",
|
|
48928
|
+
form: "single",
|
|
48929
|
+
optional: false
|
|
48930
|
+
}],
|
|
48459
48931
|
"battery.wakeForStream": [{
|
|
48460
48932
|
name: "deviceId",
|
|
48461
48933
|
form: "single",
|
|
48462
48934
|
optional: false
|
|
48463
48935
|
}],
|
|
48936
|
+
"binary.getStatus": [{
|
|
48937
|
+
name: "deviceId",
|
|
48938
|
+
form: "single",
|
|
48939
|
+
optional: false
|
|
48940
|
+
}],
|
|
48941
|
+
"brightness.getStatus": [{
|
|
48942
|
+
name: "deviceId",
|
|
48943
|
+
form: "single",
|
|
48944
|
+
optional: false
|
|
48945
|
+
}],
|
|
48464
48946
|
"brightness.setBrightness": [{
|
|
48465
48947
|
name: "deviceId",
|
|
48466
48948
|
form: "single",
|
|
@@ -48476,6 +48958,26 @@ Object.freeze({
|
|
|
48476
48958
|
form: "single",
|
|
48477
48959
|
optional: false
|
|
48478
48960
|
}],
|
|
48961
|
+
"cameraCredentials.getStatus": [{
|
|
48962
|
+
name: "deviceId",
|
|
48963
|
+
form: "single",
|
|
48964
|
+
optional: false
|
|
48965
|
+
}],
|
|
48966
|
+
"cameraGridLayout.applyDeviceSettingsPatch": [{
|
|
48967
|
+
name: "deviceId",
|
|
48968
|
+
form: "single",
|
|
48969
|
+
optional: false
|
|
48970
|
+
}],
|
|
48971
|
+
"cameraGridLayout.getDeviceLiveContribution": [{
|
|
48972
|
+
name: "deviceId",
|
|
48973
|
+
form: "single",
|
|
48974
|
+
optional: false
|
|
48975
|
+
}],
|
|
48976
|
+
"cameraGridLayout.getDeviceSettingsContribution": [{
|
|
48977
|
+
name: "deviceId",
|
|
48978
|
+
form: "single",
|
|
48979
|
+
optional: false
|
|
48980
|
+
}],
|
|
48479
48981
|
"cameraGridLayout.getLayout": [{
|
|
48480
48982
|
name: "deviceId",
|
|
48481
48983
|
form: "single",
|
|
@@ -48491,6 +48993,21 @@ Object.freeze({
|
|
|
48491
48993
|
form: "single",
|
|
48492
48994
|
optional: false
|
|
48493
48995
|
}],
|
|
48996
|
+
"cameraPipelineConfig.applyDeviceSettingsPatch": [{
|
|
48997
|
+
name: "deviceId",
|
|
48998
|
+
form: "single",
|
|
48999
|
+
optional: false
|
|
49000
|
+
}],
|
|
49001
|
+
"cameraPipelineConfig.getDeviceLiveContribution": [{
|
|
49002
|
+
name: "deviceId",
|
|
49003
|
+
form: "single",
|
|
49004
|
+
optional: false
|
|
49005
|
+
}],
|
|
49006
|
+
"cameraPipelineConfig.getDeviceSettingsContribution": [{
|
|
49007
|
+
name: "deviceId",
|
|
49008
|
+
form: "single",
|
|
49009
|
+
optional: false
|
|
49010
|
+
}],
|
|
48494
49011
|
"cameraStreams.getBrokerStreams": [{
|
|
48495
49012
|
name: "deviceId",
|
|
48496
49013
|
form: "single",
|
|
@@ -48516,6 +49033,16 @@ Object.freeze({
|
|
|
48516
49033
|
form: "single",
|
|
48517
49034
|
optional: false
|
|
48518
49035
|
}],
|
|
49036
|
+
"carbonMonoxide.getStatus": [{
|
|
49037
|
+
name: "deviceId",
|
|
49038
|
+
form: "single",
|
|
49039
|
+
optional: false
|
|
49040
|
+
}],
|
|
49041
|
+
"climateControl.getStatus": [{
|
|
49042
|
+
name: "deviceId",
|
|
49043
|
+
form: "single",
|
|
49044
|
+
optional: false
|
|
49045
|
+
}],
|
|
48519
49046
|
"climateControl.setFanMode": [{
|
|
48520
49047
|
name: "deviceId",
|
|
48521
49048
|
form: "single",
|
|
@@ -48556,16 +49083,41 @@ Object.freeze({
|
|
|
48556
49083
|
form: "single",
|
|
48557
49084
|
optional: false
|
|
48558
49085
|
}],
|
|
49086
|
+
"color.getStatus": [{
|
|
49087
|
+
name: "deviceId",
|
|
49088
|
+
form: "single",
|
|
49089
|
+
optional: false
|
|
49090
|
+
}],
|
|
48559
49091
|
"color.setColor": [{
|
|
48560
49092
|
name: "deviceId",
|
|
48561
49093
|
form: "single",
|
|
48562
49094
|
optional: false
|
|
48563
49095
|
}],
|
|
49096
|
+
"connectivity.getStatus": [{
|
|
49097
|
+
name: "deviceId",
|
|
49098
|
+
form: "single",
|
|
49099
|
+
optional: false
|
|
49100
|
+
}],
|
|
49101
|
+
"consumables.getStatus": [{
|
|
49102
|
+
name: "deviceId",
|
|
49103
|
+
form: "single",
|
|
49104
|
+
optional: false
|
|
49105
|
+
}],
|
|
48564
49106
|
"consumables.reset": [{
|
|
48565
49107
|
name: "deviceId",
|
|
48566
49108
|
form: "single",
|
|
48567
49109
|
optional: false
|
|
48568
49110
|
}],
|
|
49111
|
+
"contact.getStatus": [{
|
|
49112
|
+
name: "deviceId",
|
|
49113
|
+
form: "single",
|
|
49114
|
+
optional: false
|
|
49115
|
+
}],
|
|
49116
|
+
"control.getStatus": [{
|
|
49117
|
+
name: "deviceId",
|
|
49118
|
+
form: "single",
|
|
49119
|
+
optional: false
|
|
49120
|
+
}],
|
|
48569
49121
|
"control.setValue": [{
|
|
48570
49122
|
name: "deviceId",
|
|
48571
49123
|
form: "single",
|
|
@@ -48576,6 +49128,11 @@ Object.freeze({
|
|
|
48576
49128
|
form: "single",
|
|
48577
49129
|
optional: false
|
|
48578
49130
|
}],
|
|
49131
|
+
"cover.getStatus": [{
|
|
49132
|
+
name: "deviceId",
|
|
49133
|
+
form: "single",
|
|
49134
|
+
optional: false
|
|
49135
|
+
}],
|
|
48579
49136
|
"cover.open": [{
|
|
48580
49137
|
name: "deviceId",
|
|
48581
49138
|
form: "single",
|
|
@@ -48601,6 +49158,11 @@ Object.freeze({
|
|
|
48601
49158
|
form: "single",
|
|
48602
49159
|
optional: false
|
|
48603
49160
|
}],
|
|
49161
|
+
"dayNight.getStatus": [{
|
|
49162
|
+
name: "deviceId",
|
|
49163
|
+
form: "single",
|
|
49164
|
+
optional: false
|
|
49165
|
+
}],
|
|
48604
49166
|
"dayNight.setSettings": [{
|
|
48605
49167
|
name: "deviceId",
|
|
48606
49168
|
form: "single",
|
|
@@ -48611,11 +49173,31 @@ Object.freeze({
|
|
|
48611
49173
|
form: "single",
|
|
48612
49174
|
optional: true
|
|
48613
49175
|
}],
|
|
49176
|
+
"detectionPipeline.applyDeviceSettingsPatch": [{
|
|
49177
|
+
name: "deviceId",
|
|
49178
|
+
form: "single",
|
|
49179
|
+
optional: false
|
|
49180
|
+
}],
|
|
49181
|
+
"detectionPipeline.getDeviceLiveContribution": [{
|
|
49182
|
+
name: "deviceId",
|
|
49183
|
+
form: "single",
|
|
49184
|
+
optional: false
|
|
49185
|
+
}],
|
|
49186
|
+
"detectionPipeline.getDeviceSettingsContribution": [{
|
|
49187
|
+
name: "deviceId",
|
|
49188
|
+
form: "single",
|
|
49189
|
+
optional: false
|
|
49190
|
+
}],
|
|
48614
49191
|
"deviceAdminLink.getAdminLink": [{
|
|
48615
49192
|
name: "deviceId",
|
|
48616
49193
|
form: "single",
|
|
48617
49194
|
optional: false
|
|
48618
49195
|
}],
|
|
49196
|
+
"deviceAdoption.getStatus": [{
|
|
49197
|
+
name: "deviceId",
|
|
49198
|
+
form: "single",
|
|
49199
|
+
optional: false
|
|
49200
|
+
}],
|
|
48619
49201
|
"deviceAdoption.release": [{
|
|
48620
49202
|
name: "camDeviceId",
|
|
48621
49203
|
form: "single",
|
|
@@ -48631,6 +49213,11 @@ Object.freeze({
|
|
|
48631
49213
|
form: "single",
|
|
48632
49214
|
optional: false
|
|
48633
49215
|
}],
|
|
49216
|
+
"deviceDiscovery.getStatus": [{
|
|
49217
|
+
name: "deviceId",
|
|
49218
|
+
form: "single",
|
|
49219
|
+
optional: false
|
|
49220
|
+
}],
|
|
48634
49221
|
"deviceDiscovery.listDiscovered": [{
|
|
48635
49222
|
name: "deviceId",
|
|
48636
49223
|
form: "single",
|
|
@@ -48650,6 +49237,21 @@ Object.freeze({
|
|
|
48650
49237
|
form: "single",
|
|
48651
49238
|
optional: false
|
|
48652
49239
|
}],
|
|
49240
|
+
"deviceExport.applyDeviceSettingsPatch": [{
|
|
49241
|
+
name: "deviceId",
|
|
49242
|
+
form: "single",
|
|
49243
|
+
optional: false
|
|
49244
|
+
}],
|
|
49245
|
+
"deviceExport.getDeviceLiveContribution": [{
|
|
49246
|
+
name: "deviceId",
|
|
49247
|
+
form: "single",
|
|
49248
|
+
optional: false
|
|
49249
|
+
}],
|
|
49250
|
+
"deviceExport.getDeviceSettingsContribution": [{
|
|
49251
|
+
name: "deviceId",
|
|
49252
|
+
form: "single",
|
|
49253
|
+
optional: false
|
|
49254
|
+
}],
|
|
48653
49255
|
"deviceExtension.listCandidates": [{
|
|
48654
49256
|
name: "deviceId",
|
|
48655
49257
|
form: "single",
|
|
@@ -48998,6 +49600,26 @@ Object.freeze({
|
|
|
48998
49600
|
form: "single",
|
|
48999
49601
|
optional: false
|
|
49000
49602
|
}],
|
|
49603
|
+
"deviceStatus.getStatus": [{
|
|
49604
|
+
name: "deviceId",
|
|
49605
|
+
form: "single",
|
|
49606
|
+
optional: false
|
|
49607
|
+
}],
|
|
49608
|
+
"doorbell.getStatus": [{
|
|
49609
|
+
name: "deviceId",
|
|
49610
|
+
form: "single",
|
|
49611
|
+
optional: false
|
|
49612
|
+
}],
|
|
49613
|
+
"enumSensor.getStatus": [{
|
|
49614
|
+
name: "deviceId",
|
|
49615
|
+
form: "single",
|
|
49616
|
+
optional: false
|
|
49617
|
+
}],
|
|
49618
|
+
"eventEmitter.getStatus": [{
|
|
49619
|
+
name: "deviceId",
|
|
49620
|
+
form: "single",
|
|
49621
|
+
optional: false
|
|
49622
|
+
}],
|
|
49001
49623
|
"faceGallery.getFaceByTrack": [{
|
|
49002
49624
|
name: "deviceId",
|
|
49003
49625
|
form: "single",
|
|
@@ -49012,6 +49634,11 @@ Object.freeze({
|
|
|
49012
49634
|
form: "array",
|
|
49013
49635
|
optional: true
|
|
49014
49636
|
}],
|
|
49637
|
+
"fanControl.getStatus": [{
|
|
49638
|
+
name: "deviceId",
|
|
49639
|
+
form: "single",
|
|
49640
|
+
optional: false
|
|
49641
|
+
}],
|
|
49015
49642
|
"fanControl.setDirection": [{
|
|
49016
49643
|
name: "deviceId",
|
|
49017
49644
|
form: "single",
|
|
@@ -49032,6 +49659,26 @@ Object.freeze({
|
|
|
49032
49659
|
form: "single",
|
|
49033
49660
|
optional: false
|
|
49034
49661
|
}],
|
|
49662
|
+
"featureProbe.getStatus": [{
|
|
49663
|
+
name: "deviceId",
|
|
49664
|
+
form: "single",
|
|
49665
|
+
optional: false
|
|
49666
|
+
}],
|
|
49667
|
+
"flood.getStatus": [{
|
|
49668
|
+
name: "deviceId",
|
|
49669
|
+
form: "single",
|
|
49670
|
+
optional: false
|
|
49671
|
+
}],
|
|
49672
|
+
"gas.getStatus": [{
|
|
49673
|
+
name: "deviceId",
|
|
49674
|
+
form: "single",
|
|
49675
|
+
optional: false
|
|
49676
|
+
}],
|
|
49677
|
+
"humidifier.getStatus": [{
|
|
49678
|
+
name: "deviceId",
|
|
49679
|
+
form: "single",
|
|
49680
|
+
optional: false
|
|
49681
|
+
}],
|
|
49035
49682
|
"humidifier.setMode": [{
|
|
49036
49683
|
name: "deviceId",
|
|
49037
49684
|
form: "single",
|
|
@@ -49047,11 +49694,26 @@ Object.freeze({
|
|
|
49047
49694
|
form: "single",
|
|
49048
49695
|
optional: false
|
|
49049
49696
|
}],
|
|
49697
|
+
"humiditySensor.getStatus": [{
|
|
49698
|
+
name: "deviceId",
|
|
49699
|
+
form: "single",
|
|
49700
|
+
optional: false
|
|
49701
|
+
}],
|
|
49702
|
+
"image.getStatus": [{
|
|
49703
|
+
name: "deviceId",
|
|
49704
|
+
form: "single",
|
|
49705
|
+
optional: false
|
|
49706
|
+
}],
|
|
49050
49707
|
"imageSettings.getOptions": [{
|
|
49051
49708
|
name: "deviceId",
|
|
49052
49709
|
form: "single",
|
|
49053
49710
|
optional: false
|
|
49054
49711
|
}],
|
|
49712
|
+
"imageSettings.getStatus": [{
|
|
49713
|
+
name: "deviceId",
|
|
49714
|
+
form: "single",
|
|
49715
|
+
optional: false
|
|
49716
|
+
}],
|
|
49055
49717
|
"imageSettings.setSettings": [{
|
|
49056
49718
|
name: "deviceId",
|
|
49057
49719
|
form: "single",
|
|
@@ -49062,6 +49724,11 @@ Object.freeze({
|
|
|
49062
49724
|
form: "single",
|
|
49063
49725
|
optional: false
|
|
49064
49726
|
}],
|
|
49727
|
+
"intercom.getStatus": [{
|
|
49728
|
+
name: "deviceId",
|
|
49729
|
+
form: "single",
|
|
49730
|
+
optional: false
|
|
49731
|
+
}],
|
|
49065
49732
|
"intercom.handleAnswer": [{
|
|
49066
49733
|
name: "deviceId",
|
|
49067
49734
|
form: "single",
|
|
@@ -49092,6 +49759,11 @@ Object.freeze({
|
|
|
49092
49759
|
form: "single",
|
|
49093
49760
|
optional: false
|
|
49094
49761
|
}],
|
|
49762
|
+
"lawnMowerControl.getStatus": [{
|
|
49763
|
+
name: "deviceId",
|
|
49764
|
+
form: "single",
|
|
49765
|
+
optional: false
|
|
49766
|
+
}],
|
|
49095
49767
|
"lawnMowerControl.pause": [{
|
|
49096
49768
|
name: "deviceId",
|
|
49097
49769
|
form: "single",
|
|
@@ -49102,6 +49774,11 @@ Object.freeze({
|
|
|
49102
49774
|
form: "single",
|
|
49103
49775
|
optional: false
|
|
49104
49776
|
}],
|
|
49777
|
+
"lockControl.getStatus": [{
|
|
49778
|
+
name: "deviceId",
|
|
49779
|
+
form: "single",
|
|
49780
|
+
optional: false
|
|
49781
|
+
}],
|
|
49105
49782
|
"lockControl.lock": [{
|
|
49106
49783
|
name: "deviceId",
|
|
49107
49784
|
form: "single",
|
|
@@ -49117,6 +49794,11 @@ Object.freeze({
|
|
|
49117
49794
|
form: "single",
|
|
49118
49795
|
optional: false
|
|
49119
49796
|
}],
|
|
49797
|
+
"mediaPlayer.getStatus": [{
|
|
49798
|
+
name: "deviceId",
|
|
49799
|
+
form: "single",
|
|
49800
|
+
optional: false
|
|
49801
|
+
}],
|
|
49120
49802
|
"mediaPlayer.next": [{
|
|
49121
49803
|
name: "deviceId",
|
|
49122
49804
|
form: "single",
|
|
@@ -49177,6 +49859,11 @@ Object.freeze({
|
|
|
49177
49859
|
form: "single",
|
|
49178
49860
|
optional: false
|
|
49179
49861
|
}],
|
|
49862
|
+
"motion.getStatus": [{
|
|
49863
|
+
name: "deviceId",
|
|
49864
|
+
form: "single",
|
|
49865
|
+
optional: false
|
|
49866
|
+
}],
|
|
49180
49867
|
"motion.isDetected": [{
|
|
49181
49868
|
name: "deviceId",
|
|
49182
49869
|
form: "single",
|
|
@@ -49187,11 +49874,31 @@ Object.freeze({
|
|
|
49187
49874
|
form: "single",
|
|
49188
49875
|
optional: false
|
|
49189
49876
|
}],
|
|
49877
|
+
"motionDetection.applyDeviceSettingsPatch": [{
|
|
49878
|
+
name: "deviceId",
|
|
49879
|
+
form: "single",
|
|
49880
|
+
optional: false
|
|
49881
|
+
}],
|
|
49882
|
+
"motionDetection.getDeviceLiveContribution": [{
|
|
49883
|
+
name: "deviceId",
|
|
49884
|
+
form: "single",
|
|
49885
|
+
optional: false
|
|
49886
|
+
}],
|
|
49887
|
+
"motionDetection.getDeviceSettingsContribution": [{
|
|
49888
|
+
name: "deviceId",
|
|
49889
|
+
form: "single",
|
|
49890
|
+
optional: false
|
|
49891
|
+
}],
|
|
49190
49892
|
"motionDetection.removeCamera": [{
|
|
49191
49893
|
name: "deviceId",
|
|
49192
49894
|
form: "single",
|
|
49193
49895
|
optional: false
|
|
49194
49896
|
}],
|
|
49897
|
+
"motionTrigger.getStatus": [{
|
|
49898
|
+
name: "deviceId",
|
|
49899
|
+
form: "single",
|
|
49900
|
+
optional: false
|
|
49901
|
+
}],
|
|
49195
49902
|
"motionTrigger.setMotionTrigger": [{
|
|
49196
49903
|
name: "deviceId",
|
|
49197
49904
|
form: "single",
|
|
@@ -49202,6 +49909,11 @@ Object.freeze({
|
|
|
49202
49909
|
form: "single",
|
|
49203
49910
|
optional: false
|
|
49204
49911
|
}],
|
|
49912
|
+
"motionZones.getStatus": [{
|
|
49913
|
+
name: "deviceId",
|
|
49914
|
+
form: "single",
|
|
49915
|
+
optional: false
|
|
49916
|
+
}],
|
|
49205
49917
|
"motionZones.setZone": [{
|
|
49206
49918
|
name: "deviceId",
|
|
49207
49919
|
form: "single",
|
|
@@ -49212,6 +49924,11 @@ Object.freeze({
|
|
|
49212
49924
|
form: "single",
|
|
49213
49925
|
optional: false
|
|
49214
49926
|
}],
|
|
49927
|
+
"nativeObjectDetection.getStatus": [{
|
|
49928
|
+
name: "deviceId",
|
|
49929
|
+
form: "single",
|
|
49930
|
+
optional: false
|
|
49931
|
+
}],
|
|
49215
49932
|
"nativeObjectDetection.setEnabled": [{
|
|
49216
49933
|
name: "deviceId",
|
|
49217
49934
|
form: "single",
|
|
@@ -49227,6 +49944,11 @@ Object.freeze({
|
|
|
49227
49944
|
form: "single",
|
|
49228
49945
|
optional: false
|
|
49229
49946
|
}],
|
|
49947
|
+
"navigation.getStatus": [{
|
|
49948
|
+
name: "deviceId",
|
|
49949
|
+
form: "single",
|
|
49950
|
+
optional: false
|
|
49951
|
+
}],
|
|
49230
49952
|
"navigation.goToPoint": [{
|
|
49231
49953
|
name: "deviceId",
|
|
49232
49954
|
form: "single",
|
|
@@ -49272,6 +49994,11 @@ Object.freeze({
|
|
|
49272
49994
|
form: "single",
|
|
49273
49995
|
optional: false
|
|
49274
49996
|
}],
|
|
49997
|
+
"networkLink.getStatus": [{
|
|
49998
|
+
name: "deviceId",
|
|
49999
|
+
form: "single",
|
|
50000
|
+
optional: false
|
|
50001
|
+
}],
|
|
49275
50002
|
"networkQuality.getDeviceStats": [{
|
|
49276
50003
|
name: "deviceId",
|
|
49277
50004
|
form: "single",
|
|
@@ -49282,6 +50009,11 @@ Object.freeze({
|
|
|
49282
50009
|
form: "single",
|
|
49283
50010
|
optional: false
|
|
49284
50011
|
}],
|
|
50012
|
+
"notificationRules.getAlarmSensors": [{
|
|
50013
|
+
name: "deviceIds",
|
|
50014
|
+
form: "array",
|
|
50015
|
+
optional: false
|
|
50016
|
+
}],
|
|
49285
50017
|
"notificationRules.setDeviceMuted": [{
|
|
49286
50018
|
name: "deviceId",
|
|
49287
50019
|
form: "single",
|
|
@@ -49292,11 +50024,26 @@ Object.freeze({
|
|
|
49292
50024
|
form: "single",
|
|
49293
50025
|
optional: false
|
|
49294
50026
|
}],
|
|
50027
|
+
"notifier.getStatus": [{
|
|
50028
|
+
name: "deviceId",
|
|
50029
|
+
form: "single",
|
|
50030
|
+
optional: false
|
|
50031
|
+
}],
|
|
49295
50032
|
"notifier.send": [{
|
|
49296
50033
|
name: "deviceId",
|
|
49297
50034
|
form: "single",
|
|
49298
50035
|
optional: false
|
|
49299
50036
|
}],
|
|
50037
|
+
"numericSensor.getStatus": [{
|
|
50038
|
+
name: "deviceId",
|
|
50039
|
+
form: "single",
|
|
50040
|
+
optional: false
|
|
50041
|
+
}],
|
|
50042
|
+
"osd.getStatus": [{
|
|
50043
|
+
name: "deviceId",
|
|
50044
|
+
form: "single",
|
|
50045
|
+
optional: false
|
|
50046
|
+
}],
|
|
49300
50047
|
"osd.setOverlay": [{
|
|
49301
50048
|
name: "deviceId",
|
|
49302
50049
|
form: "single",
|
|
@@ -49356,6 +50103,11 @@ Object.freeze({
|
|
|
49356
50103
|
form: "single",
|
|
49357
50104
|
optional: false
|
|
49358
50105
|
}],
|
|
50106
|
+
"petFeeder.getStatus": [{
|
|
50107
|
+
name: "deviceId",
|
|
50108
|
+
form: "single",
|
|
50109
|
+
optional: false
|
|
50110
|
+
}],
|
|
49359
50111
|
"petFeeder.markFoodReplenished": [{
|
|
49360
50112
|
name: "deviceId",
|
|
49361
50113
|
form: "single",
|
|
@@ -49391,6 +50143,16 @@ Object.freeze({
|
|
|
49391
50143
|
form: "single",
|
|
49392
50144
|
optional: false
|
|
49393
50145
|
}],
|
|
50146
|
+
"pipelineAnalytics.applyDeviceSettingsPatch": [{
|
|
50147
|
+
name: "deviceId",
|
|
50148
|
+
form: "single",
|
|
50149
|
+
optional: false
|
|
50150
|
+
}],
|
|
50151
|
+
"pipelineAnalytics.clearTrackRelation": [{
|
|
50152
|
+
name: "deviceId",
|
|
50153
|
+
form: "single",
|
|
50154
|
+
optional: false
|
|
50155
|
+
}],
|
|
49394
50156
|
"pipelineAnalytics.clearTracks": [{
|
|
49395
50157
|
name: "deviceId",
|
|
49396
50158
|
form: "single",
|
|
@@ -49426,6 +50188,16 @@ Object.freeze({
|
|
|
49426
50188
|
form: "single",
|
|
49427
50189
|
optional: false
|
|
49428
50190
|
}],
|
|
50191
|
+
"pipelineAnalytics.getDeviceLiveContribution": [{
|
|
50192
|
+
name: "deviceId",
|
|
50193
|
+
form: "single",
|
|
50194
|
+
optional: false
|
|
50195
|
+
}],
|
|
50196
|
+
"pipelineAnalytics.getDeviceSettingsContribution": [{
|
|
50197
|
+
name: "deviceId",
|
|
50198
|
+
form: "single",
|
|
50199
|
+
optional: false
|
|
50200
|
+
}],
|
|
49429
50201
|
"pipelineAnalytics.getEventDensity": [{
|
|
49430
50202
|
name: "deviceId",
|
|
49431
50203
|
form: "single",
|
|
@@ -49541,6 +50313,11 @@ Object.freeze({
|
|
|
49541
50313
|
form: "single",
|
|
49542
50314
|
optional: false
|
|
49543
50315
|
}],
|
|
50316
|
+
"pipelineAnalytics.listTrackRelations": [{
|
|
50317
|
+
name: "deviceId",
|
|
50318
|
+
form: "single",
|
|
50319
|
+
optional: false
|
|
50320
|
+
}],
|
|
49544
50321
|
"pipelineAnalytics.listTracks": [{
|
|
49545
50322
|
name: "deviceId",
|
|
49546
50323
|
form: "single",
|
|
@@ -49611,6 +50388,16 @@ Object.freeze({
|
|
|
49611
50388
|
form: "single",
|
|
49612
50389
|
optional: false
|
|
49613
50390
|
}],
|
|
50391
|
+
"pipelineAnalytics.setTrackPurity": [{
|
|
50392
|
+
name: "deviceId",
|
|
50393
|
+
form: "single",
|
|
50394
|
+
optional: false
|
|
50395
|
+
}],
|
|
50396
|
+
"pipelineAnalytics.setTrackRelation": [{
|
|
50397
|
+
name: "deviceId",
|
|
50398
|
+
form: "single",
|
|
50399
|
+
optional: false
|
|
50400
|
+
}],
|
|
49614
50401
|
"pipelineAnalytics.wipeAllAnalytics": [{
|
|
49615
50402
|
name: "deviceId",
|
|
49616
50403
|
form: "single",
|
|
@@ -49626,6 +50413,11 @@ Object.freeze({
|
|
|
49626
50413
|
form: "single",
|
|
49627
50414
|
optional: true
|
|
49628
50415
|
}],
|
|
50416
|
+
"pipelineOrchestrator.applyDeviceSettingsPatch": [{
|
|
50417
|
+
name: "deviceId",
|
|
50418
|
+
form: "single",
|
|
50419
|
+
optional: false
|
|
50420
|
+
}],
|
|
49629
50421
|
"pipelineOrchestrator.assignAudio": [{
|
|
49630
50422
|
name: "deviceId",
|
|
49631
50423
|
form: "single",
|
|
@@ -49671,6 +50463,16 @@ Object.freeze({
|
|
|
49671
50463
|
form: "single",
|
|
49672
50464
|
optional: false
|
|
49673
50465
|
}],
|
|
50466
|
+
"pipelineOrchestrator.getDeviceLiveContribution": [{
|
|
50467
|
+
name: "deviceId",
|
|
50468
|
+
form: "single",
|
|
50469
|
+
optional: false
|
|
50470
|
+
}],
|
|
50471
|
+
"pipelineOrchestrator.getDeviceSettingsContribution": [{
|
|
50472
|
+
name: "deviceId",
|
|
50473
|
+
form: "single",
|
|
50474
|
+
optional: false
|
|
50475
|
+
}],
|
|
49674
50476
|
"pipelineOrchestrator.getPipelineAssignment": [{
|
|
49675
50477
|
name: "deviceId",
|
|
49676
50478
|
form: "single",
|
|
@@ -49681,6 +50483,11 @@ Object.freeze({
|
|
|
49681
50483
|
form: "single",
|
|
49682
50484
|
optional: false
|
|
49683
50485
|
}],
|
|
50486
|
+
"pipelineOrchestrator.requestOccupancyLook": [{
|
|
50487
|
+
name: "deviceId",
|
|
50488
|
+
form: "single",
|
|
50489
|
+
optional: false
|
|
50490
|
+
}],
|
|
49684
50491
|
"pipelineOrchestrator.resolvePipeline": [{
|
|
49685
50492
|
name: "deviceId",
|
|
49686
50493
|
form: "single",
|
|
@@ -49691,6 +50498,11 @@ Object.freeze({
|
|
|
49691
50498
|
form: "single",
|
|
49692
50499
|
optional: false
|
|
49693
50500
|
}],
|
|
50501
|
+
"pipelineOrchestrator.setCameraSensors": [{
|
|
50502
|
+
name: "deviceId",
|
|
50503
|
+
form: "single",
|
|
50504
|
+
optional: false
|
|
50505
|
+
}],
|
|
49694
50506
|
"pipelineOrchestrator.setCameraStepOverride": [{
|
|
49695
50507
|
name: "deviceId",
|
|
49696
50508
|
form: "single",
|
|
@@ -49781,11 +50593,31 @@ Object.freeze({
|
|
|
49781
50593
|
form: "single",
|
|
49782
50594
|
optional: true
|
|
49783
50595
|
}],
|
|
50596
|
+
"powerMeter.getStatus": [{
|
|
50597
|
+
name: "deviceId",
|
|
50598
|
+
form: "single",
|
|
50599
|
+
optional: false
|
|
50600
|
+
}],
|
|
50601
|
+
"presence.getStatus": [{
|
|
50602
|
+
name: "deviceId",
|
|
50603
|
+
form: "single",
|
|
50604
|
+
optional: false
|
|
50605
|
+
}],
|
|
50606
|
+
"pressureSensor.getStatus": [{
|
|
50607
|
+
name: "deviceId",
|
|
50608
|
+
form: "single",
|
|
50609
|
+
optional: false
|
|
50610
|
+
}],
|
|
49784
50611
|
"privacyMask.getOptions": [{
|
|
49785
50612
|
name: "deviceId",
|
|
49786
50613
|
form: "single",
|
|
49787
50614
|
optional: false
|
|
49788
50615
|
}],
|
|
50616
|
+
"privacyMask.getStatus": [{
|
|
50617
|
+
name: "deviceId",
|
|
50618
|
+
form: "single",
|
|
50619
|
+
optional: false
|
|
50620
|
+
}],
|
|
49789
50621
|
"privacyMask.setAudioEnabled": [{
|
|
49790
50622
|
name: "deviceId",
|
|
49791
50623
|
form: "single",
|
|
@@ -49836,6 +50668,11 @@ Object.freeze({
|
|
|
49836
50668
|
form: "single",
|
|
49837
50669
|
optional: false
|
|
49838
50670
|
}],
|
|
50671
|
+
"ptz.getStatus": [{
|
|
50672
|
+
name: "deviceId",
|
|
50673
|
+
form: "single",
|
|
50674
|
+
optional: false
|
|
50675
|
+
}],
|
|
49839
50676
|
"ptz.goHome": [{
|
|
49840
50677
|
name: "deviceId",
|
|
49841
50678
|
form: "single",
|
|
@@ -49926,6 +50763,11 @@ Object.freeze({
|
|
|
49926
50763
|
form: "single",
|
|
49927
50764
|
optional: false
|
|
49928
50765
|
}],
|
|
50766
|
+
"recordingArchive.applyDeviceSettingsPatch": [{
|
|
50767
|
+
name: "deviceId",
|
|
50768
|
+
form: "single",
|
|
50769
|
+
optional: false
|
|
50770
|
+
}],
|
|
49929
50771
|
"recordingArchive.deleteFootprint": [{
|
|
49930
50772
|
name: "deviceId",
|
|
49931
50773
|
form: "single",
|
|
@@ -49946,6 +50788,21 @@ Object.freeze({
|
|
|
49946
50788
|
form: "single",
|
|
49947
50789
|
optional: false
|
|
49948
50790
|
}],
|
|
50791
|
+
"recordingArchive.getDeviceLiveContribution": [{
|
|
50792
|
+
name: "deviceId",
|
|
50793
|
+
form: "single",
|
|
50794
|
+
optional: false
|
|
50795
|
+
}],
|
|
50796
|
+
"recordingArchive.getDeviceSettingsContribution": [{
|
|
50797
|
+
name: "deviceId",
|
|
50798
|
+
form: "single",
|
|
50799
|
+
optional: false
|
|
50800
|
+
}],
|
|
50801
|
+
"recordingArchive.getStatus": [{
|
|
50802
|
+
name: "deviceId",
|
|
50803
|
+
form: "single",
|
|
50804
|
+
optional: false
|
|
50805
|
+
}],
|
|
49949
50806
|
"recordingArchive.listOpsLog": [{
|
|
49950
50807
|
name: "deviceId",
|
|
49951
50808
|
form: "single",
|
|
@@ -50031,6 +50888,11 @@ Object.freeze({
|
|
|
50031
50888
|
form: "single",
|
|
50032
50889
|
optional: false
|
|
50033
50890
|
}],
|
|
50891
|
+
"recordingOnboard.getStatus": [{
|
|
50892
|
+
name: "deviceId",
|
|
50893
|
+
form: "single",
|
|
50894
|
+
optional: false
|
|
50895
|
+
}],
|
|
50034
50896
|
"recordingOnboard.setSettings": [{
|
|
50035
50897
|
name: "deviceId",
|
|
50036
50898
|
form: "single",
|
|
@@ -50061,6 +50923,11 @@ Object.freeze({
|
|
|
50061
50923
|
form: "single",
|
|
50062
50924
|
optional: false
|
|
50063
50925
|
}],
|
|
50926
|
+
"sceneMonitor.getStatus": [{
|
|
50927
|
+
name: "deviceId",
|
|
50928
|
+
form: "single",
|
|
50929
|
+
optional: false
|
|
50930
|
+
}],
|
|
50064
50931
|
"sceneMonitor.listScenes": [{
|
|
50065
50932
|
name: "deviceId",
|
|
50066
50933
|
form: "single",
|
|
@@ -50086,6 +50953,11 @@ Object.freeze({
|
|
|
50086
50953
|
form: "single",
|
|
50087
50954
|
optional: false
|
|
50088
50955
|
}],
|
|
50956
|
+
"scriptRunner.getStatus": [{
|
|
50957
|
+
name: "deviceId",
|
|
50958
|
+
form: "single",
|
|
50959
|
+
optional: false
|
|
50960
|
+
}],
|
|
50089
50961
|
"scriptRunner.run": [{
|
|
50090
50962
|
name: "deviceId",
|
|
50091
50963
|
form: "single",
|
|
@@ -50096,11 +50968,31 @@ Object.freeze({
|
|
|
50096
50968
|
form: "single",
|
|
50097
50969
|
optional: false
|
|
50098
50970
|
}],
|
|
50971
|
+
"smoke.getStatus": [{
|
|
50972
|
+
name: "deviceId",
|
|
50973
|
+
form: "single",
|
|
50974
|
+
optional: false
|
|
50975
|
+
}],
|
|
50976
|
+
"snapshot.applyDeviceSettingsPatch": [{
|
|
50977
|
+
name: "deviceId",
|
|
50978
|
+
form: "single",
|
|
50979
|
+
optional: false
|
|
50980
|
+
}],
|
|
50099
50981
|
"snapshot.getDebugState": [{
|
|
50100
50982
|
name: "deviceId",
|
|
50101
50983
|
form: "single",
|
|
50102
50984
|
optional: false
|
|
50103
50985
|
}],
|
|
50986
|
+
"snapshot.getDeviceLiveContribution": [{
|
|
50987
|
+
name: "deviceId",
|
|
50988
|
+
form: "single",
|
|
50989
|
+
optional: false
|
|
50990
|
+
}],
|
|
50991
|
+
"snapshot.getDeviceSettingsContribution": [{
|
|
50992
|
+
name: "deviceId",
|
|
50993
|
+
form: "single",
|
|
50994
|
+
optional: false
|
|
50995
|
+
}],
|
|
50104
50996
|
"snapshot.getSnapshot": [{
|
|
50105
50997
|
name: "deviceId",
|
|
50106
50998
|
form: "single",
|
|
@@ -50117,6 +51009,11 @@ Object.freeze({
|
|
|
50117
51009
|
form: "array",
|
|
50118
51010
|
optional: false
|
|
50119
51011
|
}],
|
|
51012
|
+
"snapshot.getStatus": [{
|
|
51013
|
+
name: "deviceId",
|
|
51014
|
+
form: "single",
|
|
51015
|
+
optional: false
|
|
51016
|
+
}],
|
|
50120
51017
|
"snapshot.invalidateCache": [{
|
|
50121
51018
|
name: "deviceId",
|
|
50122
51019
|
form: "single",
|
|
@@ -50127,6 +51024,11 @@ Object.freeze({
|
|
|
50127
51024
|
form: "single",
|
|
50128
51025
|
optional: false
|
|
50129
51026
|
}],
|
|
51027
|
+
"streamBroker.applyDeviceSettingsPatch": [{
|
|
51028
|
+
name: "deviceId",
|
|
51029
|
+
form: "single",
|
|
51030
|
+
optional: false
|
|
51031
|
+
}],
|
|
50130
51032
|
"streamBroker.assignProfile": [{
|
|
50131
51033
|
name: "deviceId",
|
|
50132
51034
|
form: "single",
|
|
@@ -50142,6 +51044,16 @@ Object.freeze({
|
|
|
50142
51044
|
form: "single",
|
|
50143
51045
|
optional: false
|
|
50144
51046
|
}],
|
|
51047
|
+
"streamBroker.getDeviceLiveContribution": [{
|
|
51048
|
+
name: "deviceId",
|
|
51049
|
+
form: "single",
|
|
51050
|
+
optional: false
|
|
51051
|
+
}],
|
|
51052
|
+
"streamBroker.getDeviceSettingsContribution": [{
|
|
51053
|
+
name: "deviceId",
|
|
51054
|
+
form: "single",
|
|
51055
|
+
optional: false
|
|
51056
|
+
}],
|
|
50145
51057
|
"streamBroker.getStreamWithCodec": [{
|
|
50146
51058
|
name: "deviceId",
|
|
50147
51059
|
form: "single",
|
|
@@ -50202,16 +51114,46 @@ Object.freeze({
|
|
|
50202
51114
|
form: "single",
|
|
50203
51115
|
optional: false
|
|
50204
51116
|
}],
|
|
51117
|
+
"streamParams.getStatus": [{
|
|
51118
|
+
name: "deviceId",
|
|
51119
|
+
form: "single",
|
|
51120
|
+
optional: false
|
|
51121
|
+
}],
|
|
50205
51122
|
"streamParams.setProfile": [{
|
|
50206
51123
|
name: "deviceId",
|
|
50207
51124
|
form: "single",
|
|
50208
51125
|
optional: false
|
|
50209
51126
|
}],
|
|
51127
|
+
"switch.getStatus": [{
|
|
51128
|
+
name: "deviceId",
|
|
51129
|
+
form: "single",
|
|
51130
|
+
optional: false
|
|
51131
|
+
}],
|
|
50210
51132
|
"switch.setState": [{
|
|
50211
51133
|
name: "deviceId",
|
|
50212
51134
|
form: "single",
|
|
50213
51135
|
optional: false
|
|
50214
51136
|
}],
|
|
51137
|
+
"tamper.getStatus": [{
|
|
51138
|
+
name: "deviceId",
|
|
51139
|
+
form: "single",
|
|
51140
|
+
optional: false
|
|
51141
|
+
}],
|
|
51142
|
+
"temperatureSensor.getStatus": [{
|
|
51143
|
+
name: "deviceId",
|
|
51144
|
+
form: "single",
|
|
51145
|
+
optional: false
|
|
51146
|
+
}],
|
|
51147
|
+
"update.getStatus": [{
|
|
51148
|
+
name: "deviceId",
|
|
51149
|
+
form: "single",
|
|
51150
|
+
optional: false
|
|
51151
|
+
}],
|
|
51152
|
+
"vacuumControl.getStatus": [{
|
|
51153
|
+
name: "deviceId",
|
|
51154
|
+
form: "single",
|
|
51155
|
+
optional: false
|
|
51156
|
+
}],
|
|
50215
51157
|
"vacuumControl.locate": [{
|
|
50216
51158
|
name: "deviceId",
|
|
50217
51159
|
form: "single",
|
|
@@ -50247,6 +51189,11 @@ Object.freeze({
|
|
|
50247
51189
|
form: "single",
|
|
50248
51190
|
optional: false
|
|
50249
51191
|
}],
|
|
51192
|
+
"valve.getStatus": [{
|
|
51193
|
+
name: "deviceId",
|
|
51194
|
+
form: "single",
|
|
51195
|
+
optional: false
|
|
51196
|
+
}],
|
|
50250
51197
|
"valve.open": [{
|
|
50251
51198
|
name: "deviceId",
|
|
50252
51199
|
form: "single",
|
|
@@ -50262,6 +51209,11 @@ Object.freeze({
|
|
|
50262
51209
|
form: "single",
|
|
50263
51210
|
optional: false
|
|
50264
51211
|
}],
|
|
51212
|
+
"vibration.getStatus": [{
|
|
51213
|
+
name: "deviceId",
|
|
51214
|
+
form: "single",
|
|
51215
|
+
optional: false
|
|
51216
|
+
}],
|
|
50265
51217
|
"videoclips.dialClipStream": [{
|
|
50266
51218
|
name: "deviceId",
|
|
50267
51219
|
form: "single",
|
|
@@ -50297,6 +51249,11 @@ Object.freeze({
|
|
|
50297
51249
|
form: "single",
|
|
50298
51250
|
optional: false
|
|
50299
51251
|
}],
|
|
51252
|
+
"waterHeater.getStatus": [{
|
|
51253
|
+
name: "deviceId",
|
|
51254
|
+
form: "single",
|
|
51255
|
+
optional: false
|
|
51256
|
+
}],
|
|
50300
51257
|
"waterHeater.setAway": [{
|
|
50301
51258
|
name: "deviceId",
|
|
50302
51259
|
form: "single",
|
|
@@ -50312,6 +51269,11 @@ Object.freeze({
|
|
|
50312
51269
|
form: "single",
|
|
50313
51270
|
optional: false
|
|
50314
51271
|
}],
|
|
51272
|
+
"weather.getStatus": [{
|
|
51273
|
+
name: "deviceId",
|
|
51274
|
+
form: "single",
|
|
51275
|
+
optional: false
|
|
51276
|
+
}],
|
|
50315
51277
|
"webrtcSession.addIceCandidate": [{
|
|
50316
51278
|
name: "deviceId",
|
|
50317
51279
|
form: "single",
|
|
@@ -50837,6 +51799,18 @@ var STATE_SUMMARY_VARS = [
|
|
|
50837
51799
|
systemEventKinds: [...SUMMARISABLE],
|
|
50838
51800
|
systemEventDeliveries: ["summary"]
|
|
50839
51801
|
},
|
|
51802
|
+
{
|
|
51803
|
+
name: "summarySection",
|
|
51804
|
+
label: "Summary: this section",
|
|
51805
|
+
description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
|
|
51806
|
+
example: "Batterie scariche",
|
|
51807
|
+
group: "system",
|
|
51808
|
+
families: ["rule"],
|
|
51809
|
+
fields: [...RULE_TEXT],
|
|
51810
|
+
kinds: ["system"],
|
|
51811
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
51812
|
+
systemEventDeliveries: ["summary"]
|
|
51813
|
+
},
|
|
50840
51814
|
...STATE_SUMMARY_SECTION_VARS.map((v) => ({
|
|
50841
51815
|
name: v.name,
|
|
50842
51816
|
label: v.label,
|
|
@@ -50913,6 +51887,37 @@ var STATE_SUMMARY_VARS = [
|
|
|
50913
51887
|
[...RULE_TEXT],
|
|
50914
51888
|
...STATE_SUMMARY_VARS
|
|
50915
51889
|
];
|
|
51890
|
+
new Set([
|
|
51891
|
+
"disarmed",
|
|
51892
|
+
"armed_home",
|
|
51893
|
+
"armed_away",
|
|
51894
|
+
"armed_night",
|
|
51895
|
+
"armed_vacation",
|
|
51896
|
+
"armed_custom_bypass",
|
|
51897
|
+
"arming",
|
|
51898
|
+
"disarming",
|
|
51899
|
+
"pending",
|
|
51900
|
+
"triggered",
|
|
51901
|
+
"open",
|
|
51902
|
+
"opening",
|
|
51903
|
+
"closing",
|
|
51904
|
+
"closed",
|
|
51905
|
+
"stopped",
|
|
51906
|
+
"locked",
|
|
51907
|
+
"unlocked",
|
|
51908
|
+
"locking",
|
|
51909
|
+
"unlocking",
|
|
51910
|
+
"jammed",
|
|
51911
|
+
"on",
|
|
51912
|
+
"off",
|
|
51913
|
+
"home",
|
|
51914
|
+
"not_home",
|
|
51915
|
+
"matched",
|
|
51916
|
+
"diverged",
|
|
51917
|
+
"unknown",
|
|
51918
|
+
"latched",
|
|
51919
|
+
"live"
|
|
51920
|
+
]);
|
|
50916
51921
|
/**
|
|
50917
51922
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
50918
51923
|
*
|
|
@@ -51006,7 +52011,7 @@ var PreviewTextField = string$2().max(200);
|
|
|
51006
52011
|
* Whether the notification's preview is a STILL or a short animation.
|
|
51007
52012
|
*
|
|
51008
52013
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
51009
|
-
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
52014
|
+
* rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
|
|
51010
52015
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
51011
52016
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
51012
52017
|
* simply applies it to a dozen frames sampled across the render and assembles
|
|
@@ -51144,6 +52149,7 @@ TimelapseRuleInputSchema.extend({
|
|
|
51144
52149
|
createdAt: number(),
|
|
51145
52150
|
updatedAt: number()
|
|
51146
52151
|
});
|
|
52152
|
+
MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
|
|
51147
52153
|
object({
|
|
51148
52154
|
/**
|
|
51149
52155
|
* Fraction of the box's own size added on EACH side before cutting.
|