@camstack/addon-provider-rtsp 1.2.116 → 1.2.118
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 +1450 -681
- package/dist/addon.mjs +1450 -681
- package/package.json +2 -4
package/dist/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-BGmz_oxW.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -532,6 +532,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
532
532
|
*/
|
|
533
533
|
EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
|
|
534
534
|
EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
|
|
535
|
+
/**
|
|
536
|
+
* A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
|
|
537
|
+
* data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
|
|
538
|
+
* consumer is the orchestrator's camera-sensors bridge, which re-emits the
|
|
539
|
+
* camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
|
|
540
|
+
* for a camera with no attached sensor). Providers must not emit
|
|
541
|
+
* `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
|
|
542
|
+
* keeps it so (camera-grid is a named, deferred exception).
|
|
543
|
+
*/
|
|
535
544
|
EventCategory["ProviderMotion"] = "provider.motion";
|
|
536
545
|
EventCategory["ProviderDetection"] = "provider.detection";
|
|
537
546
|
EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
|
|
@@ -5370,7 +5379,7 @@ var ZodIssueCode = {
|
|
|
5370
5379
|
var ZodFirstPartyTypeKind;
|
|
5371
5380
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5372
5381
|
//#endregion
|
|
5373
|
-
//#region ../types/dist/sleep-
|
|
5382
|
+
//#region ../types/dist/sleep-CDCONfkt.mjs
|
|
5374
5383
|
/**
|
|
5375
5384
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5376
5385
|
* window to float samples (D455).
|
|
@@ -7413,7 +7422,7 @@ function errMsg(err) {
|
|
|
7413
7422
|
return String(err);
|
|
7414
7423
|
}
|
|
7415
7424
|
//#endregion
|
|
7416
|
-
//#region ../types/dist/composition-
|
|
7425
|
+
//#region ../types/dist/composition-Bzr7GwgP.mjs
|
|
7417
7426
|
/**
|
|
7418
7427
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
7419
7428
|
*
|
|
@@ -7467,21 +7476,20 @@ function portable(target) {
|
|
|
7467
7476
|
}
|
|
7468
7477
|
portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
|
|
7469
7478
|
/**
|
|
7470
|
-
*
|
|
7471
|
-
*
|
|
7479
|
+
* THE table "which boolean of this device type counts as HIGH", and the
|
|
7480
|
+
* pure evaluator of its EDGE.
|
|
7472
7481
|
*
|
|
7473
|
-
*
|
|
7474
|
-
*
|
|
7475
|
-
*
|
|
7476
|
-
*
|
|
7477
|
-
*
|
|
7478
|
-
*
|
|
7479
|
-
* SPOSTA qui e il doorbell la ri-esporta.
|
|
7482
|
+
* ONE table for everyone who asks "is this device HIGH?": the
|
|
7483
|
+
* recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
|
|
7484
|
+
* sensor markers, the orchestrator's camera-sensors bridge and
|
|
7485
|
+
* the sources of a composite doorbell (`doorbellFeatureSources`, D671).
|
|
7486
|
+
* A second copy would diverge at the first cap added, and the symptom — "the
|
|
7487
|
+
* sensor rings the doorbell but does not record" — is exactly D62.
|
|
7480
7488
|
*
|
|
7481
|
-
* ⚠
|
|
7482
|
-
*
|
|
7483
|
-
*
|
|
7484
|
-
*
|
|
7489
|
+
* ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
|
|
7490
|
+
* two must not be unified: that one answers "what is the state WORD for a
|
|
7491
|
+
* rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
|
|
7492
|
+
* boolean's EDGE counts". Deliberately different vocabularies.
|
|
7485
7493
|
*/
|
|
7486
7494
|
/**
|
|
7487
7495
|
* Known binary / switch source caps → the boolean slice field whose
|
|
@@ -9122,22 +9130,22 @@ var CLASS_MAP_MACRO_TARGETS = [
|
|
|
9122
9130
|
"package"
|
|
9123
9131
|
];
|
|
9124
9132
|
/**
|
|
9125
|
-
*
|
|
9126
|
-
*
|
|
9133
|
+
* The FIRST-LEVEL macro classes: those an object detector emits and that
|
|
9134
|
+
* an operator can select.
|
|
9127
9135
|
*
|
|
9128
|
-
*
|
|
9136
|
+
* They are the three offered by the `object-detection` step
|
|
9129
9137
|
* (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
|
|
9130
|
-
* `enabledMacroClasses`). `package`
|
|
9131
|
-
* `MACRO_LABELS` —
|
|
9132
|
-
* `package-detection`,
|
|
9133
|
-
*
|
|
9138
|
+
* `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
|
|
9139
|
+
* `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
|
|
9140
|
+
* `package-detection`, whose enablement is driven by zones, and offering the
|
|
9141
|
+
* same word twice has already made an operator turn on the COCO proxy
|
|
9134
9142
|
* (suitcase/backpack/handbag) lasciando spento il detector dedicato.
|
|
9135
9143
|
*
|
|
9136
|
-
*
|
|
9137
|
-
*
|
|
9138
|
-
* (`types/detection.ts`);
|
|
9139
|
-
* (`RecordingTriggers.objectClasses`)
|
|
9140
|
-
*
|
|
9144
|
+
* ONE list. Before today the same three were hand-written in the step's offer
|
|
9145
|
+
* and a second time as the union `FirstLevelMacro`
|
|
9146
|
+
* (`types/detection.ts`); a third copy for the recording trigger
|
|
9147
|
+
* (`RecordingTriggers.objectClasses`) would have made the later divergence
|
|
9148
|
+
* invisible.
|
|
9141
9149
|
*/
|
|
9142
9150
|
var FIRST_LEVEL_MACRO_CLASSES = [
|
|
9143
9151
|
"person",
|
|
@@ -9202,17 +9210,17 @@ var RecordingStorageModeSchema = _enum([
|
|
|
9202
9210
|
"on-device-decision"
|
|
9203
9211
|
]);
|
|
9204
9212
|
/**
|
|
9205
|
-
*
|
|
9206
|
-
*
|
|
9213
|
+
* The macro classes that can open a recording window — the same
|
|
9214
|
+
* three offered by the `object-detection` step, from ONE list
|
|
9207
9215
|
* ({@link FIRST_LEVEL_MACRO_CLASSES}).
|
|
9208
9216
|
*/
|
|
9209
9217
|
var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
|
|
9210
9218
|
/**
|
|
9211
|
-
* True
|
|
9219
|
+
* True when `values` does not repeat an element.
|
|
9212
9220
|
*
|
|
9213
|
-
*
|
|
9214
|
-
*
|
|
9215
|
-
*
|
|
9221
|
+
* A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
|
|
9222
|
+
* becomes a SOURCE in `bandTriggerSources`, and the same source twice
|
|
9223
|
+
* would count its windows twice in `segmentMissedByMs`.
|
|
9216
9224
|
*/
|
|
9217
9225
|
var noDuplicates = (values) => new Set(values).size === values.length;
|
|
9218
9226
|
/** Which detectors trigger an `events`-mode band. */
|
|
@@ -9220,34 +9228,34 @@ var RecordingTriggersSchema = object({
|
|
|
9220
9228
|
motion: boolean().optional(),
|
|
9221
9229
|
audioThresholdDbfs: number().optional(),
|
|
9222
9230
|
/**
|
|
9223
|
-
*
|
|
9224
|
-
*
|
|
9225
|
-
*
|
|
9226
|
-
*
|
|
9231
|
+
* The macro classes whose detection opens a window. ABSENT = the source
|
|
9232
|
+
* is not listened to; an EMPTY array is rejected, because "events band, object
|
|
9233
|
+
* trigger on, no class" is the same shape "enabled and records
|
|
9234
|
+
* nothing, forever" that `eventsBandCanEverDemand` is written against.
|
|
9227
9235
|
*
|
|
9228
|
-
*
|
|
9229
|
-
*
|
|
9230
|
-
* `minConfidence<Macro>`
|
|
9231
|
-
* (`source: 'onboard'`)
|
|
9232
|
-
*
|
|
9236
|
+
* The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
|
|
9237
|
+
* those that went through `enabledMacroClasses`, the
|
|
9238
|
+
* `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
|
|
9239
|
+
* (`source: 'onboard'`) goes through none of those gates and does NOT open
|
|
9240
|
+
* windows — see `recorder/object-trigger.ts`.
|
|
9233
9241
|
*/
|
|
9234
9242
|
objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
|
|
9235
9243
|
/**
|
|
9236
|
-
*
|
|
9237
|
-
*
|
|
9244
|
+
* The LINKED devices whose RISING EDGE opens a window. Absent = the source
|
|
9245
|
+
* is not listened to; an empty array is rejected for the same reason as
|
|
9238
9246
|
* `objectClasses`.
|
|
9239
9247
|
*
|
|
9240
|
-
*
|
|
9241
|
-
*
|
|
9242
|
-
*
|
|
9243
|
-
*
|
|
9244
|
-
* device (D12) —
|
|
9248
|
+
* These are SOURCE device ids, not cameras: the band names them, so the
|
|
9249
|
+
* hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
|
|
9250
|
+
* does no RPC. The OFFER from which the operator picks them is another question, and
|
|
9251
|
+
* is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
|
|
9252
|
+
* device (D12) — never a global list of caps.
|
|
9245
9253
|
*
|
|
9246
|
-
*
|
|
9247
|
-
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`)
|
|
9248
|
-
*
|
|
9249
|
-
*
|
|
9250
|
-
*
|
|
9254
|
+
* What "high" means depends on the device TYPE and is not decided here:
|
|
9255
|
+
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
|
|
9256
|
+
* the same one as the composite doorbell (D671). And it is the EDGE, not
|
|
9257
|
+
* the level: a contact found already open at runner restart does not
|
|
9258
|
+
* record.
|
|
9251
9259
|
*/
|
|
9252
9260
|
sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
|
|
9253
9261
|
});
|
|
@@ -10324,7 +10332,7 @@ var DecoderSessionConfigSchema = object({
|
|
|
10324
10332
|
* - **VALUE** — at which level, for which scope, until when. That stays ONE
|
|
10325
10333
|
* thing: the logging settings document on the `system` cap. Two authorities
|
|
10326
10334
|
* over the values is the exact defect
|
|
10327
|
-
* `docs/design/plans/2026-08-26-
|
|
10335
|
+
* `docs/design/plans/2026-08-26-per-component-logging.md` was written to
|
|
10328
10336
|
* remove; re-introducing it from the cure side would be grotesque.
|
|
10329
10337
|
*
|
|
10330
10338
|
* Nothing in this file reads a clock, an env var or a store. The registry is
|
|
@@ -11600,6 +11608,68 @@ method(object({
|
|
|
11600
11608
|
password: string()
|
|
11601
11609
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
11602
11610
|
/**
|
|
11611
|
+
* How long one snapshot may take end to end: the pinned copy of the whole
|
|
11612
|
+
* database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
|
|
11613
|
+
* disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
|
|
11614
|
+
* generous because a timeout fails the whole backup run.
|
|
11615
|
+
*/
|
|
11616
|
+
var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
|
|
11617
|
+
/**
|
|
11618
|
+
* The databases an owner snapshots — declared by the OWNER, so a caller never
|
|
11619
|
+
* guesses which file is live from what sits beside it (a cleanly closed
|
|
11620
|
+
* database has no sidecars and is just as owned). Paths are absolute on the
|
|
11621
|
+
* owner's host.
|
|
11622
|
+
*/
|
|
11623
|
+
var DatabaseSnapshotTargetsSchema = object({ databases: array(object({ livePath: string() })) });
|
|
11624
|
+
/** One b-tree table of the snapshot and the rows it holds. */
|
|
11625
|
+
var DatabaseSnapshotTableSchema = object({
|
|
11626
|
+
name: string(),
|
|
11627
|
+
rows: number().int().nonnegative()
|
|
11628
|
+
});
|
|
11629
|
+
/**
|
|
11630
|
+
* What the owner wrote. Every path is ABSOLUTE on the owner's host — the
|
|
11631
|
+
* caller pins the call to its own node, so it can read the file; a caller
|
|
11632
|
+
* that finds the path outside its own data root refuses it rather than
|
|
11633
|
+
* archiving something it cannot place.
|
|
11634
|
+
*/
|
|
11635
|
+
var DatabaseSnapshotResultSchema = object({
|
|
11636
|
+
/** The live database the snapshot copies. Never to be copied as a file. */
|
|
11637
|
+
livePath: string(),
|
|
11638
|
+
/** The verified copy: `<livePath>` + {@link DATABASE_SNAPSHOT_SUFFIX}. */
|
|
11639
|
+
snapshotPath: string(),
|
|
11640
|
+
sizeBytes: number().int().nonnegative(),
|
|
11641
|
+
pageCount: number().int().nonnegative(),
|
|
11642
|
+
pageSize: number().int().positive(),
|
|
11643
|
+
/**
|
|
11644
|
+
* Every b-tree table with its row count. Read inside the SAME read
|
|
11645
|
+
* transaction the copy was taken from, and found EQUAL on the copy — so
|
|
11646
|
+
* this is the content of the snapshot, not an estimate of the source.
|
|
11647
|
+
*/
|
|
11648
|
+
tables: array(DatabaseSnapshotTableSchema),
|
|
11649
|
+
/** Wall time of the pinned copy (row counts included). */
|
|
11650
|
+
copyMs: number().nonnegative(),
|
|
11651
|
+
/** Wall time of the checks on the copy (`integrity_check`, row counts). */
|
|
11652
|
+
verifyMs: number().nonnegative(),
|
|
11653
|
+
/** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
|
|
11654
|
+
takenAt: number()
|
|
11655
|
+
});
|
|
11656
|
+
/**
|
|
11657
|
+
* A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
|
|
11658
|
+
* the same facts, with both paths relative to the archive root (the node's
|
|
11659
|
+
* data dir), because an archive outlives the host that made it.
|
|
11660
|
+
*/
|
|
11661
|
+
var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
|
|
11662
|
+
/** Archive-relative path of the live database the archive does NOT carry. */
|
|
11663
|
+
livePath: string(),
|
|
11664
|
+
/** Archive-relative path of the verified copy it carries in its place. */
|
|
11665
|
+
snapshotPath: string()
|
|
11666
|
+
});
|
|
11667
|
+
method(object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }), method(object({}), DatabaseSnapshotResultSchema, {
|
|
11668
|
+
kind: "mutation",
|
|
11669
|
+
auth: "admin",
|
|
11670
|
+
timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
|
|
11671
|
+
});
|
|
11672
|
+
/**
|
|
11603
11673
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
11604
11674
|
* `id = <addonId>:<subId>` from its provider lookup so consumers
|
|
11605
11675
|
* (admin UI, restore flow) see one canonical key.
|
|
@@ -11710,7 +11780,12 @@ var ArchiveManifestSchema = object({
|
|
|
11710
11780
|
locations: array(string()),
|
|
11711
11781
|
entries: array(ArchiveEntrySchema),
|
|
11712
11782
|
totalBytes: number(),
|
|
11713
|
-
totalFiles: number()
|
|
11783
|
+
totalFiles: number(),
|
|
11784
|
+
/**
|
|
11785
|
+
* Live SQLite databases this archive carries as their OWNER's verified
|
|
11786
|
+
* snapshot instead of as files (D693). Absent on archives made before.
|
|
11787
|
+
*/
|
|
11788
|
+
sqliteSnapshots: array(ArchiveSqliteSnapshotSchema).optional()
|
|
11714
11789
|
});
|
|
11715
11790
|
var LocationStatSchema = object({
|
|
11716
11791
|
name: string(),
|
|
@@ -11968,7 +12043,7 @@ var BrokerStatusEnum = _enum([
|
|
|
11968
12043
|
"unreachable",
|
|
11969
12044
|
"error"
|
|
11970
12045
|
]);
|
|
11971
|
-
var BrokerInfoSchema
|
|
12046
|
+
var BrokerInfoSchema = object({
|
|
11972
12047
|
/** Stable broker id. Persisted; survives addon restarts. */
|
|
11973
12048
|
id: string(),
|
|
11974
12049
|
/** Addon id of the provider that OWNS this broker.
|
|
@@ -12101,7 +12176,7 @@ var GetStateInputSchema = object({
|
|
|
12101
12176
|
* HA: entity_id (returns the cached entity state). */
|
|
12102
12177
|
key: string()
|
|
12103
12178
|
});
|
|
12104
|
-
method(ListInputSchema, array(BrokerInfoSchema
|
|
12179
|
+
method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
|
|
12105
12180
|
kind: "mutation",
|
|
12106
12181
|
auth: "admin"
|
|
12107
12182
|
}), method(RemoveInputSchema, _void(), {
|
|
@@ -13236,242 +13311,6 @@ var CompositionBlockStateSchema = object({
|
|
|
13236
13311
|
reason: string().optional(),
|
|
13237
13312
|
fields: array(CompositionFieldStateSchema)
|
|
13238
13313
|
});
|
|
13239
|
-
var NUMBER = {
|
|
13240
|
-
kind: "fixed",
|
|
13241
|
-
result: ["number"]
|
|
13242
|
-
};
|
|
13243
|
-
var BOOLEAN = {
|
|
13244
|
-
kind: "fixed",
|
|
13245
|
-
result: ["boolean"]
|
|
13246
|
-
};
|
|
13247
|
-
Object.freeze({
|
|
13248
|
-
min: NUMBER,
|
|
13249
|
-
max: NUMBER,
|
|
13250
|
-
abs: NUMBER,
|
|
13251
|
-
floor: NUMBER,
|
|
13252
|
-
ceil: NUMBER,
|
|
13253
|
-
sqrt: NUMBER,
|
|
13254
|
-
round: NUMBER,
|
|
13255
|
-
pow: NUMBER,
|
|
13256
|
-
clamp: NUMBER,
|
|
13257
|
-
avg: NUMBER,
|
|
13258
|
-
sum: NUMBER,
|
|
13259
|
-
age: NUMBER,
|
|
13260
|
-
convert: NUMBER,
|
|
13261
|
-
coalesce: { kind: "coalesce" },
|
|
13262
|
-
any: BOOLEAN,
|
|
13263
|
-
all: BOOLEAN,
|
|
13264
|
-
within: BOOLEAN,
|
|
13265
|
-
latest: {
|
|
13266
|
-
kind: "fixed",
|
|
13267
|
-
result: ["number", "null"]
|
|
13268
|
-
},
|
|
13269
|
-
number: {
|
|
13270
|
-
kind: "fixed",
|
|
13271
|
-
result: ["number", "null"]
|
|
13272
|
-
},
|
|
13273
|
-
rose: {
|
|
13274
|
-
kind: "fixed",
|
|
13275
|
-
result: ["number", "null"]
|
|
13276
|
-
},
|
|
13277
|
-
count: NUMBER
|
|
13278
|
-
});
|
|
13279
|
-
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
13280
|
-
/**
|
|
13281
|
-
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
13282
|
-
* device of that type, or an existing one that lacks them, can be given. The
|
|
13283
|
-
* blockers are the validator's own refusal codes, and a spec compares this
|
|
13284
|
-
* listing with `planComposition` for every capability — the editor can never
|
|
13285
|
-
* offer a feature the save would refuse for the same reason.
|
|
13286
|
-
*/
|
|
13287
|
-
var ComposableFieldSchema = object({
|
|
13288
|
-
path: string(),
|
|
13289
|
-
kind: CompositionFieldKindSchema,
|
|
13290
|
-
nullable: boolean(),
|
|
13291
|
-
required: boolean(),
|
|
13292
|
-
enumValues: array(string()).optional()
|
|
13293
|
-
});
|
|
13294
|
-
var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
13295
|
-
cap: string(),
|
|
13296
|
-
fields: array(ComposableFieldSchema),
|
|
13297
|
-
/** Present for an item-array cap (`consumables.items`). */
|
|
13298
|
-
itemArray: object({
|
|
13299
|
-
path: string(),
|
|
13300
|
-
keyField: string()
|
|
13301
|
-
}).optional()
|
|
13302
|
-
})) });
|
|
13303
|
-
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
13304
|
-
* agent is the reason placement is not fixed to the hub. */
|
|
13305
|
-
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
13306
|
-
/** What a block's process is doing. Mirrors the addon runner's own lifecycle so
|
|
13307
|
-
* a failing block reads the same way a failing addon does. `degraded` is a
|
|
13308
|
-
* composition on an existing device with a field handed back to the native
|
|
13309
|
-
* provider while its source is unavailable (S1b, D663); the error names it. */
|
|
13310
|
-
var CoreBlockStatusSchema = _enum([
|
|
13311
|
-
"stopped",
|
|
13312
|
-
"starting",
|
|
13313
|
-
"running",
|
|
13314
|
-
"degraded",
|
|
13315
|
-
"failed"
|
|
13316
|
-
]);
|
|
13317
|
-
/** Client-authored fields. */
|
|
13318
|
-
var CoreBlockInputSchema = object({
|
|
13319
|
-
name: string().min(1).max(120),
|
|
13320
|
-
/** TypeScript source. Compiled server-side before it is ever stored — a
|
|
13321
|
-
* block that does not compile is a fork failure the operator would meet
|
|
13322
|
-
* minutes later, in a log, instead of in the editor. */
|
|
13323
|
-
code: string().max(2e5),
|
|
13324
|
-
enabled: boolean(),
|
|
13325
|
-
placement: CoreBlockPlacementSchema,
|
|
13326
|
-
/**
|
|
13327
|
-
* Integration the block's devices hang from. Absent = the system integration
|
|
13328
|
-
* blocks share. A block may declare its own instead.
|
|
13329
|
-
*/
|
|
13330
|
-
integrationId: string().optional()
|
|
13331
|
-
});
|
|
13332
|
-
/**
|
|
13333
|
-
* What a block IS (D659). Absent means `code` — every row stored before this
|
|
13334
|
-
* union keeps working unchanged.
|
|
13335
|
-
* - `code`: the TypeScript in `code`, compiled and run in its own runner;
|
|
13336
|
-
* - `recipe`: RESERVED (automations), stored shape only; refused at run by name;
|
|
13337
|
-
* - `composition`: declarative, run by the shared `composer`; `code` is `''`.
|
|
13338
|
-
*/
|
|
13339
|
-
var CoreBlockSourceSchema = discriminatedUnion("kind", [
|
|
13340
|
-
object({ kind: literal("code") }),
|
|
13341
|
-
object({
|
|
13342
|
-
kind: literal("recipe"),
|
|
13343
|
-
recipe: AutomationRecipeSchema
|
|
13344
|
-
}),
|
|
13345
|
-
object({
|
|
13346
|
-
kind: literal("composition"),
|
|
13347
|
-
composition: CompositionSchema
|
|
13348
|
-
})
|
|
13349
|
-
]);
|
|
13350
|
-
/**
|
|
13351
|
-
* The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7).
|
|
13352
|
-
*
|
|
13353
|
-
* `name`: REQUIRED for a `new` target — the block's name IS the device's name
|
|
13354
|
-
* (D659). ABSENT for an `existing` target — a customization has no name of its
|
|
13355
|
-
* own; the server derives one (`customizationBlockName`, D663) and refuses a
|
|
13356
|
-
* client-sent name by name.
|
|
13357
|
-
*/
|
|
13358
|
-
var CompositionBlockInputSchema = object({
|
|
13359
|
-
name: string().min(1).max(120).optional(),
|
|
13360
|
-
enabled: boolean(),
|
|
13361
|
-
composition: CompositionSchema
|
|
13362
|
-
});
|
|
13363
|
-
/** A stored block. */
|
|
13364
|
-
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
13365
|
-
id: string(),
|
|
13366
|
-
createdAt: number(),
|
|
13367
|
-
updatedAt: number(),
|
|
13368
|
-
/** Server-stamped author. */
|
|
13369
|
-
createdBy: string(),
|
|
13370
|
-
status: CoreBlockStatusSchema,
|
|
13371
|
-
/**
|
|
13372
|
-
* Why the block is not running, when it is not. The operator's ONLY window
|
|
13373
|
-
* into a block that failed at load — a block that is silently absent is the
|
|
13374
|
-
* failure mode this whole feature has to avoid.
|
|
13375
|
-
*/
|
|
13376
|
-
lastError: string().optional(),
|
|
13377
|
-
/** Ms epoch of the last state change. */
|
|
13378
|
-
lastChangedAt: number(),
|
|
13379
|
-
/** What the block is. Absent means `code` (D659). */
|
|
13380
|
-
source: CoreBlockSourceSchema.optional()
|
|
13381
|
-
});
|
|
13382
|
-
/** A stored composition block and what the composer says about it. */
|
|
13383
|
-
var CompositionViewSchema = object({
|
|
13384
|
-
block: CoreBlockSchema,
|
|
13385
|
-
state: discriminatedUnion("kind", [object({
|
|
13386
|
-
kind: literal("answered"),
|
|
13387
|
-
state: CompositionBlockStateSchema.nullable()
|
|
13388
|
-
}), object({
|
|
13389
|
-
kind: literal("unreachable"),
|
|
13390
|
-
error: string()
|
|
13391
|
-
})])
|
|
13392
|
-
});
|
|
13393
|
-
/**
|
|
13394
|
-
* A read of the stored compositions. `not-loaded` while the `core_blocks`
|
|
13395
|
-
* table has not been READ: an empty answer then would make "not yet known"
|
|
13396
|
-
* look like "none", and invite the operator to recreate what exists (D315).
|
|
13397
|
-
*/
|
|
13398
|
-
var CompositionsNotLoadedSchema = object({
|
|
13399
|
-
state: literal("not-loaded"),
|
|
13400
|
-
reason: string()
|
|
13401
|
-
});
|
|
13402
|
-
var CompositionListReadSchema = discriminatedUnion("state", [object({
|
|
13403
|
-
state: literal("loaded"),
|
|
13404
|
-
views: array(CompositionViewSchema)
|
|
13405
|
-
}), CompositionsNotLoadedSchema]);
|
|
13406
|
-
var CompositionGetReadSchema = discriminatedUnion("state", [object({
|
|
13407
|
-
state: literal("loaded"),
|
|
13408
|
-
view: CompositionViewSchema.nullable()
|
|
13409
|
-
}), CompositionsNotLoadedSchema]);
|
|
13410
|
-
/** The customization of one existing device, found by its TARGET, or `not-loaded` (D315). */
|
|
13411
|
-
var CompositionCustomizationReadSchema = discriminatedUnion("state", [object({
|
|
13412
|
-
state: literal("loaded"),
|
|
13413
|
-
view: CompositionViewSchema.nullable()
|
|
13414
|
-
}), CompositionsNotLoadedSchema]);
|
|
13415
|
-
/** What a compile attempt produced. */
|
|
13416
|
-
var CoreBlockCompileResultSchema = object({
|
|
13417
|
-
ok: boolean(),
|
|
13418
|
-
/** Present when `ok` is false — the first error, in the author's words. */
|
|
13419
|
-
error: string().optional(),
|
|
13420
|
-
line: number().optional(),
|
|
13421
|
-
column: number().optional()
|
|
13422
|
-
});
|
|
13423
|
-
method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }), method(object({ blockId: string() }), object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }), method(object({ block: CoreBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13424
|
-
kind: "mutation",
|
|
13425
|
-
auth: "admin",
|
|
13426
|
-
caller: "required"
|
|
13427
|
-
}), method(object({
|
|
13428
|
-
blockId: string(),
|
|
13429
|
-
block: CoreBlockInputSchema.partial()
|
|
13430
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13431
|
-
kind: "mutation",
|
|
13432
|
-
auth: "admin",
|
|
13433
|
-
caller: "required"
|
|
13434
|
-
}), method(object({ blockId: string() }), object({ success: literal(true) }), {
|
|
13435
|
-
kind: "mutation",
|
|
13436
|
-
auth: "admin"
|
|
13437
|
-
}), method(object({
|
|
13438
|
-
blockId: string(),
|
|
13439
|
-
enabled: boolean()
|
|
13440
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13441
|
-
kind: "mutation",
|
|
13442
|
-
auth: "admin"
|
|
13443
|
-
}), method(object({ blockId: string() }), object({ block: CoreBlockSchema }), {
|
|
13444
|
-
kind: "mutation",
|
|
13445
|
-
auth: "admin"
|
|
13446
|
-
}), method(object({ code: string() }), CoreBlockCompileResultSchema, {
|
|
13447
|
-
kind: "mutation",
|
|
13448
|
-
auth: "admin"
|
|
13449
|
-
}), method(object({}), object({ libs: array(object({
|
|
13450
|
-
filePath: string(),
|
|
13451
|
-
content: string()
|
|
13452
|
-
})) }), { auth: "admin" }), method(object({ block: CompositionBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13453
|
-
kind: "mutation",
|
|
13454
|
-
auth: "admin",
|
|
13455
|
-
caller: "required"
|
|
13456
|
-
}), method(object({
|
|
13457
|
-
blockId: string(),
|
|
13458
|
-
expectedUpdatedAt: number(),
|
|
13459
|
-
block: CompositionBlockInputSchema.partial()
|
|
13460
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13461
|
-
kind: "mutation",
|
|
13462
|
-
auth: "admin",
|
|
13463
|
-
caller: "required"
|
|
13464
|
-
}), method(object({ blockId: string() }), CompositionGetReadSchema, { auth: "admin" }), method(object({}), CompositionListReadSchema, { auth: "admin" }), method(object({
|
|
13465
|
-
addonId: string().min(1),
|
|
13466
|
-
stableId: string().min(1)
|
|
13467
|
-
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({ deviceType: _enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }), method(object({
|
|
13468
|
-
composition: CompositionSchema,
|
|
13469
|
-
blockId: string().optional()
|
|
13470
|
-
}), CompositionValidationSchema, {
|
|
13471
|
-
kind: "mutation",
|
|
13472
|
-
auth: "admin",
|
|
13473
|
-
access: "view"
|
|
13474
|
-
});
|
|
13475
13314
|
var ComposerBlockSchema = object({
|
|
13476
13315
|
id: string().min(1),
|
|
13477
13316
|
name: string().min(1).max(120),
|
|
@@ -13518,6 +13357,242 @@ method(object({
|
|
|
13518
13357
|
kind: "mutation",
|
|
13519
13358
|
auth: "admin"
|
|
13520
13359
|
}), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
13360
|
+
var NUMBER = {
|
|
13361
|
+
kind: "fixed",
|
|
13362
|
+
result: ["number"]
|
|
13363
|
+
};
|
|
13364
|
+
var BOOLEAN = {
|
|
13365
|
+
kind: "fixed",
|
|
13366
|
+
result: ["boolean"]
|
|
13367
|
+
};
|
|
13368
|
+
Object.freeze({
|
|
13369
|
+
min: NUMBER,
|
|
13370
|
+
max: NUMBER,
|
|
13371
|
+
abs: NUMBER,
|
|
13372
|
+
floor: NUMBER,
|
|
13373
|
+
ceil: NUMBER,
|
|
13374
|
+
sqrt: NUMBER,
|
|
13375
|
+
round: NUMBER,
|
|
13376
|
+
pow: NUMBER,
|
|
13377
|
+
clamp: NUMBER,
|
|
13378
|
+
avg: NUMBER,
|
|
13379
|
+
sum: NUMBER,
|
|
13380
|
+
age: NUMBER,
|
|
13381
|
+
convert: NUMBER,
|
|
13382
|
+
coalesce: { kind: "coalesce" },
|
|
13383
|
+
any: BOOLEAN,
|
|
13384
|
+
all: BOOLEAN,
|
|
13385
|
+
within: BOOLEAN,
|
|
13386
|
+
latest: {
|
|
13387
|
+
kind: "fixed",
|
|
13388
|
+
result: ["number", "null"]
|
|
13389
|
+
},
|
|
13390
|
+
number: {
|
|
13391
|
+
kind: "fixed",
|
|
13392
|
+
result: ["number", "null"]
|
|
13393
|
+
},
|
|
13394
|
+
rose: {
|
|
13395
|
+
kind: "fixed",
|
|
13396
|
+
result: ["number", "null"]
|
|
13397
|
+
},
|
|
13398
|
+
count: NUMBER
|
|
13399
|
+
});
|
|
13400
|
+
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
13401
|
+
/**
|
|
13402
|
+
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
13403
|
+
* device of that type, or an existing one that lacks them, can be given. The
|
|
13404
|
+
* blockers are the validator's own refusal codes, and a spec compares this
|
|
13405
|
+
* listing with `planComposition` for every capability — the editor can never
|
|
13406
|
+
* offer a feature the save would refuse for the same reason.
|
|
13407
|
+
*/
|
|
13408
|
+
var ComposableFieldSchema = object({
|
|
13409
|
+
path: string(),
|
|
13410
|
+
kind: CompositionFieldKindSchema,
|
|
13411
|
+
nullable: boolean(),
|
|
13412
|
+
required: boolean(),
|
|
13413
|
+
enumValues: array(string()).optional()
|
|
13414
|
+
});
|
|
13415
|
+
var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
13416
|
+
cap: string(),
|
|
13417
|
+
fields: array(ComposableFieldSchema),
|
|
13418
|
+
/** Present for an item-array cap (`consumables.items`). */
|
|
13419
|
+
itemArray: object({
|
|
13420
|
+
path: string(),
|
|
13421
|
+
keyField: string()
|
|
13422
|
+
}).optional()
|
|
13423
|
+
})) });
|
|
13424
|
+
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
13425
|
+
* agent is the reason placement is not fixed to the hub. */
|
|
13426
|
+
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
13427
|
+
/** What a block's process is doing. Mirrors the addon runner's own lifecycle so
|
|
13428
|
+
* a failing block reads the same way a failing addon does. `degraded` is a
|
|
13429
|
+
* composition on an existing device with a field handed back to the native
|
|
13430
|
+
* provider while its source is unavailable (S1b, D663); the error names it. */
|
|
13431
|
+
var CoreBlockStatusSchema = _enum([
|
|
13432
|
+
"stopped",
|
|
13433
|
+
"starting",
|
|
13434
|
+
"running",
|
|
13435
|
+
"degraded",
|
|
13436
|
+
"failed"
|
|
13437
|
+
]);
|
|
13438
|
+
/** Client-authored fields. */
|
|
13439
|
+
var CoreBlockInputSchema = object({
|
|
13440
|
+
name: string().min(1).max(120),
|
|
13441
|
+
/** TypeScript source. Compiled server-side before it is ever stored — a
|
|
13442
|
+
* block that does not compile is a fork failure the operator would meet
|
|
13443
|
+
* minutes later, in a log, instead of in the editor. */
|
|
13444
|
+
code: string().max(2e5),
|
|
13445
|
+
enabled: boolean(),
|
|
13446
|
+
placement: CoreBlockPlacementSchema,
|
|
13447
|
+
/**
|
|
13448
|
+
* Integration the block's devices hang from. Absent = the system integration
|
|
13449
|
+
* blocks share. A block may declare its own instead.
|
|
13450
|
+
*/
|
|
13451
|
+
integrationId: string().optional()
|
|
13452
|
+
});
|
|
13453
|
+
/**
|
|
13454
|
+
* What a block IS (D659). Absent means `code` — every row stored before this
|
|
13455
|
+
* union keeps working unchanged.
|
|
13456
|
+
* - `code`: the TypeScript in `code`, compiled and run in its own runner;
|
|
13457
|
+
* - `recipe`: RESERVED (automations), stored shape only; refused at run by name;
|
|
13458
|
+
* - `composition`: declarative, run by the shared `composer`; `code` is `''`.
|
|
13459
|
+
*/
|
|
13460
|
+
var CoreBlockSourceSchema = discriminatedUnion("kind", [
|
|
13461
|
+
object({ kind: literal("code") }),
|
|
13462
|
+
object({
|
|
13463
|
+
kind: literal("recipe"),
|
|
13464
|
+
recipe: AutomationRecipeSchema
|
|
13465
|
+
}),
|
|
13466
|
+
object({
|
|
13467
|
+
kind: literal("composition"),
|
|
13468
|
+
composition: CompositionSchema
|
|
13469
|
+
})
|
|
13470
|
+
]);
|
|
13471
|
+
/**
|
|
13472
|
+
* The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7).
|
|
13473
|
+
*
|
|
13474
|
+
* `name`: REQUIRED for a `new` target — the block's name IS the device's name
|
|
13475
|
+
* (D659). ABSENT for an `existing` target — a customization has no name of its
|
|
13476
|
+
* own; the server derives one (`customizationBlockName`, D663) and refuses a
|
|
13477
|
+
* client-sent name by name.
|
|
13478
|
+
*/
|
|
13479
|
+
var CompositionBlockInputSchema = object({
|
|
13480
|
+
name: string().min(1).max(120).optional(),
|
|
13481
|
+
enabled: boolean(),
|
|
13482
|
+
composition: CompositionSchema
|
|
13483
|
+
});
|
|
13484
|
+
/** A stored block. */
|
|
13485
|
+
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
13486
|
+
id: string(),
|
|
13487
|
+
createdAt: number(),
|
|
13488
|
+
updatedAt: number(),
|
|
13489
|
+
/** Server-stamped author. */
|
|
13490
|
+
createdBy: string(),
|
|
13491
|
+
status: CoreBlockStatusSchema,
|
|
13492
|
+
/**
|
|
13493
|
+
* Why the block is not running, when it is not. The operator's ONLY window
|
|
13494
|
+
* into a block that failed at load — a block that is silently absent is the
|
|
13495
|
+
* failure mode this whole feature has to avoid.
|
|
13496
|
+
*/
|
|
13497
|
+
lastError: string().optional(),
|
|
13498
|
+
/** Ms epoch of the last state change. */
|
|
13499
|
+
lastChangedAt: number(),
|
|
13500
|
+
/** What the block is. Absent means `code` (D659). */
|
|
13501
|
+
source: CoreBlockSourceSchema.optional()
|
|
13502
|
+
});
|
|
13503
|
+
/** A stored composition block and what the composer says about it. */
|
|
13504
|
+
var CompositionViewSchema = object({
|
|
13505
|
+
block: CoreBlockSchema,
|
|
13506
|
+
state: discriminatedUnion("kind", [object({
|
|
13507
|
+
kind: literal("answered"),
|
|
13508
|
+
state: CompositionBlockStateSchema.nullable()
|
|
13509
|
+
}), object({
|
|
13510
|
+
kind: literal("unreachable"),
|
|
13511
|
+
error: string()
|
|
13512
|
+
})])
|
|
13513
|
+
});
|
|
13514
|
+
/**
|
|
13515
|
+
* A read of the stored compositions. `not-loaded` while the `core_blocks`
|
|
13516
|
+
* table has not been READ: an empty answer then would make "not yet known"
|
|
13517
|
+
* look like "none", and invite the operator to recreate what exists (D315).
|
|
13518
|
+
*/
|
|
13519
|
+
var CompositionsNotLoadedSchema = object({
|
|
13520
|
+
state: literal("not-loaded"),
|
|
13521
|
+
reason: string()
|
|
13522
|
+
});
|
|
13523
|
+
var CompositionListReadSchema = discriminatedUnion("state", [object({
|
|
13524
|
+
state: literal("loaded"),
|
|
13525
|
+
views: array(CompositionViewSchema)
|
|
13526
|
+
}), CompositionsNotLoadedSchema]);
|
|
13527
|
+
var CompositionGetReadSchema = discriminatedUnion("state", [object({
|
|
13528
|
+
state: literal("loaded"),
|
|
13529
|
+
view: CompositionViewSchema.nullable()
|
|
13530
|
+
}), CompositionsNotLoadedSchema]);
|
|
13531
|
+
/** The customization of one existing device, found by its TARGET, or `not-loaded` (D315). */
|
|
13532
|
+
var CompositionCustomizationReadSchema = discriminatedUnion("state", [object({
|
|
13533
|
+
state: literal("loaded"),
|
|
13534
|
+
view: CompositionViewSchema.nullable()
|
|
13535
|
+
}), CompositionsNotLoadedSchema]);
|
|
13536
|
+
/** What a compile attempt produced. */
|
|
13537
|
+
var CoreBlockCompileResultSchema = object({
|
|
13538
|
+
ok: boolean(),
|
|
13539
|
+
/** Present when `ok` is false — the first error, in the author's words. */
|
|
13540
|
+
error: string().optional(),
|
|
13541
|
+
line: number().optional(),
|
|
13542
|
+
column: number().optional()
|
|
13543
|
+
});
|
|
13544
|
+
method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }), method(object({ blockId: string() }), object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }), method(object({ block: CoreBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13545
|
+
kind: "mutation",
|
|
13546
|
+
auth: "admin",
|
|
13547
|
+
caller: "required"
|
|
13548
|
+
}), method(object({
|
|
13549
|
+
blockId: string(),
|
|
13550
|
+
block: CoreBlockInputSchema.partial()
|
|
13551
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13552
|
+
kind: "mutation",
|
|
13553
|
+
auth: "admin",
|
|
13554
|
+
caller: "required"
|
|
13555
|
+
}), method(object({ blockId: string() }), object({ success: literal(true) }), {
|
|
13556
|
+
kind: "mutation",
|
|
13557
|
+
auth: "admin"
|
|
13558
|
+
}), method(object({
|
|
13559
|
+
blockId: string(),
|
|
13560
|
+
enabled: boolean()
|
|
13561
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13562
|
+
kind: "mutation",
|
|
13563
|
+
auth: "admin"
|
|
13564
|
+
}), method(object({ blockId: string() }), object({ block: CoreBlockSchema }), {
|
|
13565
|
+
kind: "mutation",
|
|
13566
|
+
auth: "admin"
|
|
13567
|
+
}), method(object({ code: string() }), CoreBlockCompileResultSchema, {
|
|
13568
|
+
kind: "mutation",
|
|
13569
|
+
auth: "admin"
|
|
13570
|
+
}), method(object({}), object({ libs: array(object({
|
|
13571
|
+
filePath: string(),
|
|
13572
|
+
content: string()
|
|
13573
|
+
})) }), { auth: "admin" }), method(object({ block: CompositionBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13574
|
+
kind: "mutation",
|
|
13575
|
+
auth: "admin",
|
|
13576
|
+
caller: "required"
|
|
13577
|
+
}), method(object({
|
|
13578
|
+
blockId: string(),
|
|
13579
|
+
expectedUpdatedAt: number(),
|
|
13580
|
+
block: CompositionBlockInputSchema.partial()
|
|
13581
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13582
|
+
kind: "mutation",
|
|
13583
|
+
auth: "admin",
|
|
13584
|
+
caller: "required"
|
|
13585
|
+
}), method(object({ blockId: string() }), CompositionGetReadSchema, { auth: "admin" }), method(object({}), CompositionListReadSchema, { auth: "admin" }), method(object({
|
|
13586
|
+
addonId: string().min(1),
|
|
13587
|
+
stableId: string().min(1)
|
|
13588
|
+
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({ deviceType: _enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }), method(object({
|
|
13589
|
+
composition: CompositionSchema,
|
|
13590
|
+
blockId: string().optional()
|
|
13591
|
+
}), CompositionValidationSchema, {
|
|
13592
|
+
kind: "mutation",
|
|
13593
|
+
auth: "admin",
|
|
13594
|
+
access: "view"
|
|
13595
|
+
});
|
|
13521
13596
|
/**
|
|
13522
13597
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
13523
13598
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -13812,7 +13887,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
13812
13887
|
*
|
|
13813
13888
|
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
13814
13889
|
* was wrong — corrected 2026-08-26 after the hop map
|
|
13815
|
-
* (`docs/design/2026-08-26-
|
|
13890
|
+
* (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
|
|
13816
13891
|
* There is **no Zod parse at all** between the door and the engine: the
|
|
13817
13892
|
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
13818
13893
|
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
@@ -14675,7 +14750,17 @@ var SiteZoneSchema = object({
|
|
|
14675
14750
|
var ProviderStatusSchema = object({
|
|
14676
14751
|
connected: boolean(),
|
|
14677
14752
|
deviceCount: number(),
|
|
14678
|
-
error: string().optional()
|
|
14753
|
+
error: string().optional(),
|
|
14754
|
+
/**
|
|
14755
|
+
* `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
|
|
14756
|
+
* — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
|
|
14757
|
+
* which every provider bundles, so only a provider BUILT from D696-amended
|
|
14758
|
+
* code says it. ABSENT means an older provider that may still write it (raw
|
|
14759
|
+
* VMD writes, a boot seed), and the orchestrator's provider gate keeps that
|
|
14760
|
+
* provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
|
|
14761
|
+
* — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
|
|
14762
|
+
*/
|
|
14763
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
14679
14764
|
});
|
|
14680
14765
|
object({
|
|
14681
14766
|
externalId: string(),
|
|
@@ -15554,6 +15639,121 @@ method(object({
|
|
|
15554
15639
|
deviceIds: array(number()).readonly(),
|
|
15555
15640
|
caps: array(string()).readonly().optional()
|
|
15556
15641
|
}), record(string(), record(string(), unknown().nullable())));
|
|
15642
|
+
var ExtensionSlotIdSchema = _enum(["linked-devices"]);
|
|
15643
|
+
DeviceType.Camera;
|
|
15644
|
+
/** A slot's editable value, discriminated on `slot`. */
|
|
15645
|
+
var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
15646
|
+
DeviceType.Camera;
|
|
15647
|
+
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
15648
|
+
state: literal("unreachable"),
|
|
15649
|
+
reason: string()
|
|
15650
|
+
})]);
|
|
15651
|
+
/** One provider of slots — the D554 source-listing row. */
|
|
15652
|
+
var ExtensionSourceSchema = object({
|
|
15653
|
+
/** The routing prefix of every `slotRef` this provider serves. */
|
|
15654
|
+
source: string(),
|
|
15655
|
+
label: string(),
|
|
15656
|
+
/** Stamped by the dispatcher from the registry (D557). */
|
|
15657
|
+
addonId: string().optional(),
|
|
15658
|
+
availability: ExtensionSourceAvailabilitySchema
|
|
15659
|
+
});
|
|
15660
|
+
/**
|
|
15661
|
+
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
15662
|
+
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
15663
|
+
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
15664
|
+
* valid source now (a container, which is never a pick). A source in any of
|
|
15665
|
+
* these states is SHOWN, never silently dropped or re-pointed.
|
|
15666
|
+
*/
|
|
15667
|
+
var ExtensionSourceHealthSchema = _enum([
|
|
15668
|
+
"ok",
|
|
15669
|
+
"missing",
|
|
15670
|
+
"foreign",
|
|
15671
|
+
"unavailable"
|
|
15672
|
+
]);
|
|
15673
|
+
var ExtensionSlotSourceSchema = object({
|
|
15674
|
+
deviceId: number().int(),
|
|
15675
|
+
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
15676
|
+
name: string().nullable(),
|
|
15677
|
+
health: ExtensionSourceHealthSchema,
|
|
15678
|
+
detail: string().optional()
|
|
15679
|
+
});
|
|
15680
|
+
/**
|
|
15681
|
+
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
15682
|
+
* reported read-only, named, never written through this contract (D62) — e.g.
|
|
15683
|
+
* a slot whose sources act only while a wrapper is bound to the host, a
|
|
15684
|
+
* binding that belongs to `deviceManager.setWrapperActive`. No slot reports
|
|
15685
|
+
* one today (`linked-devices` answers `null`). `unknown` means the gate could
|
|
15686
|
+
* not be read; it is not "inactive" (D315).
|
|
15687
|
+
*/
|
|
15688
|
+
var ExtensionSlotActivationSchema = object({
|
|
15689
|
+
state: _enum([
|
|
15690
|
+
"active",
|
|
15691
|
+
"inactive",
|
|
15692
|
+
"unknown"
|
|
15693
|
+
]),
|
|
15694
|
+
authority: string(),
|
|
15695
|
+
detail: string().optional()
|
|
15696
|
+
});
|
|
15697
|
+
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
15698
|
+
state: literal("ok"),
|
|
15699
|
+
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
15700
|
+
slotRef: string(),
|
|
15701
|
+
slot: ExtensionSlotIdSchema,
|
|
15702
|
+
/** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
|
|
15703
|
+
authority: string(),
|
|
15704
|
+
activation: ExtensionSlotActivationSchema.nullable(),
|
|
15705
|
+
value: ExtensionSlotValueSchema,
|
|
15706
|
+
sources: array(ExtensionSlotSourceSchema),
|
|
15707
|
+
/**
|
|
15708
|
+
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
15709
|
+
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
15710
|
+
* the child a picked container stands for (D356 — a container is never a
|
|
15711
|
+
* pick, its children are). Read-only; the editor shows them and may offer
|
|
15712
|
+
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
15713
|
+
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
15714
|
+
* older than D655.
|
|
15715
|
+
*/
|
|
15716
|
+
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
15717
|
+
}), object({
|
|
15718
|
+
state: literal("unreachable"),
|
|
15719
|
+
addonId: string(),
|
|
15720
|
+
reason: string()
|
|
15721
|
+
})]);
|
|
15722
|
+
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
15723
|
+
deviceId: number().int(),
|
|
15724
|
+
name: string(),
|
|
15725
|
+
type: string(),
|
|
15726
|
+
location: string().nullable(),
|
|
15727
|
+
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
15728
|
+
parentName: string().nullable(),
|
|
15729
|
+
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
15730
|
+
suggested: boolean(),
|
|
15731
|
+
/** Why it is suggested ("same location"), null when it is not. */
|
|
15732
|
+
reason: string().nullable()
|
|
15733
|
+
})) });
|
|
15734
|
+
/**
|
|
15735
|
+
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
15736
|
+
* reloaded the host (or, for an accessory child, its parent) because the
|
|
15737
|
+
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
15738
|
+
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
15739
|
+
*/
|
|
15740
|
+
var ExtensionSetResultSchema = object({
|
|
15741
|
+
applied: literal(true),
|
|
15742
|
+
reload: _enum([
|
|
15743
|
+
"none",
|
|
15744
|
+
"host",
|
|
15745
|
+
"parent"
|
|
15746
|
+
])
|
|
15747
|
+
});
|
|
15748
|
+
var ExtensionSlotRefInputSchema = object({
|
|
15749
|
+
deviceId: number().int(),
|
|
15750
|
+
slotRef: string().min(1)
|
|
15751
|
+
});
|
|
15752
|
+
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
15753
|
+
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
15754
|
+
kind: "mutation",
|
|
15755
|
+
auth: "admin"
|
|
15756
|
+
});
|
|
15557
15757
|
/**
|
|
15558
15758
|
* Per-field ownership (D663). A composition may CLAIM fields of a native
|
|
15559
15759
|
* cap's runtime-state slice on an existing device: `replace` overlays the
|
|
@@ -15777,7 +15977,7 @@ method(object({
|
|
|
15777
15977
|
* per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
|
|
15778
15978
|
* ends in a log line, and a log line is the thing the operator asked to stop
|
|
15779
15979
|
* needing: *"possiamo armare questi errori intanto? Così al prossimo giro
|
|
15780
|
-
* ricontrolliamo tutti questi punti"
|
|
15980
|
+
* 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
|
|
15781
15981
|
* hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
|
|
15782
15982
|
* media blackout were both diagnosed. The counters stay; this is where they can
|
|
15783
15983
|
* be READ.
|
|
@@ -17153,7 +17353,7 @@ var BrokerStatusSchema$1 = _enum([
|
|
|
17153
17353
|
"unreachable",
|
|
17154
17354
|
"tls-error"
|
|
17155
17355
|
]);
|
|
17156
|
-
var BrokerInfoSchema = object({
|
|
17356
|
+
var BrokerInfoSchema$1 = object({
|
|
17157
17357
|
id: string(),
|
|
17158
17358
|
name: string(),
|
|
17159
17359
|
url: string(),
|
|
@@ -17216,7 +17416,7 @@ var StatusSchema = object({
|
|
|
17216
17416
|
brokerCount: number(),
|
|
17217
17417
|
embeddedRunning: boolean()
|
|
17218
17418
|
});
|
|
17219
|
-
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17419
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17220
17420
|
kind: "mutation",
|
|
17221
17421
|
auth: "admin"
|
|
17222
17422
|
}), method(IdInputSchema, _void(), {
|
|
@@ -18564,17 +18764,25 @@ var NcScheduleSchema = object({
|
|
|
18564
18764
|
*/
|
|
18565
18765
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
18566
18766
|
/**
|
|
18767
|
+
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
18768
|
+
* every section; `section` = one notification per section with something to
|
|
18769
|
+
* say (an unavailable section included), each titled by its section.
|
|
18770
|
+
*/
|
|
18771
|
+
var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
18772
|
+
/**
|
|
18567
18773
|
* `summary`: the rule sends NOTHING per event. When a window of `schedule`
|
|
18568
18774
|
* CLOSES, it sends one notification with the current state of its kinds
|
|
18569
18775
|
* (low batteries, consumables to replace, devices offline, updates
|
|
18570
|
-
* available, ...), after its own filters
|
|
18776
|
+
* available, ...), after its own filters — or, with `split: 'section'`
|
|
18777
|
+
* (D698), one notification per section. Nothing to report sends nothing.
|
|
18571
18778
|
* The schedule is the ordinary `NcSchedule` (weekly windows, IANA timezone,
|
|
18572
18779
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
18573
18780
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
18574
18781
|
*/
|
|
18575
18782
|
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [object({ mode: literal("instant") }), object({
|
|
18576
18783
|
mode: literal("summary"),
|
|
18577
|
-
schedule: NcScheduleSchema
|
|
18784
|
+
schedule: NcScheduleSchema,
|
|
18785
|
+
split: NcStateSummarySplitSchema.optional()
|
|
18578
18786
|
})]);
|
|
18579
18787
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
18580
18788
|
var NcPlateMatcherSchema = object({
|
|
@@ -18714,8 +18922,14 @@ var NcSensorTransitionSchema = _enum(["raised", "cleared"]);
|
|
|
18714
18922
|
/** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
|
|
18715
18923
|
var NcZoneConditionSchema = object({
|
|
18716
18924
|
ids: array(string().min(1)).min(1),
|
|
18717
|
-
/**
|
|
18718
|
-
|
|
18925
|
+
/**
|
|
18926
|
+
* LEGACY quantifier over `ids`. Absent = `any` (at least one visited), which
|
|
18927
|
+
* is what both editors mean and all they write since D690: "all of" was
|
|
18928
|
+
* removed from the editors because on an immediate rule it asked one
|
|
18929
|
+
* detection to stand in every zone at once. Still ACCEPTED, and `all` still
|
|
18930
|
+
* evaluated, so a stored rule keeps parsing and meaning what it meant.
|
|
18931
|
+
*/
|
|
18932
|
+
match: _enum(["any", "all"]).optional()
|
|
18719
18933
|
});
|
|
18720
18934
|
/**
|
|
18721
18935
|
* The P1 condition set — a flat AND of groups; absent group = pass;
|
|
@@ -19219,10 +19433,12 @@ var NcMediaPolicySchema = object({
|
|
|
19219
19433
|
/**
|
|
19220
19434
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
19221
19435
|
* notification suppresses.
|
|
19222
|
-
* - `
|
|
19223
|
-
*
|
|
19224
|
-
*
|
|
19225
|
-
*
|
|
19436
|
+
* - `per-class` (default, and the absent value since 2026-10-01 — D36) — an
|
|
19437
|
+
* independent window per detected class: cat→dog fires at once, cat→cat
|
|
19438
|
+
* still waits.
|
|
19439
|
+
* - `shared` — one window for the whole rule/scope: a cat silences the next
|
|
19440
|
+
* dog for `cooldownSec`. Only written when an operator picks it; it is no
|
|
19441
|
+
* longer what an unset rule means.
|
|
19226
19442
|
*
|
|
19227
19443
|
* AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
|
|
19228
19444
|
* must not be swallowed by a bark's window (the precedent this generalizes —
|
|
@@ -19237,8 +19453,11 @@ var NcThrottleSchema = object({
|
|
|
19237
19453
|
/**
|
|
19238
19454
|
* Class granularity of the cooldown key. Optional rather than defaulted:
|
|
19239
19455
|
* a Zod default does NOT run on the addon→addon cap path, so a persisted
|
|
19240
|
-
* rule authored before this field simply carries none
|
|
19241
|
-
*
|
|
19456
|
+
* rule authored before this field simply carries none. The engine used to
|
|
19457
|
+
* read absent as `shared` (D36); since 2026-10-01 it reads absent as
|
|
19458
|
+
* `per-class` — the operator's default — and only an explicit `shared`
|
|
19459
|
+
* still means `shared`. See `cooldownKey` / `keysPerClass` in the rule
|
|
19460
|
+
* engine, and D36's dated note.
|
|
19242
19461
|
*/
|
|
19243
19462
|
granularity: NcThrottleGranularitySchema.optional()
|
|
19244
19463
|
});
|
|
@@ -19411,78 +19630,16 @@ var NcRuleInputSchema = object({
|
|
|
19411
19630
|
*/
|
|
19412
19631
|
confirm: NcConfirmSchema.optional(),
|
|
19413
19632
|
/**
|
|
19414
|
-
*
|
|
19415
|
-
*
|
|
19416
|
-
*
|
|
19417
|
-
*
|
|
19418
|
-
*
|
|
19419
|
-
*
|
|
19420
|
-
*
|
|
19421
|
-
*
|
|
19422
|
-
*
|
|
19423
|
-
* Only two honest answers exist, and this flag picks between them. It has
|
|
19424
|
-
* effect ONLY on a rule that declares a recognition scope
|
|
19425
|
-
* ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
|
|
19426
|
-
* other rule there is nothing to wait for and the flag is inert.
|
|
19427
|
-
*
|
|
19428
|
-
* | value | what happens |
|
|
19429
|
-
* | --- | --- |
|
|
19430
|
-
* | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
|
|
19431
|
-
* | 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) |
|
|
19432
|
-
*
|
|
19433
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19434
|
-
* on the addon cap path, and absent has to keep meaning exactly what every
|
|
19435
|
-
* rule authored before this field meant.
|
|
19436
|
-
*
|
|
19437
|
-
* The cost of `true` is stated here because the editor states it too: a rule
|
|
19438
|
-
* that waits also inherits track-close SEMANTICS — its `zones` condition
|
|
19439
|
-
* tests every zone the track visited and a `crossing` condition can no longer
|
|
19440
|
-
* be satisfied, because a closed track carries no crossing.
|
|
19441
|
-
*/
|
|
19442
|
-
waitForEnhancement: boolean().optional(),
|
|
19443
|
-
/**
|
|
19444
|
-
* GROUP a burst of subjects into ONE notification that grows.
|
|
19445
|
-
*
|
|
19446
|
-
* Seconds of quiet after the last matching subject before the burst is
|
|
19447
|
-
* considered over. While it is open, the first subject enqueues immediately —
|
|
19448
|
-
* **exactly as today, with no added latency** — and every real growth (a new
|
|
19449
|
-
* subject, or a name confirmed on one already in it) REPLACES that
|
|
19450
|
-
* notification with an updated one naming everybody. The push carries the
|
|
19451
|
-
* group's own coalescing tag, so the phone replaces rather than stacks.
|
|
19452
|
-
*
|
|
19453
|
-
* `0` / absent = off, and off is today's behaviour byte for byte.
|
|
19454
|
-
*
|
|
19455
|
-
* ### Why an idle cutoff and not a window
|
|
19456
|
-
*
|
|
19457
|
-
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
19458
|
-
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
19459
|
-
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
19460
|
-
* 30 s is a widely shipped value for the same decision.
|
|
19461
|
-
*
|
|
19462
|
-
* ### What it replaces
|
|
19463
|
-
*
|
|
19464
|
-
* The blind cooldown, which collapses a burst by DISCARDING it. Measured on
|
|
19465
|
-
* device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
|
|
19466
|
-
* notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
|
|
19467
|
-
* track that did fire and 7 carrying a confirmed identity nobody heard about.
|
|
19468
|
-
* A group collapses the same volume by MERGING, so the cooldown becomes a
|
|
19469
|
-
* budget over GROUPS — which is what it always meant — and a growth is never
|
|
19470
|
-
* throttled by the window its own first member spent.
|
|
19471
|
-
*
|
|
19472
|
-
* ### Interaction with {@link waitForEnhancement}
|
|
19473
|
-
*
|
|
19474
|
-
* They compose, and the order matters. `waitForEnhancement` defers the rule to
|
|
19475
|
-
* TRACK CLOSE, so with both set the group is opened by the first member to
|
|
19476
|
-
* CLOSE — already carrying its name — and grows as later members close. That
|
|
19477
|
-
* is later, and complete. With grouping alone the group opens on the first
|
|
19478
|
-
* object event and picks up names as they are confirmed, through the growth
|
|
19479
|
-
* path. Neither combination fires twice for one subject.
|
|
19480
|
-
*
|
|
19481
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19482
|
-
* on the addon cap path, so absent must keep meaning what it meant before this
|
|
19483
|
-
* field existed.
|
|
19633
|
+
* IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
|
|
19634
|
+
* seconds; the rule sends ONE message when the window closes — early, once every
|
|
19635
|
+
* subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
|
|
19636
|
+
* the rule matched, with one mosaic tile per subject.
|
|
19637
|
+
* Absent = plain immediate (one message per track, at the first match).
|
|
19638
|
+
* Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
|
|
19639
|
+
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
19640
|
+
* path does not run Zod defaults.
|
|
19484
19641
|
*/
|
|
19485
|
-
|
|
19642
|
+
groupingSec: number().int().min(5).max(60).optional()
|
|
19486
19643
|
});
|
|
19487
19644
|
/**
|
|
19488
19645
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -19530,9 +19687,10 @@ var NcRuleClearableKeySchema = _enum([
|
|
|
19530
19687
|
"targetUsers",
|
|
19531
19688
|
"snoozeOptions",
|
|
19532
19689
|
"snoozeAllowGlobal",
|
|
19533
|
-
"waitForEnhancement",
|
|
19534
19690
|
"actions",
|
|
19535
19691
|
"confirm",
|
|
19692
|
+
"groupingSec",
|
|
19693
|
+
"waitForEnhancement",
|
|
19536
19694
|
"groupIdleSec"
|
|
19537
19695
|
]);
|
|
19538
19696
|
var NcRuleUpdateInputSchema = object({
|
|
@@ -19554,19 +19712,47 @@ var NcRuleSchema = NcRuleInputSchema.extend({
|
|
|
19554
19712
|
*/
|
|
19555
19713
|
disabledTargetIds: array(string()).default([])
|
|
19556
19714
|
});
|
|
19715
|
+
/**
|
|
19716
|
+
* The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
|
|
19717
|
+
* still-true state. `backups-exports` and `alarm` are not sections — a completed
|
|
19718
|
+
* job is not an open state, and the alarm stays instant.
|
|
19719
|
+
*/
|
|
19720
|
+
var NcStateSummarySectionIdSchema = _enum([
|
|
19721
|
+
"device-state",
|
|
19722
|
+
"streams",
|
|
19723
|
+
"battery",
|
|
19724
|
+
"consumables",
|
|
19725
|
+
"tanks",
|
|
19726
|
+
"detection-blind",
|
|
19727
|
+
"nodes",
|
|
19728
|
+
"addons",
|
|
19729
|
+
"updates"
|
|
19730
|
+
]);
|
|
19557
19731
|
/** One section of a previewed state summary. `unavailable` = its state could not be read. */
|
|
19558
19732
|
var NcStateSummaryPreviewSectionSchema = object({
|
|
19559
|
-
id:
|
|
19733
|
+
id: NcStateSummarySectionIdSchema,
|
|
19560
19734
|
status: _enum(["read", "unavailable"]),
|
|
19561
19735
|
items: number().int().nonnegative(),
|
|
19562
19736
|
reason: string().optional()
|
|
19563
19737
|
});
|
|
19564
19738
|
/**
|
|
19739
|
+
* One notification a previewed summary would send (D698): the whole summary on
|
|
19740
|
+
* a `rule` split (no `section`), one section's on a `section` split.
|
|
19741
|
+
*/
|
|
19742
|
+
var NcStateSummaryPreviewRowSchema = object({
|
|
19743
|
+
section: NcStateSummarySectionIdSchema.optional(),
|
|
19744
|
+
/** The section's name on a per-section row; every reported section's, joined, on a combined one. */
|
|
19745
|
+
title: string(),
|
|
19746
|
+
text: string(),
|
|
19747
|
+
count: number().int().nonnegative()
|
|
19748
|
+
});
|
|
19749
|
+
/**
|
|
19565
19750
|
* The summary a rule would send now. `empty` = nothing to report and every
|
|
19566
19751
|
* section read: such a summary is NOT sent. `dropped` counts the open states
|
|
19567
19752
|
* the rule's own filters (or a camera mute) left out, by reason.
|
|
19568
19753
|
* `excludedGroups` names the kind groups selected that have no state to report
|
|
19569
|
-
* (backups & exports).
|
|
19754
|
+
* (backups & exports). `split` and `rows` (D698) say how it would be sent —
|
|
19755
|
+
* optional, so an older hub's answer still parses.
|
|
19570
19756
|
*/
|
|
19571
19757
|
var NcStateSummaryPreviewSchema = object({
|
|
19572
19758
|
empty: boolean(),
|
|
@@ -19574,7 +19760,9 @@ var NcStateSummaryPreviewSchema = object({
|
|
|
19574
19760
|
text: string(),
|
|
19575
19761
|
sections: array(NcStateSummaryPreviewSectionSchema),
|
|
19576
19762
|
dropped: record(string(), number().int().nonnegative()),
|
|
19577
|
-
excludedGroups: array(string())
|
|
19763
|
+
excludedGroups: array(string()),
|
|
19764
|
+
split: NcStateSummarySplitSchema.optional(),
|
|
19765
|
+
rows: array(NcStateSummaryPreviewRowSchema).optional()
|
|
19578
19766
|
});
|
|
19579
19767
|
var NcTestResultSchema = object({
|
|
19580
19768
|
recordId: string(),
|
|
@@ -19989,6 +20177,29 @@ object({
|
|
|
19989
20177
|
firstAt: number(),
|
|
19990
20178
|
lastAt: number()
|
|
19991
20179
|
});
|
|
20180
|
+
var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
|
|
20181
|
+
var NcAlarmDelaySecSchema = number().int().min(0).max(600);
|
|
20182
|
+
var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
|
|
20183
|
+
var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
|
|
20184
|
+
var NcAlarmModeDelaysListSchema = array(object({
|
|
20185
|
+
mode: AlarmArmModeSchema,
|
|
20186
|
+
exitDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20187
|
+
entryDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20188
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
|
|
20189
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
20190
|
+
var NcAlarmModeDelaysEditListSchema = array(object({
|
|
20191
|
+
mode: AlarmArmModeSchema,
|
|
20192
|
+
exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20193
|
+
entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20194
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
|
|
20195
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
20196
|
+
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
20197
|
+
var NcAlarmNonBlockingEditSchema = object({
|
|
20198
|
+
mode: AlarmArmModeSchema,
|
|
20199
|
+
deviceId: number().int().positive(),
|
|
20200
|
+
/** true = on the list (may be open, does not block); false = off the list (blocks). */
|
|
20201
|
+
nonBlocking: boolean()
|
|
20202
|
+
});
|
|
19992
20203
|
/**
|
|
19993
20204
|
* The per-mode lists, at most one per mode. Two lists for one mode have no
|
|
19994
20205
|
* meaning a reader could agree on (union? the last one?), so they are refused
|
|
@@ -19997,10 +20208,10 @@ object({
|
|
|
19997
20208
|
var NcAlarmNonBlockingListSchema = array(object({
|
|
19998
20209
|
mode: AlarmArmModeSchema,
|
|
19999
20210
|
deviceIds: array(number().int()).max(200)
|
|
20000
|
-
})).max(8).refine(
|
|
20211
|
+
})).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
|
|
20001
20212
|
/**
|
|
20002
|
-
* The three durations
|
|
20003
|
-
* transitions, and which openings each mode tolerates.
|
|
20213
|
+
* The three durations — global, and per mode since D697 — the panel's state
|
|
20214
|
+
* machine runs on, who hears about its transitions, and which openings each mode tolerates.
|
|
20004
20215
|
*
|
|
20005
20216
|
* They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
|
|
20006
20217
|
* `alarm-panel` is `deviceNative` and its other provider mirrors somebody
|
|
@@ -20010,15 +20221,15 @@ var NcAlarmNonBlockingListSchema = array(object({
|
|
|
20010
20221
|
*/
|
|
20011
20222
|
var NcAlarmSettingsSchema = object({
|
|
20012
20223
|
/** Grace period between arming and the mode taking effect. 0 = immediate. */
|
|
20013
|
-
exitDelaySec:
|
|
20224
|
+
exitDelaySec: NcAlarmDelaySecSchema,
|
|
20014
20225
|
/** Grace period between a trigger and the alarm firing. 0 = immediate. */
|
|
20015
|
-
entryDelaySec:
|
|
20226
|
+
entryDelaySec: NcAlarmDelaySecSchema,
|
|
20016
20227
|
/**
|
|
20017
20228
|
* How long `triggered` lasts before the panel re-arms itself.
|
|
20018
20229
|
* **0 = until an operator disarms it** — the behaviour before this field
|
|
20019
20230
|
* existed, and therefore what an untouched install keeps doing.
|
|
20020
20231
|
*/
|
|
20021
|
-
triggeredDurationSec:
|
|
20232
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema,
|
|
20022
20233
|
/**
|
|
20023
20234
|
* Deprecated by D630 — every transition is announced. Parsed, never read;
|
|
20024
20235
|
* remove after one release. Optional so an older admin's patch (which still
|
|
@@ -20041,17 +20252,30 @@ var NcAlarmSettingsSchema = object({
|
|
|
20041
20252
|
* per mode is meaningful. Defaulted to `[]` so a blob stored before D630
|
|
20042
20253
|
* parses as "every opening blocks" — the behaviour it was written under.
|
|
20043
20254
|
*/
|
|
20044
|
-
nonBlocking: NcAlarmNonBlockingListSchema.default([])
|
|
20255
|
+
nonBlocking: NcAlarmNonBlockingListSchema.default([]),
|
|
20256
|
+
/**
|
|
20257
|
+
* Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
|
|
20258
|
+
* without a field, uses the global value above — so `[]`, the default, is exactly the
|
|
20259
|
+
* behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
|
|
20260
|
+
*/
|
|
20261
|
+
modeDelays: NcAlarmModeDelaysListSchema.default([])
|
|
20045
20262
|
});
|
|
20046
20263
|
/**
|
|
20047
20264
|
* Every field optional — a tab edits one control at a time.
|
|
20048
20265
|
*
|
|
20049
|
-
* `nonBlocking`
|
|
20050
|
-
* remove an inner `.default()`, so a patch that never
|
|
20051
|
-
* parse to `
|
|
20052
|
-
* (the same trap {@link NcRulePatchSchema} documents).
|
|
20266
|
+
* `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
|
|
20267
|
+
* `.partial()` does not remove an inner `.default()`, so a patch that never
|
|
20268
|
+
* named the field would parse to `[]` and wipe every mode's list on an
|
|
20269
|
+
* unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
|
|
20270
|
+
* `modeDelays` means EDITS, not the stored overrides.
|
|
20053
20271
|
*/
|
|
20054
|
-
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20272
|
+
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20273
|
+
nonBlocking: NcAlarmNonBlockingListSchema,
|
|
20274
|
+
/** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
|
|
20275
|
+
modeDelays: NcAlarmModeDelaysEditListSchema,
|
|
20276
|
+
/** ONE membership change; the panel applies it to the list it holds at its turn. */
|
|
20277
|
+
nonBlockingEdit: NcAlarmNonBlockingEditSchema
|
|
20278
|
+
}).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
|
|
20055
20279
|
/**
|
|
20056
20280
|
* What one arm mode actually arms, DERIVED from the enabled rules gated on it.
|
|
20057
20281
|
* Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
|
|
@@ -20151,6 +20375,28 @@ var NcAlarmConfigSchema = object({
|
|
|
20151
20375
|
*/
|
|
20152
20376
|
live: NcAlarmLiveSchema.optional()
|
|
20153
20377
|
});
|
|
20378
|
+
var NcAlarmSensorReadingSchema = _enum([
|
|
20379
|
+
"open",
|
|
20380
|
+
"closed",
|
|
20381
|
+
"unknown",
|
|
20382
|
+
"not-opening"
|
|
20383
|
+
]);
|
|
20384
|
+
/** One device's state as the alarm reads it — the classifier the arm check uses. */
|
|
20385
|
+
var NcAlarmSensorStateSchema = object({
|
|
20386
|
+
deviceId: number().int().positive(),
|
|
20387
|
+
reading: NcAlarmSensorReadingSchema,
|
|
20388
|
+
/** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
|
|
20389
|
+
state: string().nullable(),
|
|
20390
|
+
/** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
|
|
20391
|
+
unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
|
|
20392
|
+
/** The device manager's liveness as the centre mirrors it; null = not known. */
|
|
20393
|
+
online: boolean().nullable()
|
|
20394
|
+
});
|
|
20395
|
+
var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
|
|
20396
|
+
var NcAlarmSensorsSchema = object({
|
|
20397
|
+
sensors: array(NcAlarmSensorStateSchema),
|
|
20398
|
+
readAt: number().int().nonnegative()
|
|
20399
|
+
});
|
|
20154
20400
|
/**
|
|
20155
20401
|
* ONE rule's demand on ONE camera's clip ring.
|
|
20156
20402
|
*
|
|
@@ -20241,7 +20487,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
|
|
|
20241
20487
|
}), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
|
|
20242
20488
|
kind: "mutation",
|
|
20243
20489
|
auth: "admin"
|
|
20244
|
-
});
|
|
20490
|
+
}), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
|
|
20245
20491
|
/**
|
|
20246
20492
|
* Zod schemas for persisted record types.
|
|
20247
20493
|
*
|
|
@@ -20588,12 +20834,26 @@ var CameraSensorRefSchema = object({
|
|
|
20588
20834
|
function cameraSensorRefKey(ref) {
|
|
20589
20835
|
return `${ref.addonId}/${ref.stableId}`;
|
|
20590
20836
|
}
|
|
20591
|
-
/**
|
|
20592
|
-
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20837
|
+
/**
|
|
20838
|
+
* A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
|
|
20839
|
+
* `replace`: its motion is the camera's, and while one is READY the camera's
|
|
20840
|
+
* own motion no longer counts on its own. `confirm`: while one is READY the
|
|
20841
|
+
* camera's own motion counts only while a confirm sensor is active — with or
|
|
20842
|
+
* without a replace sensor (spec C2, the controller's ruling on Q1).
|
|
20843
|
+
*/
|
|
20844
|
+
var CameraSensorModeSchema = _enum([
|
|
20845
|
+
"in-addition",
|
|
20846
|
+
"confirm",
|
|
20847
|
+
"replace"
|
|
20848
|
+
]);
|
|
20849
|
+
/** A stored sensor with no mode — every CS-1 row — is in addition. */
|
|
20850
|
+
var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
|
|
20851
|
+
/**
|
|
20852
|
+
* A camera's attached sensors. A CS-1 row carried an envelope
|
|
20853
|
+
* `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
|
|
20854
|
+
* what the write stores (D672 rule 3), so it is never written again.
|
|
20855
|
+
*/
|
|
20856
|
+
var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
|
|
20597
20857
|
const seen = /* @__PURE__ */ new Set();
|
|
20598
20858
|
value.sensors.forEach((ref, index) => {
|
|
20599
20859
|
const key = cameraSensorRefKey(ref);
|
|
@@ -20605,39 +20865,41 @@ var CameraSensorsConfigSchema = object({
|
|
|
20605
20865
|
seen.add(key);
|
|
20606
20866
|
});
|
|
20607
20867
|
});
|
|
20608
|
-
|
|
20868
|
+
/** Every attachment names its mode; an older orchestrator that does not is in addition. */
|
|
20869
|
+
var AttachmentFields = {
|
|
20609
20870
|
addonId: string(),
|
|
20610
|
-
stableId: string()
|
|
20871
|
+
stableId: string(),
|
|
20872
|
+
mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
|
|
20611
20873
|
};
|
|
20612
20874
|
var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
20613
20875
|
object({
|
|
20614
|
-
...
|
|
20876
|
+
...AttachmentFields,
|
|
20615
20877
|
state: literal("ready"),
|
|
20616
20878
|
deviceId: number(),
|
|
20617
20879
|
name: string(),
|
|
20618
20880
|
caps: array(string()).readonly()
|
|
20619
20881
|
}),
|
|
20620
20882
|
object({
|
|
20621
|
-
...
|
|
20883
|
+
...AttachmentFields,
|
|
20622
20884
|
state: literal("offline"),
|
|
20623
20885
|
deviceId: number(),
|
|
20624
20886
|
name: string(),
|
|
20625
20887
|
reason: _enum(["offline", "disabled"])
|
|
20626
20888
|
}),
|
|
20627
20889
|
object({
|
|
20628
|
-
...
|
|
20890
|
+
...AttachmentFields,
|
|
20629
20891
|
state: literal("missing"),
|
|
20630
20892
|
reason: string()
|
|
20631
20893
|
}),
|
|
20632
20894
|
object({
|
|
20633
|
-
...
|
|
20895
|
+
...AttachmentFields,
|
|
20634
20896
|
state: literal("unsupported"),
|
|
20635
20897
|
deviceId: number(),
|
|
20636
20898
|
name: string(),
|
|
20637
20899
|
reason: string()
|
|
20638
20900
|
}),
|
|
20639
20901
|
object({
|
|
20640
|
-
...
|
|
20902
|
+
...AttachmentFields,
|
|
20641
20903
|
state: literal("unreadable"),
|
|
20642
20904
|
reason: string()
|
|
20643
20905
|
})
|
|
@@ -20650,17 +20912,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
|
20650
20912
|
* say.
|
|
20651
20913
|
*/
|
|
20652
20914
|
var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
|
|
20915
|
+
/** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
|
|
20916
|
+
var CameraOwnMotionSchema = _enum([
|
|
20917
|
+
"always",
|
|
20918
|
+
"when-confirmed",
|
|
20919
|
+
"never"
|
|
20920
|
+
]);
|
|
20921
|
+
/** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
|
|
20922
|
+
var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
|
|
20923
|
+
/**
|
|
20924
|
+
* The camera's OWN onboard motion (D696): the raw input the bridge combines,
|
|
20925
|
+
* never the effective value. The camera's `motion` slice is the effective one,
|
|
20926
|
+
* so a view of the camera's own row reads this.
|
|
20927
|
+
* - `atMs`: when the bridge received the camera's last own edge.
|
|
20928
|
+
* - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
|
|
20929
|
+
* AND it is younger than the window the bridge counts the camera's own motion
|
|
20930
|
+
* for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
|
|
20931
|
+
* sends a clear (heartbeats only) therefore reads `false` once no push came
|
|
20932
|
+
* within the window; a status read is a snapshot, so a live view re-asks.
|
|
20933
|
+
* Absent = this orchestrator has not received the camera's own motion since it
|
|
20934
|
+
* started (unknown, never "quiet"), or an orchestrator older than D696.
|
|
20935
|
+
*/
|
|
20936
|
+
var CameraRawLevelSchema = object({
|
|
20937
|
+
detected: boolean(),
|
|
20938
|
+
atMs: number()
|
|
20939
|
+
});
|
|
20653
20940
|
var CameraSensorsStatusSchema = discriminatedUnion("state", [
|
|
20654
|
-
object({
|
|
20941
|
+
object({
|
|
20942
|
+
state: literal("not-configured"),
|
|
20943
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20944
|
+
}),
|
|
20655
20945
|
object({
|
|
20656
20946
|
state: literal("unreadable"),
|
|
20657
|
-
reason: string()
|
|
20947
|
+
reason: string(),
|
|
20948
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20658
20949
|
}),
|
|
20659
20950
|
object({
|
|
20660
20951
|
state: literal("configured"),
|
|
20661
|
-
|
|
20952
|
+
cameraLevel: CameraRawLevelSchema.optional(),
|
|
20662
20953
|
sensors: array(CameraSensorAttachmentSchema).readonly(),
|
|
20663
|
-
|
|
20954
|
+
/** Absent = an orchestrator older than CS-2: it does not say (D315). */
|
|
20955
|
+
cameraMotion: CameraOwnMotionSchema.optional(),
|
|
20956
|
+
notForwarded: CameraSensorsNotForwardedSchema.optional(),
|
|
20957
|
+
notEnforced: CameraSensorsNotEnforcedSchema.optional()
|
|
20664
20958
|
})
|
|
20665
20959
|
]);
|
|
20666
20960
|
Object.freeze({
|
|
@@ -21345,14 +21639,14 @@ var TrackSchema = object({
|
|
|
21345
21639
|
* `derive-returned-null tile=standin`,
|
|
21346
21640
|
* `native-tile tile=native no-key-frame-at-close`, …) written at close and
|
|
21347
21641
|
* CLEARED by the late-keyFrame upgrade when a native tile lands after all.
|
|
21348
|
-
* The operator-facing answer to "perché manca l'immagine?" on a track whose
|
|
21642
|
+
* The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
|
|
21349
21643
|
* tile is a face/plate stand-in, a raster crop, or an icon.
|
|
21350
21644
|
*
|
|
21351
21645
|
* **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
|
|
21352
21646
|
* the TILE ranked below native, so a track whose thumbnail landed natively
|
|
21353
21647
|
* while its key frame missed carried no reason at all — three of the four
|
|
21354
21648
|
* `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
|
|
21355
|
-
* that shape, and their "niente ultimo" had no cause anywhere on the row.
|
|
21649
|
+
* that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
|
|
21356
21650
|
* The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
|
|
21357
21651
|
* lastFrame copy source`), so its absence is now on this line whatever the
|
|
21358
21652
|
* tile ended up being.
|
|
@@ -21439,7 +21733,7 @@ var MotionEventSchema = object({
|
|
|
21439
21733
|
/**
|
|
21440
21734
|
* Ms offsets from `timestamp` (the episode's own first rising edge, so the
|
|
21441
21735
|
* first entry is always `0`) of every genuine off→on transition the
|
|
21442
|
-
* episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
|
|
21736
|
+
* episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
|
|
21443
21737
|
* push: a firmware source that keepalives at ~1 Hz for the whole burst
|
|
21444
21738
|
* (Reolink, Hikvision) produces exactly one edge; a source that reports an
|
|
21445
21739
|
* explicit `false` mid-episode and then resumes before the quiet window
|
|
@@ -21963,6 +22257,7 @@ var KeyEventSchema = object({
|
|
|
21963
22257
|
bestEventId: string(),
|
|
21964
22258
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
21965
22259
|
windowMs: number().optional(),
|
|
22260
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
21966
22261
|
...TrackFlagFields,
|
|
21967
22262
|
...TrackRetrainFields
|
|
21968
22263
|
});
|
|
@@ -22495,7 +22790,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
22495
22790
|
trackIds: array(string()).min(1)
|
|
22496
22791
|
}), object({
|
|
22497
22792
|
deleted: number().int(),
|
|
22498
|
-
failed: array(string()).readonly()
|
|
22793
|
+
failed: array(string()).readonly(),
|
|
22794
|
+
sparedMediaIds: array(number().int()).readonly().optional()
|
|
22499
22795
|
}), {
|
|
22500
22796
|
kind: "mutation",
|
|
22501
22797
|
auth: "admin"
|
|
@@ -23890,8 +24186,10 @@ var RunnerCameraConfigSchema = object({
|
|
|
23890
24186
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
23891
24187
|
* analyzer providers) running on decoded frames in this runner.
|
|
23892
24188
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
23893
|
-
* analytics). The provider emits ProviderMotion
|
|
23894
|
-
*
|
|
24189
|
+
* analytics). The provider emits its raw push as `ProviderMotion`
|
|
24190
|
+
* (D673); the orchestrator's camera-sensors bridge re-emits the camera's
|
|
24191
|
+
* effective motion as `MotionOnMotionChanged`, which is what reaches
|
|
24192
|
+
* `reportMotion`.
|
|
23895
24193
|
*/
|
|
23896
24194
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
23897
24195
|
/**
|
|
@@ -24068,7 +24366,15 @@ var RunnerLocalLoadSchema = object({
|
|
|
24068
24366
|
hasGpu: boolean(),
|
|
24069
24367
|
inferenceBackend: string().optional(),
|
|
24070
24368
|
cpuCores: number().optional()
|
|
24071
|
-
})
|
|
24369
|
+
}),
|
|
24370
|
+
/**
|
|
24371
|
+
* Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
|
|
24372
|
+
* runner never writes it. ABSENT = a runner older than D696, which still
|
|
24373
|
+
* writes the slice from its phase machine; the orchestrator does not write
|
|
24374
|
+
* while any runner node is absent-or-unanswered, so one slice never has two
|
|
24375
|
+
* writers.
|
|
24376
|
+
*/
|
|
24377
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
24072
24378
|
});
|
|
24073
24379
|
/**
|
|
24074
24380
|
* Aggregate runtime metrics for the runner's whole local pool. Mirrors the
|
|
@@ -24724,7 +25030,42 @@ var SetCameraSensorsInputSchema = object({
|
|
|
24724
25030
|
/** `null` removes the attachment: the camera goes back to `not-configured`. */
|
|
24725
25031
|
config: CameraSensorsConfigSchema.nullable()
|
|
24726
25032
|
});
|
|
24727
|
-
|
|
25033
|
+
/**
|
|
25034
|
+
* Why an early occupancy look (D691) was not scheduled.
|
|
25035
|
+
*
|
|
25036
|
+
* - `unknown-camera` — no session was ever dispatched for it, so there is no
|
|
25037
|
+
* node and no config to attach a burst with.
|
|
25038
|
+
* - `out-of-range` — the ask is negative or further out than the orchestrator
|
|
25039
|
+
* will hold a timer for; the parked-object cadence is the answer there.
|
|
25040
|
+
* - `no-burst-producer` — this build has no burst producer at all.
|
|
25041
|
+
* - `already-looked` — this camera's ONE early look since its last session has
|
|
25042
|
+
* been spent. A look's own burst can re-arm a flickering flip, and a look
|
|
25043
|
+
* per arm would chain a burst every ~30 s forever (review H2); the next
|
|
25044
|
+
* real session re-arms the budget.
|
|
25045
|
+
*/
|
|
25046
|
+
var OccupancyLookRefusalSchema = _enum([
|
|
25047
|
+
"unknown-camera",
|
|
25048
|
+
"out-of-range",
|
|
25049
|
+
"no-burst-producer",
|
|
25050
|
+
"already-looked"
|
|
25051
|
+
]);
|
|
25052
|
+
method(object({
|
|
25053
|
+
deviceId: number().int().nonnegative(),
|
|
25054
|
+
/** How long from NOW until the pending flip's sustain window ends. RELATIVE,
|
|
25055
|
+
* so the caller's clock and the orchestrator's never have to agree. */
|
|
25056
|
+
afterMs: number().finite(),
|
|
25057
|
+
/** Why, for the log. */
|
|
25058
|
+
reason: string()
|
|
25059
|
+
}), object({
|
|
25060
|
+
scheduled: boolean(),
|
|
25061
|
+
/** When `scheduled`: how long until the burst is dialled. */
|
|
25062
|
+
dueInMs: number().optional(),
|
|
25063
|
+
/** When not `scheduled`: why. */
|
|
25064
|
+
refusedBecause: OccupancyLookRefusalSchema.optional()
|
|
25065
|
+
}), {
|
|
25066
|
+
kind: "mutation",
|
|
25067
|
+
auth: "admin"
|
|
25068
|
+
}), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
24728
25069
|
kind: "mutation",
|
|
24729
25070
|
auth: "admin"
|
|
24730
25071
|
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
@@ -26802,7 +27143,7 @@ var ClipPlaybackSchema = object({
|
|
|
26802
27143
|
* **One authorised yes is one wake.** `next-natural` — take the clip the next
|
|
26803
27144
|
* time the camera is awake for its own reasons — is deliberately not a member:
|
|
26804
27145
|
* it was proposed, it is free on the battery, and the operator declined it on
|
|
26805
|
-
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."
|
|
27146
|
+
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
|
|
26806
27147
|
* D558 "Considered and not taken").
|
|
26807
27148
|
*/
|
|
26808
27149
|
var ClipWakeSchema = _enum(["authorised"]);
|
|
@@ -27063,7 +27404,7 @@ DeviceType.Camera, method(object({
|
|
|
27063
27404
|
* It replaced `sources?: string[]`, a VIEW filter over source ids that
|
|
27064
27405
|
* assumed the answer was a fan-out over everything a camera has. The
|
|
27065
27406
|
* operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
|
|
27066
|
-
* solo"* — so the list is asked of one provider at a time and there is
|
|
27407
|
+
* solo"* [there is only one user] — so the list is asked of one provider at a time and there is
|
|
27067
27408
|
* nothing to filter out of it.
|
|
27068
27409
|
*/
|
|
27069
27410
|
provider: string().min(1)
|
|
@@ -27191,219 +27532,6 @@ DeviceType.Camera, method(object({
|
|
|
27191
27532
|
auth: "protected"
|
|
27192
27533
|
});
|
|
27193
27534
|
/**
|
|
27194
|
-
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
27195
|
-
* name (same pattern as `snapshot`):
|
|
27196
|
-
*
|
|
27197
|
-
* - **Native** providers: registered per-device by device-driver
|
|
27198
|
-
* addons via `ctx.registerNativeCap` — either on a
|
|
27199
|
-
* `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
|
|
27200
|
-
* or directly on the camera (Reolink registers at camera level).
|
|
27201
|
-
* Emits an `onPressed` event every time the firmware pushes a
|
|
27202
|
-
* ring; status tracks the last press and a pressCount since start
|
|
27203
|
-
* (diagnostic).
|
|
27204
|
-
*
|
|
27205
|
-
* - **Wrapper** provider: the `virtual-doorbell` system builtin
|
|
27206
|
-
* (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
|
|
27207
|
-
* device (contact / switch / event-emitter …) into a doorbell for
|
|
27208
|
-
* a camera. `defaultActive: false` — the operator explicitly binds
|
|
27209
|
-
* it per camera in the device-bindings UI, then picks the source
|
|
27210
|
-
* device + trigger in the per-device settings.
|
|
27211
|
-
*
|
|
27212
|
-
* The DeviceEventPropagator re-emits `onPressed` on the camera parent
|
|
27213
|
-
* — subscribers listening at the camera level receive ring events
|
|
27214
|
-
* with `via[]` populated. No code on the parent needed.
|
|
27215
|
-
*/
|
|
27216
|
-
var DoorbellStatusSchema = object({
|
|
27217
|
-
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
27218
|
-
lastPressedAt: number().nullable(),
|
|
27219
|
-
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
27220
|
-
pressCountSinceStart: number()
|
|
27221
|
-
});
|
|
27222
|
-
var DoorbellPressEventSchema = object({
|
|
27223
|
-
deviceId: number(),
|
|
27224
|
-
timestamp: number()
|
|
27225
|
-
});
|
|
27226
|
-
/**
|
|
27227
|
-
* The `doorbell-source` extension slot's editable value (D648): the camera's
|
|
27228
|
-
* virtual-doorbell trigger devices, exactly what the wrapper's
|
|
27229
|
-
* `doorbellSources` persists (as `{ deviceId }` records).
|
|
27230
|
-
*/
|
|
27231
|
-
var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
|
|
27232
|
-
/**
|
|
27233
|
-
* The `doorbell-source` slot — which devices ring this camera's VIRTUAL
|
|
27234
|
-
* doorbell, owned by the `virtual-doorbell` wrapper over its
|
|
27235
|
-
* `doorbellSources` store (D648). A source rings when one of its
|
|
27236
|
-
* `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
|
|
27237
|
-
* different authority (`deviceManager.setWrapperActive`, D62) — the slot
|
|
27238
|
-
* reports it, it never writes it.
|
|
27239
|
-
*/
|
|
27240
|
-
var DOORBELL_SOURCE_SLOT = {
|
|
27241
|
-
id: "doorbell-source",
|
|
27242
|
-
label: "Doorbell trigger devices",
|
|
27243
|
-
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.",
|
|
27244
|
-
shape: "association",
|
|
27245
|
-
hostDeviceTypes: [DeviceType.Camera],
|
|
27246
|
-
sourceCaps: SOURCE_CAPS,
|
|
27247
|
-
cardinality: "many",
|
|
27248
|
-
value: DoorbellSourceSlotValueSchema
|
|
27249
|
-
};
|
|
27250
|
-
var doorbellCapability = {
|
|
27251
|
-
name: "doorbell",
|
|
27252
|
-
scope: "device",
|
|
27253
|
-
deviceNative: true,
|
|
27254
|
-
mode: "singleton",
|
|
27255
|
-
kind: "wrapper",
|
|
27256
|
-
defaultActive: false,
|
|
27257
|
-
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
27258
|
-
extensionSlots: [DOORBELL_SOURCE_SLOT],
|
|
27259
|
-
methods: {},
|
|
27260
|
-
events: {
|
|
27261
|
-
/**
|
|
27262
|
-
* Fires once per physical press. Reolink delivers via Baichuan
|
|
27263
|
-
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
27264
|
-
* release/duration — it's a pulse.
|
|
27265
|
-
*/
|
|
27266
|
-
onPressed: {
|
|
27267
|
-
data: DoorbellPressEventSchema,
|
|
27268
|
-
fromState: {
|
|
27269
|
-
field: "lastPressedAt",
|
|
27270
|
-
on: "advance"
|
|
27271
|
-
}
|
|
27272
|
-
} },
|
|
27273
|
-
status: {
|
|
27274
|
-
schema: DoorbellStatusSchema,
|
|
27275
|
-
kind: "push"
|
|
27276
|
-
},
|
|
27277
|
-
/**
|
|
27278
|
-
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
27279
|
-
* Mirrored by the kernel and readable via
|
|
27280
|
-
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
27281
|
-
* without subscribing.
|
|
27282
|
-
*/
|
|
27283
|
-
runtimeState: DoorbellStatusSchema,
|
|
27284
|
-
/**
|
|
27285
|
-
* 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.
|
|
27286
|
-
*
|
|
27287
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
27288
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
27289
|
-
*/
|
|
27290
|
-
durability: "restored"
|
|
27291
|
-
};
|
|
27292
|
-
var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
|
|
27293
|
-
DeviceType.Camera, DeviceType.Camera;
|
|
27294
|
-
/** A slot's editable value, discriminated on `slot`. */
|
|
27295
|
-
var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
27296
|
-
DeviceType.Camera;
|
|
27297
|
-
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
27298
|
-
state: literal("unreachable"),
|
|
27299
|
-
reason: string()
|
|
27300
|
-
})]);
|
|
27301
|
-
/** One provider of slots — the D554 source-listing row. */
|
|
27302
|
-
var ExtensionSourceSchema = object({
|
|
27303
|
-
/** The routing prefix of every `slotRef` this provider serves. */
|
|
27304
|
-
source: string(),
|
|
27305
|
-
label: string(),
|
|
27306
|
-
/** Stamped by the dispatcher from the registry (D557). */
|
|
27307
|
-
addonId: string().optional(),
|
|
27308
|
-
availability: ExtensionSourceAvailabilitySchema
|
|
27309
|
-
});
|
|
27310
|
-
/**
|
|
27311
|
-
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
27312
|
-
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
27313
|
-
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
27314
|
-
* valid source now (a container, which is never a pick). A source in any of
|
|
27315
|
-
* these states is SHOWN, never silently dropped or re-pointed.
|
|
27316
|
-
*/
|
|
27317
|
-
var ExtensionSourceHealthSchema = _enum([
|
|
27318
|
-
"ok",
|
|
27319
|
-
"missing",
|
|
27320
|
-
"foreign",
|
|
27321
|
-
"unavailable"
|
|
27322
|
-
]);
|
|
27323
|
-
var ExtensionSlotSourceSchema = object({
|
|
27324
|
-
deviceId: number().int(),
|
|
27325
|
-
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
27326
|
-
name: string().nullable(),
|
|
27327
|
-
health: ExtensionSourceHealthSchema,
|
|
27328
|
-
detail: string().optional()
|
|
27329
|
-
});
|
|
27330
|
-
/**
|
|
27331
|
-
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
27332
|
-
* reported read-only, named, never written through this contract (D62). The
|
|
27333
|
-
* virtual doorbell's sources ring only while the wrapper is bound to the
|
|
27334
|
-
* camera, and that binding belongs to `deviceManager.setWrapperActive`.
|
|
27335
|
-
* `unknown` means the gate could not be read; it is not "inactive" (D315).
|
|
27336
|
-
*/
|
|
27337
|
-
var ExtensionSlotActivationSchema = object({
|
|
27338
|
-
state: _enum([
|
|
27339
|
-
"active",
|
|
27340
|
-
"inactive",
|
|
27341
|
-
"unknown"
|
|
27342
|
-
]),
|
|
27343
|
-
authority: string(),
|
|
27344
|
-
detail: string().optional()
|
|
27345
|
-
});
|
|
27346
|
-
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
27347
|
-
state: literal("ok"),
|
|
27348
|
-
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
27349
|
-
slotRef: string(),
|
|
27350
|
-
slot: ExtensionSlotIdSchema,
|
|
27351
|
-
/** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
|
|
27352
|
-
authority: string(),
|
|
27353
|
-
activation: ExtensionSlotActivationSchema.nullable(),
|
|
27354
|
-
value: ExtensionSlotValueSchema,
|
|
27355
|
-
sources: array(ExtensionSlotSourceSchema),
|
|
27356
|
-
/**
|
|
27357
|
-
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
27358
|
-
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
27359
|
-
* the child a picked container stands for (D356 — a container is never a
|
|
27360
|
-
* pick, its children are). Read-only; the editor shows them and may offer
|
|
27361
|
-
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
27362
|
-
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
27363
|
-
* older than D655.
|
|
27364
|
-
*/
|
|
27365
|
-
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
27366
|
-
}), object({
|
|
27367
|
-
state: literal("unreachable"),
|
|
27368
|
-
addonId: string(),
|
|
27369
|
-
reason: string()
|
|
27370
|
-
})]);
|
|
27371
|
-
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
27372
|
-
deviceId: number().int(),
|
|
27373
|
-
name: string(),
|
|
27374
|
-
type: string(),
|
|
27375
|
-
location: string().nullable(),
|
|
27376
|
-
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
27377
|
-
parentName: string().nullable(),
|
|
27378
|
-
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
27379
|
-
suggested: boolean(),
|
|
27380
|
-
/** Why it is suggested ("same location"), null when it is not. */
|
|
27381
|
-
reason: string().nullable()
|
|
27382
|
-
})) });
|
|
27383
|
-
/**
|
|
27384
|
-
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
27385
|
-
* reloaded the host (or, for an accessory child, its parent) because the
|
|
27386
|
-
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
27387
|
-
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
27388
|
-
*/
|
|
27389
|
-
var ExtensionSetResultSchema = object({
|
|
27390
|
-
applied: literal(true),
|
|
27391
|
-
reload: _enum([
|
|
27392
|
-
"none",
|
|
27393
|
-
"host",
|
|
27394
|
-
"parent"
|
|
27395
|
-
])
|
|
27396
|
-
});
|
|
27397
|
-
var ExtensionSlotRefInputSchema = object({
|
|
27398
|
-
deviceId: number().int(),
|
|
27399
|
-
slotRef: string().min(1)
|
|
27400
|
-
});
|
|
27401
|
-
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
27402
|
-
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
27403
|
-
kind: "mutation",
|
|
27404
|
-
auth: "admin"
|
|
27405
|
-
});
|
|
27406
|
-
/**
|
|
27407
27535
|
* Optional client-side hints sent at session creation to help the provider
|
|
27408
27536
|
* pick the best native source. All fields optional — a viewer that knows
|
|
27409
27537
|
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
@@ -29879,6 +30007,70 @@ onStatusChanged: { data: object({
|
|
|
29879
30007
|
* whether persisting is worth a SQLite commit. */
|
|
29880
30008
|
volatileStateFields: ["lastChangedAt"]
|
|
29881
30009
|
};
|
|
30010
|
+
var DoorbellStatusSchema = object({
|
|
30011
|
+
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
30012
|
+
lastPressedAt: number().nullable(),
|
|
30013
|
+
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
30014
|
+
pressCountSinceStart: number()
|
|
30015
|
+
});
|
|
30016
|
+
var DoorbellPressEventSchema = object({
|
|
30017
|
+
deviceId: number(),
|
|
30018
|
+
timestamp: number()
|
|
30019
|
+
});
|
|
30020
|
+
/**
|
|
30021
|
+
* Doorbell button cap. Two kinds of provider serve it, and to every consumer
|
|
30022
|
+
* they are the same cap:
|
|
30023
|
+
*
|
|
30024
|
+
* - **Native** providers, registered per device by a driver addon through
|
|
30025
|
+
* `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
|
|
30026
|
+
* `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
|
|
30027
|
+
* camera level). They emit `onPressed` on every firmware ring.
|
|
30028
|
+
* - **A composed doorbell** (D670, D671): a camera's customization gives it
|
|
30029
|
+
* the cap, its `lastPressedAt` rising from the sources the operator
|
|
30030
|
+
* assigned in Customize → Doorbell, and the composer emits `onPressed`
|
|
30031
|
+
* from that field's advance (`fromState`).
|
|
30032
|
+
*
|
|
30033
|
+
* The DeviceEventPropagator re-emits `onPressed` on the camera parent.
|
|
30034
|
+
*/
|
|
30035
|
+
var doorbellCapability = {
|
|
30036
|
+
name: "doorbell",
|
|
30037
|
+
scope: "device",
|
|
30038
|
+
deviceNative: true,
|
|
30039
|
+
mode: "singleton",
|
|
30040
|
+
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
30041
|
+
methods: {},
|
|
30042
|
+
events: {
|
|
30043
|
+
/**
|
|
30044
|
+
* Fires once per physical press. Reolink delivers via Baichuan
|
|
30045
|
+
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
30046
|
+
* release/duration — it's a pulse.
|
|
30047
|
+
*/
|
|
30048
|
+
onPressed: {
|
|
30049
|
+
data: DoorbellPressEventSchema,
|
|
30050
|
+
fromState: {
|
|
30051
|
+
field: "lastPressedAt",
|
|
30052
|
+
on: "advance"
|
|
30053
|
+
}
|
|
30054
|
+
} },
|
|
30055
|
+
status: {
|
|
30056
|
+
schema: DoorbellStatusSchema,
|
|
30057
|
+
kind: "push"
|
|
30058
|
+
},
|
|
30059
|
+
/**
|
|
30060
|
+
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
30061
|
+
* Mirrored by the kernel and readable via
|
|
30062
|
+
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
30063
|
+
* without subscribing.
|
|
30064
|
+
*/
|
|
30065
|
+
runtimeState: DoorbellStatusSchema,
|
|
30066
|
+
/**
|
|
30067
|
+
* 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.
|
|
30068
|
+
*
|
|
30069
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
30070
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
30071
|
+
*/
|
|
30072
|
+
durability: "restored"
|
|
30073
|
+
};
|
|
29882
30074
|
/**
|
|
29883
30075
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
29884
30076
|
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
@@ -32023,9 +32215,9 @@ var MotionStatusSchema = object({
|
|
|
32023
32215
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
32024
32216
|
lastDetectedAt: number().nullable(),
|
|
32025
32217
|
/**
|
|
32026
|
-
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device
|
|
32027
|
-
* `null` while false and on every `Sensor`
|
|
32028
|
-
* constant's doc for the one-authority rule.
|
|
32218
|
+
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
|
|
32219
|
+
* orchestrator writes it, D696), `null` while false and on every `Sensor`
|
|
32220
|
+
* device (D475) — see that constant's doc for the one-authority rule.
|
|
32029
32221
|
*
|
|
32030
32222
|
* ## Reading this field still arms nothing
|
|
32031
32223
|
*
|
|
@@ -32043,34 +32235,31 @@ var MotionStatusSchema = object({
|
|
|
32043
32235
|
* `addon-export-alexa/src/motion-clear-hold.ts` and
|
|
32044
32236
|
* `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
|
|
32045
32237
|
*
|
|
32046
|
-
* ## Who writes it
|
|
32047
|
-
*
|
|
32048
|
-
* - **Cameras** — the
|
|
32049
|
-
*
|
|
32050
|
-
* `
|
|
32051
|
-
* `
|
|
32052
|
-
*
|
|
32053
|
-
*
|
|
32054
|
-
* a
|
|
32055
|
-
*
|
|
32056
|
-
*
|
|
32057
|
-
*
|
|
32058
|
-
*
|
|
32059
|
-
*
|
|
32060
|
-
*
|
|
32061
|
-
*
|
|
32062
|
-
*
|
|
32063
|
-
*
|
|
32064
|
-
* `
|
|
32065
|
-
*
|
|
32066
|
-
*
|
|
32067
|
-
*
|
|
32068
|
-
*
|
|
32069
|
-
*
|
|
32070
|
-
*
|
|
32071
|
-
* This predates D475 and is not fixed there: the fix touches every
|
|
32072
|
-
* camera provider. Recorded in D475's Consequences. Do not restore the
|
|
32073
|
-
* "sole writer" wording without also removing the other writers.
|
|
32238
|
+
* ## Who writes it (D696)
|
|
32239
|
+
*
|
|
32240
|
+
* - **Cameras** — the orchestrator, and nothing else. It writes the camera's
|
|
32241
|
+
* EFFECTIVE motion (`addon-pipeline-orchestrator`
|
|
32242
|
+
* `camera-sensors/motion-slice.ts`), alongside the effective
|
|
32243
|
+
* `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
|
|
32244
|
+
* for a split camera, an unsplit emitter's direct event, the analyzer and
|
|
32245
|
+
* device activity, as the camera's `motionSources` counts them. A source
|
|
32246
|
+
* that never sends a clear falls one window after its last `true`.
|
|
32247
|
+
* `lastDetectedAt` moves only on an effective rise. No camera provider
|
|
32248
|
+
* writes this slice (not even a boot seed), and neither does the runner's
|
|
32249
|
+
* phase machine: its phase is "a session is attached" for every on-motion
|
|
32250
|
+
* session, not motion, and it now has its own `DetectionPhaseTransition`.
|
|
32251
|
+
* A provider's `isDetected` answers from the hub's slice.
|
|
32252
|
+
* - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
|
|
32253
|
+
* imports) — the provider pushes both edges itself, from the upstream
|
|
32254
|
+
* system's own state change. That is the sensor's own fact.
|
|
32255
|
+
*
|
|
32256
|
+
* `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
|
|
32257
|
+
* `motion` slice; each sensor writer is a named exemption.
|
|
32258
|
+
*
|
|
32259
|
+
* This replaces the D475 §4 rule ("the phase machine is the sole writer").
|
|
32260
|
+
* That rule was never true: Hikvision and Amcrest wrote the slice raw beside
|
|
32261
|
+
* it, every provider seeded it at boot, and every session left it
|
|
32262
|
+
* `detected: true` after its detach.
|
|
32074
32263
|
*/
|
|
32075
32264
|
autoClearAfterMs: number().nullable()
|
|
32076
32265
|
});
|
|
@@ -32142,11 +32331,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
32142
32331
|
*/
|
|
32143
32332
|
runtimeState: MotionStatusSchema,
|
|
32144
32333
|
/**
|
|
32145
|
-
* Runtime-state durability: **session** —
|
|
32334
|
+
* Runtime-state durability: **session** — the writer of this slice
|
|
32146
32335
|
* writes only on an EDGE, so a restored `detected: true` would stay
|
|
32147
32336
|
* frozen until the next one instead of being corrected. The next edge
|
|
32148
|
-
* re-publishes the real state
|
|
32149
|
-
*
|
|
32337
|
+
* re-publishes the real state, and the orchestrator re-publishes every
|
|
32338
|
+
* camera when it starts writing (D696; on who writes it, see
|
|
32339
|
+
* `autoClearAfterMs` above).
|
|
32150
32340
|
*
|
|
32151
32341
|
* See `RuntimeStateDurability`. Enforced by
|
|
32152
32342
|
* `scripts/check-runtime-state-durability.ts`.
|
|
@@ -34529,8 +34719,7 @@ var ptzAutotrackCapability = {
|
|
|
34529
34719
|
deviceNative: true,
|
|
34530
34720
|
mode: "singleton",
|
|
34531
34721
|
/**
|
|
34532
|
-
* Two kinds of provider behind one name, the same shape `snapshot`
|
|
34533
|
-
* `doorbell` use:
|
|
34722
|
+
* Two kinds of provider behind one name, the same shape `snapshot` uses:
|
|
34534
34723
|
*
|
|
34535
34724
|
* - **Native**: the camera's own firmware autotrack, registered per device by
|
|
34536
34725
|
* the driver when the probe says it exists (Reolink: yes; Hikvision:
|
|
@@ -34538,7 +34727,7 @@ var ptzAutotrackCapability = {
|
|
|
34538
34727
|
* - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
|
|
34539
34728
|
* which follows a subject with `ptz.move` pulses driven by the detection
|
|
34540
34729
|
* pipeline. `defaultActive: false` — the operator binds it per camera in
|
|
34541
|
-
* the bindings UI
|
|
34730
|
+
* the bindings UI.
|
|
34542
34731
|
*
|
|
34543
34732
|
* The binding chooses WHICH implementation answers; `setEnabled` stays the
|
|
34544
34733
|
* one switch for the function either way. A camera never has both driving its
|
|
@@ -35213,7 +35402,7 @@ var ReadGopBytesResultSchema = object({
|
|
|
35213
35402
|
/**
|
|
35214
35403
|
* A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
|
|
35215
35404
|
* twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
|
|
35216
|
-
* replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-
|
|
35405
|
+
* replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
|
|
35217
35406
|
* a replay needs several seconds of native pixels, not one frame.
|
|
35218
35407
|
*
|
|
35219
35408
|
* `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
|
|
@@ -38577,6 +38766,7 @@ var zoneRulesCapability = {
|
|
|
38577
38766
|
*/
|
|
38578
38767
|
durability: "restored"
|
|
38579
38768
|
};
|
|
38769
|
+
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
38580
38770
|
/**
|
|
38581
38771
|
* Accessory device helpers — shared across drivers.
|
|
38582
38772
|
*
|
|
@@ -39636,13 +39826,14 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
39636
39826
|
async getStatus() {
|
|
39637
39827
|
const all = await this.ctx.kernel.devices?.getAll() ?? [];
|
|
39638
39828
|
const summary = this.restoreFailureSummary();
|
|
39639
|
-
|
|
39829
|
+
const base = {
|
|
39640
39830
|
connected: true,
|
|
39641
|
-
deviceCount: all.length
|
|
39831
|
+
deviceCount: all.length,
|
|
39832
|
+
motionSliceWriter: "orchestrator"
|
|
39642
39833
|
};
|
|
39834
|
+
if (summary === null) return base;
|
|
39643
39835
|
return {
|
|
39644
|
-
|
|
39645
|
-
deviceCount: all.length,
|
|
39836
|
+
...base,
|
|
39646
39837
|
error: summary
|
|
39647
39838
|
};
|
|
39648
39839
|
}
|
|
@@ -42672,6 +42863,18 @@ Object.freeze({
|
|
|
42672
42863
|
addonId: null,
|
|
42673
42864
|
access: "view"
|
|
42674
42865
|
},
|
|
42866
|
+
"databaseSnapshot.listDatabases": {
|
|
42867
|
+
capName: "database-snapshot",
|
|
42868
|
+
capScope: "system",
|
|
42869
|
+
addonId: null,
|
|
42870
|
+
access: "view"
|
|
42871
|
+
},
|
|
42872
|
+
"databaseSnapshot.writeSnapshot": {
|
|
42873
|
+
capName: "database-snapshot",
|
|
42874
|
+
capScope: "system",
|
|
42875
|
+
addonId: null,
|
|
42876
|
+
access: "create"
|
|
42877
|
+
},
|
|
42675
42878
|
"dataStoreProvider.aggregate": {
|
|
42676
42879
|
capName: "data-store-provider",
|
|
42677
42880
|
capScope: "system",
|
|
@@ -45132,6 +45335,12 @@ Object.freeze({
|
|
|
45132
45335
|
addonId: null,
|
|
45133
45336
|
access: "view"
|
|
45134
45337
|
},
|
|
45338
|
+
"notificationRules.getAlarmSensors": {
|
|
45339
|
+
capName: "notification-rules",
|
|
45340
|
+
capScope: "system",
|
|
45341
|
+
addonId: null,
|
|
45342
|
+
access: "view"
|
|
45343
|
+
},
|
|
45135
45344
|
"notificationRules.getClipRetentionAsks": {
|
|
45136
45345
|
capName: "notification-rules",
|
|
45137
45346
|
capScope: "system",
|
|
@@ -46236,6 +46445,12 @@ Object.freeze({
|
|
|
46236
46445
|
addonId: null,
|
|
46237
46446
|
access: "delete"
|
|
46238
46447
|
},
|
|
46448
|
+
"pipelineOrchestrator.requestOccupancyLook": {
|
|
46449
|
+
capName: "pipeline-orchestrator",
|
|
46450
|
+
capScope: "system",
|
|
46451
|
+
addonId: null,
|
|
46452
|
+
access: "create"
|
|
46453
|
+
},
|
|
46239
46454
|
"pipelineOrchestrator.resetNodePipelineDefaults": {
|
|
46240
46455
|
capName: "pipeline-orchestrator",
|
|
46241
46456
|
capScope: "system",
|
|
@@ -48704,6 +48919,11 @@ Object.freeze({
|
|
|
48704
48919
|
}
|
|
48705
48920
|
});
|
|
48706
48921
|
Object.freeze({
|
|
48922
|
+
"accessories.getStatus": [{
|
|
48923
|
+
name: "deviceId",
|
|
48924
|
+
form: "single",
|
|
48925
|
+
optional: false
|
|
48926
|
+
}],
|
|
48707
48927
|
"accessories.setChildHidden": [{
|
|
48708
48928
|
name: "childDeviceId",
|
|
48709
48929
|
form: "single",
|
|
@@ -48723,6 +48943,11 @@ Object.freeze({
|
|
|
48723
48943
|
form: "single",
|
|
48724
48944
|
optional: false
|
|
48725
48945
|
}],
|
|
48946
|
+
"airQualitySensor.getStatus": [{
|
|
48947
|
+
name: "deviceId",
|
|
48948
|
+
form: "single",
|
|
48949
|
+
optional: false
|
|
48950
|
+
}],
|
|
48726
48951
|
"alarmPanel.arm": [{
|
|
48727
48952
|
name: "deviceId",
|
|
48728
48953
|
form: "single",
|
|
@@ -48733,11 +48958,36 @@ Object.freeze({
|
|
|
48733
48958
|
form: "single",
|
|
48734
48959
|
optional: false
|
|
48735
48960
|
}],
|
|
48961
|
+
"alarmPanel.getStatus": [{
|
|
48962
|
+
name: "deviceId",
|
|
48963
|
+
form: "single",
|
|
48964
|
+
optional: false
|
|
48965
|
+
}],
|
|
48736
48966
|
"alarmPanel.trigger": [{
|
|
48737
48967
|
name: "deviceId",
|
|
48738
48968
|
form: "single",
|
|
48739
48969
|
optional: false
|
|
48740
48970
|
}],
|
|
48971
|
+
"ambientLightSensor.getStatus": [{
|
|
48972
|
+
name: "deviceId",
|
|
48973
|
+
form: "single",
|
|
48974
|
+
optional: false
|
|
48975
|
+
}],
|
|
48976
|
+
"audioAnalysis.applyDeviceSettingsPatch": [{
|
|
48977
|
+
name: "deviceId",
|
|
48978
|
+
form: "single",
|
|
48979
|
+
optional: false
|
|
48980
|
+
}],
|
|
48981
|
+
"audioAnalysis.getDeviceLiveContribution": [{
|
|
48982
|
+
name: "deviceId",
|
|
48983
|
+
form: "single",
|
|
48984
|
+
optional: false
|
|
48985
|
+
}],
|
|
48986
|
+
"audioAnalysis.getDeviceSettingsContribution": [{
|
|
48987
|
+
name: "deviceId",
|
|
48988
|
+
form: "single",
|
|
48989
|
+
optional: false
|
|
48990
|
+
}],
|
|
48741
48991
|
"audioAnalysis.resolveDeviceSettings": [{
|
|
48742
48992
|
name: "deviceId",
|
|
48743
48993
|
form: "single",
|
|
@@ -48778,16 +49028,36 @@ Object.freeze({
|
|
|
48778
49028
|
form: "single",
|
|
48779
49029
|
optional: false
|
|
48780
49030
|
}],
|
|
49031
|
+
"automationControl.getStatus": [{
|
|
49032
|
+
name: "deviceId",
|
|
49033
|
+
form: "single",
|
|
49034
|
+
optional: false
|
|
49035
|
+
}],
|
|
48781
49036
|
"automationControl.trigger": [{
|
|
48782
49037
|
name: "deviceId",
|
|
48783
49038
|
form: "single",
|
|
48784
49039
|
optional: false
|
|
48785
49040
|
}],
|
|
49041
|
+
"battery.getStatus": [{
|
|
49042
|
+
name: "deviceId",
|
|
49043
|
+
form: "single",
|
|
49044
|
+
optional: false
|
|
49045
|
+
}],
|
|
48786
49046
|
"battery.wakeForStream": [{
|
|
48787
49047
|
name: "deviceId",
|
|
48788
49048
|
form: "single",
|
|
48789
49049
|
optional: false
|
|
48790
49050
|
}],
|
|
49051
|
+
"binary.getStatus": [{
|
|
49052
|
+
name: "deviceId",
|
|
49053
|
+
form: "single",
|
|
49054
|
+
optional: false
|
|
49055
|
+
}],
|
|
49056
|
+
"brightness.getStatus": [{
|
|
49057
|
+
name: "deviceId",
|
|
49058
|
+
form: "single",
|
|
49059
|
+
optional: false
|
|
49060
|
+
}],
|
|
48791
49061
|
"brightness.setBrightness": [{
|
|
48792
49062
|
name: "deviceId",
|
|
48793
49063
|
form: "single",
|
|
@@ -48803,6 +49073,26 @@ Object.freeze({
|
|
|
48803
49073
|
form: "single",
|
|
48804
49074
|
optional: false
|
|
48805
49075
|
}],
|
|
49076
|
+
"cameraCredentials.getStatus": [{
|
|
49077
|
+
name: "deviceId",
|
|
49078
|
+
form: "single",
|
|
49079
|
+
optional: false
|
|
49080
|
+
}],
|
|
49081
|
+
"cameraGridLayout.applyDeviceSettingsPatch": [{
|
|
49082
|
+
name: "deviceId",
|
|
49083
|
+
form: "single",
|
|
49084
|
+
optional: false
|
|
49085
|
+
}],
|
|
49086
|
+
"cameraGridLayout.getDeviceLiveContribution": [{
|
|
49087
|
+
name: "deviceId",
|
|
49088
|
+
form: "single",
|
|
49089
|
+
optional: false
|
|
49090
|
+
}],
|
|
49091
|
+
"cameraGridLayout.getDeviceSettingsContribution": [{
|
|
49092
|
+
name: "deviceId",
|
|
49093
|
+
form: "single",
|
|
49094
|
+
optional: false
|
|
49095
|
+
}],
|
|
48806
49096
|
"cameraGridLayout.getLayout": [{
|
|
48807
49097
|
name: "deviceId",
|
|
48808
49098
|
form: "single",
|
|
@@ -48818,6 +49108,21 @@ Object.freeze({
|
|
|
48818
49108
|
form: "single",
|
|
48819
49109
|
optional: false
|
|
48820
49110
|
}],
|
|
49111
|
+
"cameraPipelineConfig.applyDeviceSettingsPatch": [{
|
|
49112
|
+
name: "deviceId",
|
|
49113
|
+
form: "single",
|
|
49114
|
+
optional: false
|
|
49115
|
+
}],
|
|
49116
|
+
"cameraPipelineConfig.getDeviceLiveContribution": [{
|
|
49117
|
+
name: "deviceId",
|
|
49118
|
+
form: "single",
|
|
49119
|
+
optional: false
|
|
49120
|
+
}],
|
|
49121
|
+
"cameraPipelineConfig.getDeviceSettingsContribution": [{
|
|
49122
|
+
name: "deviceId",
|
|
49123
|
+
form: "single",
|
|
49124
|
+
optional: false
|
|
49125
|
+
}],
|
|
48821
49126
|
"cameraStreams.getBrokerStreams": [{
|
|
48822
49127
|
name: "deviceId",
|
|
48823
49128
|
form: "single",
|
|
@@ -48843,6 +49148,16 @@ Object.freeze({
|
|
|
48843
49148
|
form: "single",
|
|
48844
49149
|
optional: false
|
|
48845
49150
|
}],
|
|
49151
|
+
"carbonMonoxide.getStatus": [{
|
|
49152
|
+
name: "deviceId",
|
|
49153
|
+
form: "single",
|
|
49154
|
+
optional: false
|
|
49155
|
+
}],
|
|
49156
|
+
"climateControl.getStatus": [{
|
|
49157
|
+
name: "deviceId",
|
|
49158
|
+
form: "single",
|
|
49159
|
+
optional: false
|
|
49160
|
+
}],
|
|
48846
49161
|
"climateControl.setFanMode": [{
|
|
48847
49162
|
name: "deviceId",
|
|
48848
49163
|
form: "single",
|
|
@@ -48883,16 +49198,41 @@ Object.freeze({
|
|
|
48883
49198
|
form: "single",
|
|
48884
49199
|
optional: false
|
|
48885
49200
|
}],
|
|
49201
|
+
"color.getStatus": [{
|
|
49202
|
+
name: "deviceId",
|
|
49203
|
+
form: "single",
|
|
49204
|
+
optional: false
|
|
49205
|
+
}],
|
|
48886
49206
|
"color.setColor": [{
|
|
48887
49207
|
name: "deviceId",
|
|
48888
49208
|
form: "single",
|
|
48889
49209
|
optional: false
|
|
48890
49210
|
}],
|
|
49211
|
+
"connectivity.getStatus": [{
|
|
49212
|
+
name: "deviceId",
|
|
49213
|
+
form: "single",
|
|
49214
|
+
optional: false
|
|
49215
|
+
}],
|
|
49216
|
+
"consumables.getStatus": [{
|
|
49217
|
+
name: "deviceId",
|
|
49218
|
+
form: "single",
|
|
49219
|
+
optional: false
|
|
49220
|
+
}],
|
|
48891
49221
|
"consumables.reset": [{
|
|
48892
49222
|
name: "deviceId",
|
|
48893
49223
|
form: "single",
|
|
48894
49224
|
optional: false
|
|
48895
49225
|
}],
|
|
49226
|
+
"contact.getStatus": [{
|
|
49227
|
+
name: "deviceId",
|
|
49228
|
+
form: "single",
|
|
49229
|
+
optional: false
|
|
49230
|
+
}],
|
|
49231
|
+
"control.getStatus": [{
|
|
49232
|
+
name: "deviceId",
|
|
49233
|
+
form: "single",
|
|
49234
|
+
optional: false
|
|
49235
|
+
}],
|
|
48896
49236
|
"control.setValue": [{
|
|
48897
49237
|
name: "deviceId",
|
|
48898
49238
|
form: "single",
|
|
@@ -48903,6 +49243,11 @@ Object.freeze({
|
|
|
48903
49243
|
form: "single",
|
|
48904
49244
|
optional: false
|
|
48905
49245
|
}],
|
|
49246
|
+
"cover.getStatus": [{
|
|
49247
|
+
name: "deviceId",
|
|
49248
|
+
form: "single",
|
|
49249
|
+
optional: false
|
|
49250
|
+
}],
|
|
48906
49251
|
"cover.open": [{
|
|
48907
49252
|
name: "deviceId",
|
|
48908
49253
|
form: "single",
|
|
@@ -48928,6 +49273,11 @@ Object.freeze({
|
|
|
48928
49273
|
form: "single",
|
|
48929
49274
|
optional: false
|
|
48930
49275
|
}],
|
|
49276
|
+
"dayNight.getStatus": [{
|
|
49277
|
+
name: "deviceId",
|
|
49278
|
+
form: "single",
|
|
49279
|
+
optional: false
|
|
49280
|
+
}],
|
|
48931
49281
|
"dayNight.setSettings": [{
|
|
48932
49282
|
name: "deviceId",
|
|
48933
49283
|
form: "single",
|
|
@@ -48938,11 +49288,31 @@ Object.freeze({
|
|
|
48938
49288
|
form: "single",
|
|
48939
49289
|
optional: true
|
|
48940
49290
|
}],
|
|
49291
|
+
"detectionPipeline.applyDeviceSettingsPatch": [{
|
|
49292
|
+
name: "deviceId",
|
|
49293
|
+
form: "single",
|
|
49294
|
+
optional: false
|
|
49295
|
+
}],
|
|
49296
|
+
"detectionPipeline.getDeviceLiveContribution": [{
|
|
49297
|
+
name: "deviceId",
|
|
49298
|
+
form: "single",
|
|
49299
|
+
optional: false
|
|
49300
|
+
}],
|
|
49301
|
+
"detectionPipeline.getDeviceSettingsContribution": [{
|
|
49302
|
+
name: "deviceId",
|
|
49303
|
+
form: "single",
|
|
49304
|
+
optional: false
|
|
49305
|
+
}],
|
|
48941
49306
|
"deviceAdminLink.getAdminLink": [{
|
|
48942
49307
|
name: "deviceId",
|
|
48943
49308
|
form: "single",
|
|
48944
49309
|
optional: false
|
|
48945
49310
|
}],
|
|
49311
|
+
"deviceAdoption.getStatus": [{
|
|
49312
|
+
name: "deviceId",
|
|
49313
|
+
form: "single",
|
|
49314
|
+
optional: false
|
|
49315
|
+
}],
|
|
48946
49316
|
"deviceAdoption.release": [{
|
|
48947
49317
|
name: "camDeviceId",
|
|
48948
49318
|
form: "single",
|
|
@@ -48958,6 +49328,11 @@ Object.freeze({
|
|
|
48958
49328
|
form: "single",
|
|
48959
49329
|
optional: false
|
|
48960
49330
|
}],
|
|
49331
|
+
"deviceDiscovery.getStatus": [{
|
|
49332
|
+
name: "deviceId",
|
|
49333
|
+
form: "single",
|
|
49334
|
+
optional: false
|
|
49335
|
+
}],
|
|
48961
49336
|
"deviceDiscovery.listDiscovered": [{
|
|
48962
49337
|
name: "deviceId",
|
|
48963
49338
|
form: "single",
|
|
@@ -48977,6 +49352,21 @@ Object.freeze({
|
|
|
48977
49352
|
form: "single",
|
|
48978
49353
|
optional: false
|
|
48979
49354
|
}],
|
|
49355
|
+
"deviceExport.applyDeviceSettingsPatch": [{
|
|
49356
|
+
name: "deviceId",
|
|
49357
|
+
form: "single",
|
|
49358
|
+
optional: false
|
|
49359
|
+
}],
|
|
49360
|
+
"deviceExport.getDeviceLiveContribution": [{
|
|
49361
|
+
name: "deviceId",
|
|
49362
|
+
form: "single",
|
|
49363
|
+
optional: false
|
|
49364
|
+
}],
|
|
49365
|
+
"deviceExport.getDeviceSettingsContribution": [{
|
|
49366
|
+
name: "deviceId",
|
|
49367
|
+
form: "single",
|
|
49368
|
+
optional: false
|
|
49369
|
+
}],
|
|
48980
49370
|
"deviceExtension.listCandidates": [{
|
|
48981
49371
|
name: "deviceId",
|
|
48982
49372
|
form: "single",
|
|
@@ -49325,6 +49715,26 @@ Object.freeze({
|
|
|
49325
49715
|
form: "single",
|
|
49326
49716
|
optional: false
|
|
49327
49717
|
}],
|
|
49718
|
+
"deviceStatus.getStatus": [{
|
|
49719
|
+
name: "deviceId",
|
|
49720
|
+
form: "single",
|
|
49721
|
+
optional: false
|
|
49722
|
+
}],
|
|
49723
|
+
"doorbell.getStatus": [{
|
|
49724
|
+
name: "deviceId",
|
|
49725
|
+
form: "single",
|
|
49726
|
+
optional: false
|
|
49727
|
+
}],
|
|
49728
|
+
"enumSensor.getStatus": [{
|
|
49729
|
+
name: "deviceId",
|
|
49730
|
+
form: "single",
|
|
49731
|
+
optional: false
|
|
49732
|
+
}],
|
|
49733
|
+
"eventEmitter.getStatus": [{
|
|
49734
|
+
name: "deviceId",
|
|
49735
|
+
form: "single",
|
|
49736
|
+
optional: false
|
|
49737
|
+
}],
|
|
49328
49738
|
"faceGallery.getFaceByTrack": [{
|
|
49329
49739
|
name: "deviceId",
|
|
49330
49740
|
form: "single",
|
|
@@ -49339,6 +49749,11 @@ Object.freeze({
|
|
|
49339
49749
|
form: "array",
|
|
49340
49750
|
optional: true
|
|
49341
49751
|
}],
|
|
49752
|
+
"fanControl.getStatus": [{
|
|
49753
|
+
name: "deviceId",
|
|
49754
|
+
form: "single",
|
|
49755
|
+
optional: false
|
|
49756
|
+
}],
|
|
49342
49757
|
"fanControl.setDirection": [{
|
|
49343
49758
|
name: "deviceId",
|
|
49344
49759
|
form: "single",
|
|
@@ -49359,6 +49774,26 @@ Object.freeze({
|
|
|
49359
49774
|
form: "single",
|
|
49360
49775
|
optional: false
|
|
49361
49776
|
}],
|
|
49777
|
+
"featureProbe.getStatus": [{
|
|
49778
|
+
name: "deviceId",
|
|
49779
|
+
form: "single",
|
|
49780
|
+
optional: false
|
|
49781
|
+
}],
|
|
49782
|
+
"flood.getStatus": [{
|
|
49783
|
+
name: "deviceId",
|
|
49784
|
+
form: "single",
|
|
49785
|
+
optional: false
|
|
49786
|
+
}],
|
|
49787
|
+
"gas.getStatus": [{
|
|
49788
|
+
name: "deviceId",
|
|
49789
|
+
form: "single",
|
|
49790
|
+
optional: false
|
|
49791
|
+
}],
|
|
49792
|
+
"humidifier.getStatus": [{
|
|
49793
|
+
name: "deviceId",
|
|
49794
|
+
form: "single",
|
|
49795
|
+
optional: false
|
|
49796
|
+
}],
|
|
49362
49797
|
"humidifier.setMode": [{
|
|
49363
49798
|
name: "deviceId",
|
|
49364
49799
|
form: "single",
|
|
@@ -49374,11 +49809,26 @@ Object.freeze({
|
|
|
49374
49809
|
form: "single",
|
|
49375
49810
|
optional: false
|
|
49376
49811
|
}],
|
|
49812
|
+
"humiditySensor.getStatus": [{
|
|
49813
|
+
name: "deviceId",
|
|
49814
|
+
form: "single",
|
|
49815
|
+
optional: false
|
|
49816
|
+
}],
|
|
49817
|
+
"image.getStatus": [{
|
|
49818
|
+
name: "deviceId",
|
|
49819
|
+
form: "single",
|
|
49820
|
+
optional: false
|
|
49821
|
+
}],
|
|
49377
49822
|
"imageSettings.getOptions": [{
|
|
49378
49823
|
name: "deviceId",
|
|
49379
49824
|
form: "single",
|
|
49380
49825
|
optional: false
|
|
49381
49826
|
}],
|
|
49827
|
+
"imageSettings.getStatus": [{
|
|
49828
|
+
name: "deviceId",
|
|
49829
|
+
form: "single",
|
|
49830
|
+
optional: false
|
|
49831
|
+
}],
|
|
49382
49832
|
"imageSettings.setSettings": [{
|
|
49383
49833
|
name: "deviceId",
|
|
49384
49834
|
form: "single",
|
|
@@ -49389,6 +49839,11 @@ Object.freeze({
|
|
|
49389
49839
|
form: "single",
|
|
49390
49840
|
optional: false
|
|
49391
49841
|
}],
|
|
49842
|
+
"intercom.getStatus": [{
|
|
49843
|
+
name: "deviceId",
|
|
49844
|
+
form: "single",
|
|
49845
|
+
optional: false
|
|
49846
|
+
}],
|
|
49392
49847
|
"intercom.handleAnswer": [{
|
|
49393
49848
|
name: "deviceId",
|
|
49394
49849
|
form: "single",
|
|
@@ -49419,6 +49874,11 @@ Object.freeze({
|
|
|
49419
49874
|
form: "single",
|
|
49420
49875
|
optional: false
|
|
49421
49876
|
}],
|
|
49877
|
+
"lawnMowerControl.getStatus": [{
|
|
49878
|
+
name: "deviceId",
|
|
49879
|
+
form: "single",
|
|
49880
|
+
optional: false
|
|
49881
|
+
}],
|
|
49422
49882
|
"lawnMowerControl.pause": [{
|
|
49423
49883
|
name: "deviceId",
|
|
49424
49884
|
form: "single",
|
|
@@ -49429,6 +49889,11 @@ Object.freeze({
|
|
|
49429
49889
|
form: "single",
|
|
49430
49890
|
optional: false
|
|
49431
49891
|
}],
|
|
49892
|
+
"lockControl.getStatus": [{
|
|
49893
|
+
name: "deviceId",
|
|
49894
|
+
form: "single",
|
|
49895
|
+
optional: false
|
|
49896
|
+
}],
|
|
49432
49897
|
"lockControl.lock": [{
|
|
49433
49898
|
name: "deviceId",
|
|
49434
49899
|
form: "single",
|
|
@@ -49444,6 +49909,11 @@ Object.freeze({
|
|
|
49444
49909
|
form: "single",
|
|
49445
49910
|
optional: false
|
|
49446
49911
|
}],
|
|
49912
|
+
"mediaPlayer.getStatus": [{
|
|
49913
|
+
name: "deviceId",
|
|
49914
|
+
form: "single",
|
|
49915
|
+
optional: false
|
|
49916
|
+
}],
|
|
49447
49917
|
"mediaPlayer.next": [{
|
|
49448
49918
|
name: "deviceId",
|
|
49449
49919
|
form: "single",
|
|
@@ -49504,6 +49974,11 @@ Object.freeze({
|
|
|
49504
49974
|
form: "single",
|
|
49505
49975
|
optional: false
|
|
49506
49976
|
}],
|
|
49977
|
+
"motion.getStatus": [{
|
|
49978
|
+
name: "deviceId",
|
|
49979
|
+
form: "single",
|
|
49980
|
+
optional: false
|
|
49981
|
+
}],
|
|
49507
49982
|
"motion.isDetected": [{
|
|
49508
49983
|
name: "deviceId",
|
|
49509
49984
|
form: "single",
|
|
@@ -49514,11 +49989,31 @@ Object.freeze({
|
|
|
49514
49989
|
form: "single",
|
|
49515
49990
|
optional: false
|
|
49516
49991
|
}],
|
|
49992
|
+
"motionDetection.applyDeviceSettingsPatch": [{
|
|
49993
|
+
name: "deviceId",
|
|
49994
|
+
form: "single",
|
|
49995
|
+
optional: false
|
|
49996
|
+
}],
|
|
49997
|
+
"motionDetection.getDeviceLiveContribution": [{
|
|
49998
|
+
name: "deviceId",
|
|
49999
|
+
form: "single",
|
|
50000
|
+
optional: false
|
|
50001
|
+
}],
|
|
50002
|
+
"motionDetection.getDeviceSettingsContribution": [{
|
|
50003
|
+
name: "deviceId",
|
|
50004
|
+
form: "single",
|
|
50005
|
+
optional: false
|
|
50006
|
+
}],
|
|
49517
50007
|
"motionDetection.removeCamera": [{
|
|
49518
50008
|
name: "deviceId",
|
|
49519
50009
|
form: "single",
|
|
49520
50010
|
optional: false
|
|
49521
50011
|
}],
|
|
50012
|
+
"motionTrigger.getStatus": [{
|
|
50013
|
+
name: "deviceId",
|
|
50014
|
+
form: "single",
|
|
50015
|
+
optional: false
|
|
50016
|
+
}],
|
|
49522
50017
|
"motionTrigger.setMotionTrigger": [{
|
|
49523
50018
|
name: "deviceId",
|
|
49524
50019
|
form: "single",
|
|
@@ -49529,6 +50024,11 @@ Object.freeze({
|
|
|
49529
50024
|
form: "single",
|
|
49530
50025
|
optional: false
|
|
49531
50026
|
}],
|
|
50027
|
+
"motionZones.getStatus": [{
|
|
50028
|
+
name: "deviceId",
|
|
50029
|
+
form: "single",
|
|
50030
|
+
optional: false
|
|
50031
|
+
}],
|
|
49532
50032
|
"motionZones.setZone": [{
|
|
49533
50033
|
name: "deviceId",
|
|
49534
50034
|
form: "single",
|
|
@@ -49539,6 +50039,11 @@ Object.freeze({
|
|
|
49539
50039
|
form: "single",
|
|
49540
50040
|
optional: false
|
|
49541
50041
|
}],
|
|
50042
|
+
"nativeObjectDetection.getStatus": [{
|
|
50043
|
+
name: "deviceId",
|
|
50044
|
+
form: "single",
|
|
50045
|
+
optional: false
|
|
50046
|
+
}],
|
|
49542
50047
|
"nativeObjectDetection.setEnabled": [{
|
|
49543
50048
|
name: "deviceId",
|
|
49544
50049
|
form: "single",
|
|
@@ -49554,6 +50059,11 @@ Object.freeze({
|
|
|
49554
50059
|
form: "single",
|
|
49555
50060
|
optional: false
|
|
49556
50061
|
}],
|
|
50062
|
+
"navigation.getStatus": [{
|
|
50063
|
+
name: "deviceId",
|
|
50064
|
+
form: "single",
|
|
50065
|
+
optional: false
|
|
50066
|
+
}],
|
|
49557
50067
|
"navigation.goToPoint": [{
|
|
49558
50068
|
name: "deviceId",
|
|
49559
50069
|
form: "single",
|
|
@@ -49599,6 +50109,11 @@ Object.freeze({
|
|
|
49599
50109
|
form: "single",
|
|
49600
50110
|
optional: false
|
|
49601
50111
|
}],
|
|
50112
|
+
"networkLink.getStatus": [{
|
|
50113
|
+
name: "deviceId",
|
|
50114
|
+
form: "single",
|
|
50115
|
+
optional: false
|
|
50116
|
+
}],
|
|
49602
50117
|
"networkQuality.getDeviceStats": [{
|
|
49603
50118
|
name: "deviceId",
|
|
49604
50119
|
form: "single",
|
|
@@ -49609,6 +50124,11 @@ Object.freeze({
|
|
|
49609
50124
|
form: "single",
|
|
49610
50125
|
optional: false
|
|
49611
50126
|
}],
|
|
50127
|
+
"notificationRules.getAlarmSensors": [{
|
|
50128
|
+
name: "deviceIds",
|
|
50129
|
+
form: "array",
|
|
50130
|
+
optional: false
|
|
50131
|
+
}],
|
|
49612
50132
|
"notificationRules.setDeviceMuted": [{
|
|
49613
50133
|
name: "deviceId",
|
|
49614
50134
|
form: "single",
|
|
@@ -49619,11 +50139,26 @@ Object.freeze({
|
|
|
49619
50139
|
form: "single",
|
|
49620
50140
|
optional: false
|
|
49621
50141
|
}],
|
|
50142
|
+
"notifier.getStatus": [{
|
|
50143
|
+
name: "deviceId",
|
|
50144
|
+
form: "single",
|
|
50145
|
+
optional: false
|
|
50146
|
+
}],
|
|
49622
50147
|
"notifier.send": [{
|
|
49623
50148
|
name: "deviceId",
|
|
49624
50149
|
form: "single",
|
|
49625
50150
|
optional: false
|
|
49626
50151
|
}],
|
|
50152
|
+
"numericSensor.getStatus": [{
|
|
50153
|
+
name: "deviceId",
|
|
50154
|
+
form: "single",
|
|
50155
|
+
optional: false
|
|
50156
|
+
}],
|
|
50157
|
+
"osd.getStatus": [{
|
|
50158
|
+
name: "deviceId",
|
|
50159
|
+
form: "single",
|
|
50160
|
+
optional: false
|
|
50161
|
+
}],
|
|
49627
50162
|
"osd.setOverlay": [{
|
|
49628
50163
|
name: "deviceId",
|
|
49629
50164
|
form: "single",
|
|
@@ -49683,6 +50218,11 @@ Object.freeze({
|
|
|
49683
50218
|
form: "single",
|
|
49684
50219
|
optional: false
|
|
49685
50220
|
}],
|
|
50221
|
+
"petFeeder.getStatus": [{
|
|
50222
|
+
name: "deviceId",
|
|
50223
|
+
form: "single",
|
|
50224
|
+
optional: false
|
|
50225
|
+
}],
|
|
49686
50226
|
"petFeeder.markFoodReplenished": [{
|
|
49687
50227
|
name: "deviceId",
|
|
49688
50228
|
form: "single",
|
|
@@ -49718,6 +50258,11 @@ Object.freeze({
|
|
|
49718
50258
|
form: "single",
|
|
49719
50259
|
optional: false
|
|
49720
50260
|
}],
|
|
50261
|
+
"pipelineAnalytics.applyDeviceSettingsPatch": [{
|
|
50262
|
+
name: "deviceId",
|
|
50263
|
+
form: "single",
|
|
50264
|
+
optional: false
|
|
50265
|
+
}],
|
|
49721
50266
|
"pipelineAnalytics.clearTrackRelation": [{
|
|
49722
50267
|
name: "deviceId",
|
|
49723
50268
|
form: "single",
|
|
@@ -49758,6 +50303,16 @@ Object.freeze({
|
|
|
49758
50303
|
form: "single",
|
|
49759
50304
|
optional: false
|
|
49760
50305
|
}],
|
|
50306
|
+
"pipelineAnalytics.getDeviceLiveContribution": [{
|
|
50307
|
+
name: "deviceId",
|
|
50308
|
+
form: "single",
|
|
50309
|
+
optional: false
|
|
50310
|
+
}],
|
|
50311
|
+
"pipelineAnalytics.getDeviceSettingsContribution": [{
|
|
50312
|
+
name: "deviceId",
|
|
50313
|
+
form: "single",
|
|
50314
|
+
optional: false
|
|
50315
|
+
}],
|
|
49761
50316
|
"pipelineAnalytics.getEventDensity": [{
|
|
49762
50317
|
name: "deviceId",
|
|
49763
50318
|
form: "single",
|
|
@@ -49973,6 +50528,11 @@ Object.freeze({
|
|
|
49973
50528
|
form: "single",
|
|
49974
50529
|
optional: true
|
|
49975
50530
|
}],
|
|
50531
|
+
"pipelineOrchestrator.applyDeviceSettingsPatch": [{
|
|
50532
|
+
name: "deviceId",
|
|
50533
|
+
form: "single",
|
|
50534
|
+
optional: false
|
|
50535
|
+
}],
|
|
49976
50536
|
"pipelineOrchestrator.assignAudio": [{
|
|
49977
50537
|
name: "deviceId",
|
|
49978
50538
|
form: "single",
|
|
@@ -50018,6 +50578,16 @@ Object.freeze({
|
|
|
50018
50578
|
form: "single",
|
|
50019
50579
|
optional: false
|
|
50020
50580
|
}],
|
|
50581
|
+
"pipelineOrchestrator.getDeviceLiveContribution": [{
|
|
50582
|
+
name: "deviceId",
|
|
50583
|
+
form: "single",
|
|
50584
|
+
optional: false
|
|
50585
|
+
}],
|
|
50586
|
+
"pipelineOrchestrator.getDeviceSettingsContribution": [{
|
|
50587
|
+
name: "deviceId",
|
|
50588
|
+
form: "single",
|
|
50589
|
+
optional: false
|
|
50590
|
+
}],
|
|
50021
50591
|
"pipelineOrchestrator.getPipelineAssignment": [{
|
|
50022
50592
|
name: "deviceId",
|
|
50023
50593
|
form: "single",
|
|
@@ -50028,6 +50598,11 @@ Object.freeze({
|
|
|
50028
50598
|
form: "single",
|
|
50029
50599
|
optional: false
|
|
50030
50600
|
}],
|
|
50601
|
+
"pipelineOrchestrator.requestOccupancyLook": [{
|
|
50602
|
+
name: "deviceId",
|
|
50603
|
+
form: "single",
|
|
50604
|
+
optional: false
|
|
50605
|
+
}],
|
|
50031
50606
|
"pipelineOrchestrator.resolvePipeline": [{
|
|
50032
50607
|
name: "deviceId",
|
|
50033
50608
|
form: "single",
|
|
@@ -50133,11 +50708,31 @@ Object.freeze({
|
|
|
50133
50708
|
form: "single",
|
|
50134
50709
|
optional: true
|
|
50135
50710
|
}],
|
|
50711
|
+
"powerMeter.getStatus": [{
|
|
50712
|
+
name: "deviceId",
|
|
50713
|
+
form: "single",
|
|
50714
|
+
optional: false
|
|
50715
|
+
}],
|
|
50716
|
+
"presence.getStatus": [{
|
|
50717
|
+
name: "deviceId",
|
|
50718
|
+
form: "single",
|
|
50719
|
+
optional: false
|
|
50720
|
+
}],
|
|
50721
|
+
"pressureSensor.getStatus": [{
|
|
50722
|
+
name: "deviceId",
|
|
50723
|
+
form: "single",
|
|
50724
|
+
optional: false
|
|
50725
|
+
}],
|
|
50136
50726
|
"privacyMask.getOptions": [{
|
|
50137
50727
|
name: "deviceId",
|
|
50138
50728
|
form: "single",
|
|
50139
50729
|
optional: false
|
|
50140
50730
|
}],
|
|
50731
|
+
"privacyMask.getStatus": [{
|
|
50732
|
+
name: "deviceId",
|
|
50733
|
+
form: "single",
|
|
50734
|
+
optional: false
|
|
50735
|
+
}],
|
|
50141
50736
|
"privacyMask.setAudioEnabled": [{
|
|
50142
50737
|
name: "deviceId",
|
|
50143
50738
|
form: "single",
|
|
@@ -50188,6 +50783,11 @@ Object.freeze({
|
|
|
50188
50783
|
form: "single",
|
|
50189
50784
|
optional: false
|
|
50190
50785
|
}],
|
|
50786
|
+
"ptz.getStatus": [{
|
|
50787
|
+
name: "deviceId",
|
|
50788
|
+
form: "single",
|
|
50789
|
+
optional: false
|
|
50790
|
+
}],
|
|
50191
50791
|
"ptz.goHome": [{
|
|
50192
50792
|
name: "deviceId",
|
|
50193
50793
|
form: "single",
|
|
@@ -50278,6 +50878,11 @@ Object.freeze({
|
|
|
50278
50878
|
form: "single",
|
|
50279
50879
|
optional: false
|
|
50280
50880
|
}],
|
|
50881
|
+
"recordingArchive.applyDeviceSettingsPatch": [{
|
|
50882
|
+
name: "deviceId",
|
|
50883
|
+
form: "single",
|
|
50884
|
+
optional: false
|
|
50885
|
+
}],
|
|
50281
50886
|
"recordingArchive.deleteFootprint": [{
|
|
50282
50887
|
name: "deviceId",
|
|
50283
50888
|
form: "single",
|
|
@@ -50298,6 +50903,21 @@ Object.freeze({
|
|
|
50298
50903
|
form: "single",
|
|
50299
50904
|
optional: false
|
|
50300
50905
|
}],
|
|
50906
|
+
"recordingArchive.getDeviceLiveContribution": [{
|
|
50907
|
+
name: "deviceId",
|
|
50908
|
+
form: "single",
|
|
50909
|
+
optional: false
|
|
50910
|
+
}],
|
|
50911
|
+
"recordingArchive.getDeviceSettingsContribution": [{
|
|
50912
|
+
name: "deviceId",
|
|
50913
|
+
form: "single",
|
|
50914
|
+
optional: false
|
|
50915
|
+
}],
|
|
50916
|
+
"recordingArchive.getStatus": [{
|
|
50917
|
+
name: "deviceId",
|
|
50918
|
+
form: "single",
|
|
50919
|
+
optional: false
|
|
50920
|
+
}],
|
|
50301
50921
|
"recordingArchive.listOpsLog": [{
|
|
50302
50922
|
name: "deviceId",
|
|
50303
50923
|
form: "single",
|
|
@@ -50383,6 +51003,11 @@ Object.freeze({
|
|
|
50383
51003
|
form: "single",
|
|
50384
51004
|
optional: false
|
|
50385
51005
|
}],
|
|
51006
|
+
"recordingOnboard.getStatus": [{
|
|
51007
|
+
name: "deviceId",
|
|
51008
|
+
form: "single",
|
|
51009
|
+
optional: false
|
|
51010
|
+
}],
|
|
50386
51011
|
"recordingOnboard.setSettings": [{
|
|
50387
51012
|
name: "deviceId",
|
|
50388
51013
|
form: "single",
|
|
@@ -50413,6 +51038,11 @@ Object.freeze({
|
|
|
50413
51038
|
form: "single",
|
|
50414
51039
|
optional: false
|
|
50415
51040
|
}],
|
|
51041
|
+
"sceneMonitor.getStatus": [{
|
|
51042
|
+
name: "deviceId",
|
|
51043
|
+
form: "single",
|
|
51044
|
+
optional: false
|
|
51045
|
+
}],
|
|
50416
51046
|
"sceneMonitor.listScenes": [{
|
|
50417
51047
|
name: "deviceId",
|
|
50418
51048
|
form: "single",
|
|
@@ -50438,6 +51068,11 @@ Object.freeze({
|
|
|
50438
51068
|
form: "single",
|
|
50439
51069
|
optional: false
|
|
50440
51070
|
}],
|
|
51071
|
+
"scriptRunner.getStatus": [{
|
|
51072
|
+
name: "deviceId",
|
|
51073
|
+
form: "single",
|
|
51074
|
+
optional: false
|
|
51075
|
+
}],
|
|
50441
51076
|
"scriptRunner.run": [{
|
|
50442
51077
|
name: "deviceId",
|
|
50443
51078
|
form: "single",
|
|
@@ -50448,11 +51083,31 @@ Object.freeze({
|
|
|
50448
51083
|
form: "single",
|
|
50449
51084
|
optional: false
|
|
50450
51085
|
}],
|
|
51086
|
+
"smoke.getStatus": [{
|
|
51087
|
+
name: "deviceId",
|
|
51088
|
+
form: "single",
|
|
51089
|
+
optional: false
|
|
51090
|
+
}],
|
|
51091
|
+
"snapshot.applyDeviceSettingsPatch": [{
|
|
51092
|
+
name: "deviceId",
|
|
51093
|
+
form: "single",
|
|
51094
|
+
optional: false
|
|
51095
|
+
}],
|
|
50451
51096
|
"snapshot.getDebugState": [{
|
|
50452
51097
|
name: "deviceId",
|
|
50453
51098
|
form: "single",
|
|
50454
51099
|
optional: false
|
|
50455
51100
|
}],
|
|
51101
|
+
"snapshot.getDeviceLiveContribution": [{
|
|
51102
|
+
name: "deviceId",
|
|
51103
|
+
form: "single",
|
|
51104
|
+
optional: false
|
|
51105
|
+
}],
|
|
51106
|
+
"snapshot.getDeviceSettingsContribution": [{
|
|
51107
|
+
name: "deviceId",
|
|
51108
|
+
form: "single",
|
|
51109
|
+
optional: false
|
|
51110
|
+
}],
|
|
50456
51111
|
"snapshot.getSnapshot": [{
|
|
50457
51112
|
name: "deviceId",
|
|
50458
51113
|
form: "single",
|
|
@@ -50469,6 +51124,11 @@ Object.freeze({
|
|
|
50469
51124
|
form: "array",
|
|
50470
51125
|
optional: false
|
|
50471
51126
|
}],
|
|
51127
|
+
"snapshot.getStatus": [{
|
|
51128
|
+
name: "deviceId",
|
|
51129
|
+
form: "single",
|
|
51130
|
+
optional: false
|
|
51131
|
+
}],
|
|
50472
51132
|
"snapshot.invalidateCache": [{
|
|
50473
51133
|
name: "deviceId",
|
|
50474
51134
|
form: "single",
|
|
@@ -50479,6 +51139,11 @@ Object.freeze({
|
|
|
50479
51139
|
form: "single",
|
|
50480
51140
|
optional: false
|
|
50481
51141
|
}],
|
|
51142
|
+
"streamBroker.applyDeviceSettingsPatch": [{
|
|
51143
|
+
name: "deviceId",
|
|
51144
|
+
form: "single",
|
|
51145
|
+
optional: false
|
|
51146
|
+
}],
|
|
50482
51147
|
"streamBroker.assignProfile": [{
|
|
50483
51148
|
name: "deviceId",
|
|
50484
51149
|
form: "single",
|
|
@@ -50494,6 +51159,16 @@ Object.freeze({
|
|
|
50494
51159
|
form: "single",
|
|
50495
51160
|
optional: false
|
|
50496
51161
|
}],
|
|
51162
|
+
"streamBroker.getDeviceLiveContribution": [{
|
|
51163
|
+
name: "deviceId",
|
|
51164
|
+
form: "single",
|
|
51165
|
+
optional: false
|
|
51166
|
+
}],
|
|
51167
|
+
"streamBroker.getDeviceSettingsContribution": [{
|
|
51168
|
+
name: "deviceId",
|
|
51169
|
+
form: "single",
|
|
51170
|
+
optional: false
|
|
51171
|
+
}],
|
|
50497
51172
|
"streamBroker.getStreamWithCodec": [{
|
|
50498
51173
|
name: "deviceId",
|
|
50499
51174
|
form: "single",
|
|
@@ -50554,16 +51229,46 @@ Object.freeze({
|
|
|
50554
51229
|
form: "single",
|
|
50555
51230
|
optional: false
|
|
50556
51231
|
}],
|
|
51232
|
+
"streamParams.getStatus": [{
|
|
51233
|
+
name: "deviceId",
|
|
51234
|
+
form: "single",
|
|
51235
|
+
optional: false
|
|
51236
|
+
}],
|
|
50557
51237
|
"streamParams.setProfile": [{
|
|
50558
51238
|
name: "deviceId",
|
|
50559
51239
|
form: "single",
|
|
50560
51240
|
optional: false
|
|
50561
51241
|
}],
|
|
51242
|
+
"switch.getStatus": [{
|
|
51243
|
+
name: "deviceId",
|
|
51244
|
+
form: "single",
|
|
51245
|
+
optional: false
|
|
51246
|
+
}],
|
|
50562
51247
|
"switch.setState": [{
|
|
50563
51248
|
name: "deviceId",
|
|
50564
51249
|
form: "single",
|
|
50565
51250
|
optional: false
|
|
50566
51251
|
}],
|
|
51252
|
+
"tamper.getStatus": [{
|
|
51253
|
+
name: "deviceId",
|
|
51254
|
+
form: "single",
|
|
51255
|
+
optional: false
|
|
51256
|
+
}],
|
|
51257
|
+
"temperatureSensor.getStatus": [{
|
|
51258
|
+
name: "deviceId",
|
|
51259
|
+
form: "single",
|
|
51260
|
+
optional: false
|
|
51261
|
+
}],
|
|
51262
|
+
"update.getStatus": [{
|
|
51263
|
+
name: "deviceId",
|
|
51264
|
+
form: "single",
|
|
51265
|
+
optional: false
|
|
51266
|
+
}],
|
|
51267
|
+
"vacuumControl.getStatus": [{
|
|
51268
|
+
name: "deviceId",
|
|
51269
|
+
form: "single",
|
|
51270
|
+
optional: false
|
|
51271
|
+
}],
|
|
50567
51272
|
"vacuumControl.locate": [{
|
|
50568
51273
|
name: "deviceId",
|
|
50569
51274
|
form: "single",
|
|
@@ -50599,6 +51304,11 @@ Object.freeze({
|
|
|
50599
51304
|
form: "single",
|
|
50600
51305
|
optional: false
|
|
50601
51306
|
}],
|
|
51307
|
+
"valve.getStatus": [{
|
|
51308
|
+
name: "deviceId",
|
|
51309
|
+
form: "single",
|
|
51310
|
+
optional: false
|
|
51311
|
+
}],
|
|
50602
51312
|
"valve.open": [{
|
|
50603
51313
|
name: "deviceId",
|
|
50604
51314
|
form: "single",
|
|
@@ -50614,6 +51324,11 @@ Object.freeze({
|
|
|
50614
51324
|
form: "single",
|
|
50615
51325
|
optional: false
|
|
50616
51326
|
}],
|
|
51327
|
+
"vibration.getStatus": [{
|
|
51328
|
+
name: "deviceId",
|
|
51329
|
+
form: "single",
|
|
51330
|
+
optional: false
|
|
51331
|
+
}],
|
|
50617
51332
|
"videoclips.dialClipStream": [{
|
|
50618
51333
|
name: "deviceId",
|
|
50619
51334
|
form: "single",
|
|
@@ -50649,6 +51364,11 @@ Object.freeze({
|
|
|
50649
51364
|
form: "single",
|
|
50650
51365
|
optional: false
|
|
50651
51366
|
}],
|
|
51367
|
+
"waterHeater.getStatus": [{
|
|
51368
|
+
name: "deviceId",
|
|
51369
|
+
form: "single",
|
|
51370
|
+
optional: false
|
|
51371
|
+
}],
|
|
50652
51372
|
"waterHeater.setAway": [{
|
|
50653
51373
|
name: "deviceId",
|
|
50654
51374
|
form: "single",
|
|
@@ -50664,6 +51384,11 @@ Object.freeze({
|
|
|
50664
51384
|
form: "single",
|
|
50665
51385
|
optional: false
|
|
50666
51386
|
}],
|
|
51387
|
+
"weather.getStatus": [{
|
|
51388
|
+
name: "deviceId",
|
|
51389
|
+
form: "single",
|
|
51390
|
+
optional: false
|
|
51391
|
+
}],
|
|
50667
51392
|
"webrtcSession.addIceCandidate": [{
|
|
50668
51393
|
name: "deviceId",
|
|
50669
51394
|
form: "single",
|
|
@@ -51189,6 +51914,18 @@ var STATE_SUMMARY_VARS = [
|
|
|
51189
51914
|
systemEventKinds: [...SUMMARISABLE],
|
|
51190
51915
|
systemEventDeliveries: ["summary"]
|
|
51191
51916
|
},
|
|
51917
|
+
{
|
|
51918
|
+
name: "summarySection",
|
|
51919
|
+
label: "Summary: this section",
|
|
51920
|
+
description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
|
|
51921
|
+
example: "Batterie scariche",
|
|
51922
|
+
group: "system",
|
|
51923
|
+
families: ["rule"],
|
|
51924
|
+
fields: [...RULE_TEXT],
|
|
51925
|
+
kinds: ["system"],
|
|
51926
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
51927
|
+
systemEventDeliveries: ["summary"]
|
|
51928
|
+
},
|
|
51192
51929
|
...STATE_SUMMARY_SECTION_VARS.map((v) => ({
|
|
51193
51930
|
name: v.name,
|
|
51194
51931
|
label: v.label,
|
|
@@ -51265,6 +52002,37 @@ var STATE_SUMMARY_VARS = [
|
|
|
51265
52002
|
[...RULE_TEXT],
|
|
51266
52003
|
...STATE_SUMMARY_VARS
|
|
51267
52004
|
];
|
|
52005
|
+
new Set([
|
|
52006
|
+
"disarmed",
|
|
52007
|
+
"armed_home",
|
|
52008
|
+
"armed_away",
|
|
52009
|
+
"armed_night",
|
|
52010
|
+
"armed_vacation",
|
|
52011
|
+
"armed_custom_bypass",
|
|
52012
|
+
"arming",
|
|
52013
|
+
"disarming",
|
|
52014
|
+
"pending",
|
|
52015
|
+
"triggered",
|
|
52016
|
+
"open",
|
|
52017
|
+
"opening",
|
|
52018
|
+
"closing",
|
|
52019
|
+
"closed",
|
|
52020
|
+
"stopped",
|
|
52021
|
+
"locked",
|
|
52022
|
+
"unlocked",
|
|
52023
|
+
"locking",
|
|
52024
|
+
"unlocking",
|
|
52025
|
+
"jammed",
|
|
52026
|
+
"on",
|
|
52027
|
+
"off",
|
|
52028
|
+
"home",
|
|
52029
|
+
"not_home",
|
|
52030
|
+
"matched",
|
|
52031
|
+
"diverged",
|
|
52032
|
+
"unknown",
|
|
52033
|
+
"latched",
|
|
52034
|
+
"live"
|
|
52035
|
+
]);
|
|
51268
52036
|
/**
|
|
51269
52037
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
51270
52038
|
*
|
|
@@ -51358,7 +52126,7 @@ var PreviewTextField = string().max(200);
|
|
|
51358
52126
|
* Whether the notification's preview is a STILL or a short animation.
|
|
51359
52127
|
*
|
|
51360
52128
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
51361
|
-
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
52129
|
+
* rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
|
|
51362
52130
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
51363
52131
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
51364
52132
|
* simply applies it to a dozen frames sampled across the render and assembles
|
|
@@ -51496,6 +52264,7 @@ TimelapseRuleInputSchema.extend({
|
|
|
51496
52264
|
createdAt: number(),
|
|
51497
52265
|
updatedAt: number()
|
|
51498
52266
|
});
|
|
52267
|
+
MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
|
|
51499
52268
|
object({
|
|
51500
52269
|
/**
|
|
51501
52270
|
* Fraction of the box's own size added on EACH side before cutting.
|