@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.js
CHANGED
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_net = require("node:net");
|
|
25
25
|
node_net = __toESM(node_net);
|
|
26
|
-
//#region ../types/dist/event-category-
|
|
26
|
+
//#region ../types/dist/event-category-BGmz_oxW.mjs
|
|
27
27
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
28
28
|
EventCategory["SystemBoot"] = "system.boot";
|
|
29
29
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -556,6 +556,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
556
556
|
*/
|
|
557
557
|
EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
|
|
558
558
|
EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
|
|
559
|
+
/**
|
|
560
|
+
* A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
|
|
561
|
+
* data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
|
|
562
|
+
* consumer is the orchestrator's camera-sensors bridge, which re-emits the
|
|
563
|
+
* camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
|
|
564
|
+
* for a camera with no attached sensor). Providers must not emit
|
|
565
|
+
* `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
|
|
566
|
+
* keeps it so (camera-grid is a named, deferred exception).
|
|
567
|
+
*/
|
|
559
568
|
EventCategory["ProviderMotion"] = "provider.motion";
|
|
560
569
|
EventCategory["ProviderDetection"] = "provider.detection";
|
|
561
570
|
EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
|
|
@@ -5394,7 +5403,7 @@ var ZodIssueCode = {
|
|
|
5394
5403
|
var ZodFirstPartyTypeKind;
|
|
5395
5404
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5396
5405
|
//#endregion
|
|
5397
|
-
//#region ../types/dist/sleep-
|
|
5406
|
+
//#region ../types/dist/sleep-CDCONfkt.mjs
|
|
5398
5407
|
/**
|
|
5399
5408
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5400
5409
|
* window to float samples (D455).
|
|
@@ -7437,7 +7446,7 @@ function errMsg(err) {
|
|
|
7437
7446
|
return String(err);
|
|
7438
7447
|
}
|
|
7439
7448
|
//#endregion
|
|
7440
|
-
//#region ../types/dist/composition-
|
|
7449
|
+
//#region ../types/dist/composition-Bzr7GwgP.mjs
|
|
7441
7450
|
/**
|
|
7442
7451
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
7443
7452
|
*
|
|
@@ -7491,21 +7500,20 @@ function portable(target) {
|
|
|
7491
7500
|
}
|
|
7492
7501
|
portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
|
|
7493
7502
|
/**
|
|
7494
|
-
*
|
|
7495
|
-
*
|
|
7503
|
+
* THE table "which boolean of this device type counts as HIGH", and the
|
|
7504
|
+
* pure evaluator of its EDGE.
|
|
7496
7505
|
*
|
|
7497
|
-
*
|
|
7498
|
-
*
|
|
7499
|
-
*
|
|
7500
|
-
*
|
|
7501
|
-
*
|
|
7502
|
-
*
|
|
7503
|
-
* SPOSTA qui e il doorbell la ri-esporta.
|
|
7506
|
+
* ONE table for everyone who asks "is this device HIGH?": the
|
|
7507
|
+
* recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
|
|
7508
|
+
* sensor markers, the orchestrator's camera-sensors bridge and
|
|
7509
|
+
* the sources of a composite doorbell (`doorbellFeatureSources`, D671).
|
|
7510
|
+
* A second copy would diverge at the first cap added, and the symptom — "the
|
|
7511
|
+
* sensor rings the doorbell but does not record" — is exactly D62.
|
|
7504
7512
|
*
|
|
7505
|
-
* ⚠
|
|
7506
|
-
*
|
|
7507
|
-
*
|
|
7508
|
-
*
|
|
7513
|
+
* ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
|
|
7514
|
+
* two must not be unified: that one answers "what is the state WORD for a
|
|
7515
|
+
* rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
|
|
7516
|
+
* boolean's EDGE counts". Deliberately different vocabularies.
|
|
7509
7517
|
*/
|
|
7510
7518
|
/**
|
|
7511
7519
|
* Known binary / switch source caps → the boolean slice field whose
|
|
@@ -9146,22 +9154,22 @@ var CLASS_MAP_MACRO_TARGETS = [
|
|
|
9146
9154
|
"package"
|
|
9147
9155
|
];
|
|
9148
9156
|
/**
|
|
9149
|
-
*
|
|
9150
|
-
*
|
|
9157
|
+
* The FIRST-LEVEL macro classes: those an object detector emits and that
|
|
9158
|
+
* an operator can select.
|
|
9151
9159
|
*
|
|
9152
|
-
*
|
|
9160
|
+
* They are the three offered by the `object-detection` step
|
|
9153
9161
|
* (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
|
|
9154
|
-
* `enabledMacroClasses`). `package`
|
|
9155
|
-
* `MACRO_LABELS` —
|
|
9156
|
-
* `package-detection`,
|
|
9157
|
-
*
|
|
9162
|
+
* `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
|
|
9163
|
+
* `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
|
|
9164
|
+
* `package-detection`, whose enablement is driven by zones, and offering the
|
|
9165
|
+
* same word twice has already made an operator turn on the COCO proxy
|
|
9158
9166
|
* (suitcase/backpack/handbag) lasciando spento il detector dedicato.
|
|
9159
9167
|
*
|
|
9160
|
-
*
|
|
9161
|
-
*
|
|
9162
|
-
* (`types/detection.ts`);
|
|
9163
|
-
* (`RecordingTriggers.objectClasses`)
|
|
9164
|
-
*
|
|
9168
|
+
* ONE list. Before today the same three were hand-written in the step's offer
|
|
9169
|
+
* and a second time as the union `FirstLevelMacro`
|
|
9170
|
+
* (`types/detection.ts`); a third copy for the recording trigger
|
|
9171
|
+
* (`RecordingTriggers.objectClasses`) would have made the later divergence
|
|
9172
|
+
* invisible.
|
|
9165
9173
|
*/
|
|
9166
9174
|
var FIRST_LEVEL_MACRO_CLASSES = [
|
|
9167
9175
|
"person",
|
|
@@ -9226,17 +9234,17 @@ var RecordingStorageModeSchema = _enum([
|
|
|
9226
9234
|
"on-device-decision"
|
|
9227
9235
|
]);
|
|
9228
9236
|
/**
|
|
9229
|
-
*
|
|
9230
|
-
*
|
|
9237
|
+
* The macro classes that can open a recording window — the same
|
|
9238
|
+
* three offered by the `object-detection` step, from ONE list
|
|
9231
9239
|
* ({@link FIRST_LEVEL_MACRO_CLASSES}).
|
|
9232
9240
|
*/
|
|
9233
9241
|
var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
|
|
9234
9242
|
/**
|
|
9235
|
-
* True
|
|
9243
|
+
* True when `values` does not repeat an element.
|
|
9236
9244
|
*
|
|
9237
|
-
*
|
|
9238
|
-
*
|
|
9239
|
-
*
|
|
9245
|
+
* A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
|
|
9246
|
+
* becomes a SOURCE in `bandTriggerSources`, and the same source twice
|
|
9247
|
+
* would count its windows twice in `segmentMissedByMs`.
|
|
9240
9248
|
*/
|
|
9241
9249
|
var noDuplicates = (values) => new Set(values).size === values.length;
|
|
9242
9250
|
/** Which detectors trigger an `events`-mode band. */
|
|
@@ -9244,34 +9252,34 @@ var RecordingTriggersSchema = object({
|
|
|
9244
9252
|
motion: boolean().optional(),
|
|
9245
9253
|
audioThresholdDbfs: number().optional(),
|
|
9246
9254
|
/**
|
|
9247
|
-
*
|
|
9248
|
-
*
|
|
9249
|
-
*
|
|
9250
|
-
*
|
|
9255
|
+
* The macro classes whose detection opens a window. ABSENT = the source
|
|
9256
|
+
* is not listened to; an EMPTY array is rejected, because "events band, object
|
|
9257
|
+
* trigger on, no class" is the same shape "enabled and records
|
|
9258
|
+
* nothing, forever" that `eventsBandCanEverDemand` is written against.
|
|
9251
9259
|
*
|
|
9252
|
-
*
|
|
9253
|
-
*
|
|
9254
|
-
* `minConfidence<Macro>`
|
|
9255
|
-
* (`source: 'onboard'`)
|
|
9256
|
-
*
|
|
9260
|
+
* The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
|
|
9261
|
+
* those that went through `enabledMacroClasses`, the
|
|
9262
|
+
* `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
|
|
9263
|
+
* (`source: 'onboard'`) goes through none of those gates and does NOT open
|
|
9264
|
+
* windows — see `recorder/object-trigger.ts`.
|
|
9257
9265
|
*/
|
|
9258
9266
|
objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
|
|
9259
9267
|
/**
|
|
9260
|
-
*
|
|
9261
|
-
*
|
|
9268
|
+
* The LINKED devices whose RISING EDGE opens a window. Absent = the source
|
|
9269
|
+
* is not listened to; an empty array is rejected for the same reason as
|
|
9262
9270
|
* `objectClasses`.
|
|
9263
9271
|
*
|
|
9264
|
-
*
|
|
9265
|
-
*
|
|
9266
|
-
*
|
|
9267
|
-
*
|
|
9268
|
-
* device (D12) —
|
|
9272
|
+
* These are SOURCE device ids, not cameras: the band names them, so the
|
|
9273
|
+
* hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
|
|
9274
|
+
* does no RPC. The OFFER from which the operator picks them is another question, and
|
|
9275
|
+
* is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
|
|
9276
|
+
* device (D12) — never a global list of caps.
|
|
9269
9277
|
*
|
|
9270
|
-
*
|
|
9271
|
-
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`)
|
|
9272
|
-
*
|
|
9273
|
-
*
|
|
9274
|
-
*
|
|
9278
|
+
* What "high" means depends on the device TYPE and is not decided here:
|
|
9279
|
+
* `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
|
|
9280
|
+
* the same one as the composite doorbell (D671). And it is the EDGE, not
|
|
9281
|
+
* the level: a contact found already open at runner restart does not
|
|
9282
|
+
* record.
|
|
9275
9283
|
*/
|
|
9276
9284
|
sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
|
|
9277
9285
|
});
|
|
@@ -10348,7 +10356,7 @@ var DecoderSessionConfigSchema = object({
|
|
|
10348
10356
|
* - **VALUE** — at which level, for which scope, until when. That stays ONE
|
|
10349
10357
|
* thing: the logging settings document on the `system` cap. Two authorities
|
|
10350
10358
|
* over the values is the exact defect
|
|
10351
|
-
* `docs/design/plans/2026-08-26-
|
|
10359
|
+
* `docs/design/plans/2026-08-26-per-component-logging.md` was written to
|
|
10352
10360
|
* remove; re-introducing it from the cure side would be grotesque.
|
|
10353
10361
|
*
|
|
10354
10362
|
* Nothing in this file reads a clock, an env var or a store. The registry is
|
|
@@ -11624,6 +11632,68 @@ method(object({
|
|
|
11624
11632
|
password: string()
|
|
11625
11633
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
11626
11634
|
/**
|
|
11635
|
+
* How long one snapshot may take end to end: the pinned copy of the whole
|
|
11636
|
+
* database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
|
|
11637
|
+
* disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
|
|
11638
|
+
* generous because a timeout fails the whole backup run.
|
|
11639
|
+
*/
|
|
11640
|
+
var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
|
|
11641
|
+
/**
|
|
11642
|
+
* The databases an owner snapshots — declared by the OWNER, so a caller never
|
|
11643
|
+
* guesses which file is live from what sits beside it (a cleanly closed
|
|
11644
|
+
* database has no sidecars and is just as owned). Paths are absolute on the
|
|
11645
|
+
* owner's host.
|
|
11646
|
+
*/
|
|
11647
|
+
var DatabaseSnapshotTargetsSchema = object({ databases: array(object({ livePath: string() })) });
|
|
11648
|
+
/** One b-tree table of the snapshot and the rows it holds. */
|
|
11649
|
+
var DatabaseSnapshotTableSchema = object({
|
|
11650
|
+
name: string(),
|
|
11651
|
+
rows: number().int().nonnegative()
|
|
11652
|
+
});
|
|
11653
|
+
/**
|
|
11654
|
+
* What the owner wrote. Every path is ABSOLUTE on the owner's host — the
|
|
11655
|
+
* caller pins the call to its own node, so it can read the file; a caller
|
|
11656
|
+
* that finds the path outside its own data root refuses it rather than
|
|
11657
|
+
* archiving something it cannot place.
|
|
11658
|
+
*/
|
|
11659
|
+
var DatabaseSnapshotResultSchema = object({
|
|
11660
|
+
/** The live database the snapshot copies. Never to be copied as a file. */
|
|
11661
|
+
livePath: string(),
|
|
11662
|
+
/** The verified copy: `<livePath>` + {@link DATABASE_SNAPSHOT_SUFFIX}. */
|
|
11663
|
+
snapshotPath: string(),
|
|
11664
|
+
sizeBytes: number().int().nonnegative(),
|
|
11665
|
+
pageCount: number().int().nonnegative(),
|
|
11666
|
+
pageSize: number().int().positive(),
|
|
11667
|
+
/**
|
|
11668
|
+
* Every b-tree table with its row count. Read inside the SAME read
|
|
11669
|
+
* transaction the copy was taken from, and found EQUAL on the copy — so
|
|
11670
|
+
* this is the content of the snapshot, not an estimate of the source.
|
|
11671
|
+
*/
|
|
11672
|
+
tables: array(DatabaseSnapshotTableSchema),
|
|
11673
|
+
/** Wall time of the pinned copy (row counts included). */
|
|
11674
|
+
copyMs: number().nonnegative(),
|
|
11675
|
+
/** Wall time of the checks on the copy (`integrity_check`, row counts). */
|
|
11676
|
+
verifyMs: number().nonnegative(),
|
|
11677
|
+
/** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
|
|
11678
|
+
takenAt: number()
|
|
11679
|
+
});
|
|
11680
|
+
/**
|
|
11681
|
+
* A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
|
|
11682
|
+
* the same facts, with both paths relative to the archive root (the node's
|
|
11683
|
+
* data dir), because an archive outlives the host that made it.
|
|
11684
|
+
*/
|
|
11685
|
+
var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
|
|
11686
|
+
/** Archive-relative path of the live database the archive does NOT carry. */
|
|
11687
|
+
livePath: string(),
|
|
11688
|
+
/** Archive-relative path of the verified copy it carries in its place. */
|
|
11689
|
+
snapshotPath: string()
|
|
11690
|
+
});
|
|
11691
|
+
method(object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }), method(object({}), DatabaseSnapshotResultSchema, {
|
|
11692
|
+
kind: "mutation",
|
|
11693
|
+
auth: "admin",
|
|
11694
|
+
timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
|
|
11695
|
+
});
|
|
11696
|
+
/**
|
|
11627
11697
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
11628
11698
|
* `id = <addonId>:<subId>` from its provider lookup so consumers
|
|
11629
11699
|
* (admin UI, restore flow) see one canonical key.
|
|
@@ -11734,7 +11804,12 @@ var ArchiveManifestSchema = object({
|
|
|
11734
11804
|
locations: array(string()),
|
|
11735
11805
|
entries: array(ArchiveEntrySchema),
|
|
11736
11806
|
totalBytes: number(),
|
|
11737
|
-
totalFiles: number()
|
|
11807
|
+
totalFiles: number(),
|
|
11808
|
+
/**
|
|
11809
|
+
* Live SQLite databases this archive carries as their OWNER's verified
|
|
11810
|
+
* snapshot instead of as files (D693). Absent on archives made before.
|
|
11811
|
+
*/
|
|
11812
|
+
sqliteSnapshots: array(ArchiveSqliteSnapshotSchema).optional()
|
|
11738
11813
|
});
|
|
11739
11814
|
var LocationStatSchema = object({
|
|
11740
11815
|
name: string(),
|
|
@@ -11992,7 +12067,7 @@ var BrokerStatusEnum = _enum([
|
|
|
11992
12067
|
"unreachable",
|
|
11993
12068
|
"error"
|
|
11994
12069
|
]);
|
|
11995
|
-
var BrokerInfoSchema
|
|
12070
|
+
var BrokerInfoSchema = object({
|
|
11996
12071
|
/** Stable broker id. Persisted; survives addon restarts. */
|
|
11997
12072
|
id: string(),
|
|
11998
12073
|
/** Addon id of the provider that OWNS this broker.
|
|
@@ -12125,7 +12200,7 @@ var GetStateInputSchema = object({
|
|
|
12125
12200
|
* HA: entity_id (returns the cached entity state). */
|
|
12126
12201
|
key: string()
|
|
12127
12202
|
});
|
|
12128
|
-
method(ListInputSchema, array(BrokerInfoSchema
|
|
12203
|
+
method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
|
|
12129
12204
|
kind: "mutation",
|
|
12130
12205
|
auth: "admin"
|
|
12131
12206
|
}), method(RemoveInputSchema, _void(), {
|
|
@@ -13260,242 +13335,6 @@ var CompositionBlockStateSchema = object({
|
|
|
13260
13335
|
reason: string().optional(),
|
|
13261
13336
|
fields: array(CompositionFieldStateSchema)
|
|
13262
13337
|
});
|
|
13263
|
-
var NUMBER = {
|
|
13264
|
-
kind: "fixed",
|
|
13265
|
-
result: ["number"]
|
|
13266
|
-
};
|
|
13267
|
-
var BOOLEAN = {
|
|
13268
|
-
kind: "fixed",
|
|
13269
|
-
result: ["boolean"]
|
|
13270
|
-
};
|
|
13271
|
-
Object.freeze({
|
|
13272
|
-
min: NUMBER,
|
|
13273
|
-
max: NUMBER,
|
|
13274
|
-
abs: NUMBER,
|
|
13275
|
-
floor: NUMBER,
|
|
13276
|
-
ceil: NUMBER,
|
|
13277
|
-
sqrt: NUMBER,
|
|
13278
|
-
round: NUMBER,
|
|
13279
|
-
pow: NUMBER,
|
|
13280
|
-
clamp: NUMBER,
|
|
13281
|
-
avg: NUMBER,
|
|
13282
|
-
sum: NUMBER,
|
|
13283
|
-
age: NUMBER,
|
|
13284
|
-
convert: NUMBER,
|
|
13285
|
-
coalesce: { kind: "coalesce" },
|
|
13286
|
-
any: BOOLEAN,
|
|
13287
|
-
all: BOOLEAN,
|
|
13288
|
-
within: BOOLEAN,
|
|
13289
|
-
latest: {
|
|
13290
|
-
kind: "fixed",
|
|
13291
|
-
result: ["number", "null"]
|
|
13292
|
-
},
|
|
13293
|
-
number: {
|
|
13294
|
-
kind: "fixed",
|
|
13295
|
-
result: ["number", "null"]
|
|
13296
|
-
},
|
|
13297
|
-
rose: {
|
|
13298
|
-
kind: "fixed",
|
|
13299
|
-
result: ["number", "null"]
|
|
13300
|
-
},
|
|
13301
|
-
count: NUMBER
|
|
13302
|
-
});
|
|
13303
|
-
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
13304
|
-
/**
|
|
13305
|
-
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
13306
|
-
* device of that type, or an existing one that lacks them, can be given. The
|
|
13307
|
-
* blockers are the validator's own refusal codes, and a spec compares this
|
|
13308
|
-
* listing with `planComposition` for every capability — the editor can never
|
|
13309
|
-
* offer a feature the save would refuse for the same reason.
|
|
13310
|
-
*/
|
|
13311
|
-
var ComposableFieldSchema = object({
|
|
13312
|
-
path: string(),
|
|
13313
|
-
kind: CompositionFieldKindSchema,
|
|
13314
|
-
nullable: boolean(),
|
|
13315
|
-
required: boolean(),
|
|
13316
|
-
enumValues: array(string()).optional()
|
|
13317
|
-
});
|
|
13318
|
-
var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
13319
|
-
cap: string(),
|
|
13320
|
-
fields: array(ComposableFieldSchema),
|
|
13321
|
-
/** Present for an item-array cap (`consumables.items`). */
|
|
13322
|
-
itemArray: object({
|
|
13323
|
-
path: string(),
|
|
13324
|
-
keyField: string()
|
|
13325
|
-
}).optional()
|
|
13326
|
-
})) });
|
|
13327
|
-
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
13328
|
-
* agent is the reason placement is not fixed to the hub. */
|
|
13329
|
-
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
13330
|
-
/** What a block's process is doing. Mirrors the addon runner's own lifecycle so
|
|
13331
|
-
* a failing block reads the same way a failing addon does. `degraded` is a
|
|
13332
|
-
* composition on an existing device with a field handed back to the native
|
|
13333
|
-
* provider while its source is unavailable (S1b, D663); the error names it. */
|
|
13334
|
-
var CoreBlockStatusSchema = _enum([
|
|
13335
|
-
"stopped",
|
|
13336
|
-
"starting",
|
|
13337
|
-
"running",
|
|
13338
|
-
"degraded",
|
|
13339
|
-
"failed"
|
|
13340
|
-
]);
|
|
13341
|
-
/** Client-authored fields. */
|
|
13342
|
-
var CoreBlockInputSchema = object({
|
|
13343
|
-
name: string().min(1).max(120),
|
|
13344
|
-
/** TypeScript source. Compiled server-side before it is ever stored — a
|
|
13345
|
-
* block that does not compile is a fork failure the operator would meet
|
|
13346
|
-
* minutes later, in a log, instead of in the editor. */
|
|
13347
|
-
code: string().max(2e5),
|
|
13348
|
-
enabled: boolean(),
|
|
13349
|
-
placement: CoreBlockPlacementSchema,
|
|
13350
|
-
/**
|
|
13351
|
-
* Integration the block's devices hang from. Absent = the system integration
|
|
13352
|
-
* blocks share. A block may declare its own instead.
|
|
13353
|
-
*/
|
|
13354
|
-
integrationId: string().optional()
|
|
13355
|
-
});
|
|
13356
|
-
/**
|
|
13357
|
-
* What a block IS (D659). Absent means `code` — every row stored before this
|
|
13358
|
-
* union keeps working unchanged.
|
|
13359
|
-
* - `code`: the TypeScript in `code`, compiled and run in its own runner;
|
|
13360
|
-
* - `recipe`: RESERVED (automations), stored shape only; refused at run by name;
|
|
13361
|
-
* - `composition`: declarative, run by the shared `composer`; `code` is `''`.
|
|
13362
|
-
*/
|
|
13363
|
-
var CoreBlockSourceSchema = discriminatedUnion("kind", [
|
|
13364
|
-
object({ kind: literal("code") }),
|
|
13365
|
-
object({
|
|
13366
|
-
kind: literal("recipe"),
|
|
13367
|
-
recipe: AutomationRecipeSchema
|
|
13368
|
-
}),
|
|
13369
|
-
object({
|
|
13370
|
-
kind: literal("composition"),
|
|
13371
|
-
composition: CompositionSchema
|
|
13372
|
-
})
|
|
13373
|
-
]);
|
|
13374
|
-
/**
|
|
13375
|
-
* The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7).
|
|
13376
|
-
*
|
|
13377
|
-
* `name`: REQUIRED for a `new` target — the block's name IS the device's name
|
|
13378
|
-
* (D659). ABSENT for an `existing` target — a customization has no name of its
|
|
13379
|
-
* own; the server derives one (`customizationBlockName`, D663) and refuses a
|
|
13380
|
-
* client-sent name by name.
|
|
13381
|
-
*/
|
|
13382
|
-
var CompositionBlockInputSchema = object({
|
|
13383
|
-
name: string().min(1).max(120).optional(),
|
|
13384
|
-
enabled: boolean(),
|
|
13385
|
-
composition: CompositionSchema
|
|
13386
|
-
});
|
|
13387
|
-
/** A stored block. */
|
|
13388
|
-
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
13389
|
-
id: string(),
|
|
13390
|
-
createdAt: number(),
|
|
13391
|
-
updatedAt: number(),
|
|
13392
|
-
/** Server-stamped author. */
|
|
13393
|
-
createdBy: string(),
|
|
13394
|
-
status: CoreBlockStatusSchema,
|
|
13395
|
-
/**
|
|
13396
|
-
* Why the block is not running, when it is not. The operator's ONLY window
|
|
13397
|
-
* into a block that failed at load — a block that is silently absent is the
|
|
13398
|
-
* failure mode this whole feature has to avoid.
|
|
13399
|
-
*/
|
|
13400
|
-
lastError: string().optional(),
|
|
13401
|
-
/** Ms epoch of the last state change. */
|
|
13402
|
-
lastChangedAt: number(),
|
|
13403
|
-
/** What the block is. Absent means `code` (D659). */
|
|
13404
|
-
source: CoreBlockSourceSchema.optional()
|
|
13405
|
-
});
|
|
13406
|
-
/** A stored composition block and what the composer says about it. */
|
|
13407
|
-
var CompositionViewSchema = object({
|
|
13408
|
-
block: CoreBlockSchema,
|
|
13409
|
-
state: discriminatedUnion("kind", [object({
|
|
13410
|
-
kind: literal("answered"),
|
|
13411
|
-
state: CompositionBlockStateSchema.nullable()
|
|
13412
|
-
}), object({
|
|
13413
|
-
kind: literal("unreachable"),
|
|
13414
|
-
error: string()
|
|
13415
|
-
})])
|
|
13416
|
-
});
|
|
13417
|
-
/**
|
|
13418
|
-
* A read of the stored compositions. `not-loaded` while the `core_blocks`
|
|
13419
|
-
* table has not been READ: an empty answer then would make "not yet known"
|
|
13420
|
-
* look like "none", and invite the operator to recreate what exists (D315).
|
|
13421
|
-
*/
|
|
13422
|
-
var CompositionsNotLoadedSchema = object({
|
|
13423
|
-
state: literal("not-loaded"),
|
|
13424
|
-
reason: string()
|
|
13425
|
-
});
|
|
13426
|
-
var CompositionListReadSchema = discriminatedUnion("state", [object({
|
|
13427
|
-
state: literal("loaded"),
|
|
13428
|
-
views: array(CompositionViewSchema)
|
|
13429
|
-
}), CompositionsNotLoadedSchema]);
|
|
13430
|
-
var CompositionGetReadSchema = discriminatedUnion("state", [object({
|
|
13431
|
-
state: literal("loaded"),
|
|
13432
|
-
view: CompositionViewSchema.nullable()
|
|
13433
|
-
}), CompositionsNotLoadedSchema]);
|
|
13434
|
-
/** The customization of one existing device, found by its TARGET, or `not-loaded` (D315). */
|
|
13435
|
-
var CompositionCustomizationReadSchema = discriminatedUnion("state", [object({
|
|
13436
|
-
state: literal("loaded"),
|
|
13437
|
-
view: CompositionViewSchema.nullable()
|
|
13438
|
-
}), CompositionsNotLoadedSchema]);
|
|
13439
|
-
/** What a compile attempt produced. */
|
|
13440
|
-
var CoreBlockCompileResultSchema = object({
|
|
13441
|
-
ok: boolean(),
|
|
13442
|
-
/** Present when `ok` is false — the first error, in the author's words. */
|
|
13443
|
-
error: string().optional(),
|
|
13444
|
-
line: number().optional(),
|
|
13445
|
-
column: number().optional()
|
|
13446
|
-
});
|
|
13447
|
-
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 }), {
|
|
13448
|
-
kind: "mutation",
|
|
13449
|
-
auth: "admin",
|
|
13450
|
-
caller: "required"
|
|
13451
|
-
}), method(object({
|
|
13452
|
-
blockId: string(),
|
|
13453
|
-
block: CoreBlockInputSchema.partial()
|
|
13454
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13455
|
-
kind: "mutation",
|
|
13456
|
-
auth: "admin",
|
|
13457
|
-
caller: "required"
|
|
13458
|
-
}), method(object({ blockId: string() }), object({ success: literal(true) }), {
|
|
13459
|
-
kind: "mutation",
|
|
13460
|
-
auth: "admin"
|
|
13461
|
-
}), method(object({
|
|
13462
|
-
blockId: string(),
|
|
13463
|
-
enabled: boolean()
|
|
13464
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13465
|
-
kind: "mutation",
|
|
13466
|
-
auth: "admin"
|
|
13467
|
-
}), method(object({ blockId: string() }), object({ block: CoreBlockSchema }), {
|
|
13468
|
-
kind: "mutation",
|
|
13469
|
-
auth: "admin"
|
|
13470
|
-
}), method(object({ code: string() }), CoreBlockCompileResultSchema, {
|
|
13471
|
-
kind: "mutation",
|
|
13472
|
-
auth: "admin"
|
|
13473
|
-
}), method(object({}), object({ libs: array(object({
|
|
13474
|
-
filePath: string(),
|
|
13475
|
-
content: string()
|
|
13476
|
-
})) }), { auth: "admin" }), method(object({ block: CompositionBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13477
|
-
kind: "mutation",
|
|
13478
|
-
auth: "admin",
|
|
13479
|
-
caller: "required"
|
|
13480
|
-
}), method(object({
|
|
13481
|
-
blockId: string(),
|
|
13482
|
-
expectedUpdatedAt: number(),
|
|
13483
|
-
block: CompositionBlockInputSchema.partial()
|
|
13484
|
-
}), object({ block: CoreBlockSchema }), {
|
|
13485
|
-
kind: "mutation",
|
|
13486
|
-
auth: "admin",
|
|
13487
|
-
caller: "required"
|
|
13488
|
-
}), method(object({ blockId: string() }), CompositionGetReadSchema, { auth: "admin" }), method(object({}), CompositionListReadSchema, { auth: "admin" }), method(object({
|
|
13489
|
-
addonId: string().min(1),
|
|
13490
|
-
stableId: string().min(1)
|
|
13491
|
-
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({ deviceType: _enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }), method(object({
|
|
13492
|
-
composition: CompositionSchema,
|
|
13493
|
-
blockId: string().optional()
|
|
13494
|
-
}), CompositionValidationSchema, {
|
|
13495
|
-
kind: "mutation",
|
|
13496
|
-
auth: "admin",
|
|
13497
|
-
access: "view"
|
|
13498
|
-
});
|
|
13499
13338
|
var ComposerBlockSchema = object({
|
|
13500
13339
|
id: string().min(1),
|
|
13501
13340
|
name: string().min(1).max(120),
|
|
@@ -13542,6 +13381,242 @@ method(object({
|
|
|
13542
13381
|
kind: "mutation",
|
|
13543
13382
|
auth: "admin"
|
|
13544
13383
|
}), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
13384
|
+
var NUMBER = {
|
|
13385
|
+
kind: "fixed",
|
|
13386
|
+
result: ["number"]
|
|
13387
|
+
};
|
|
13388
|
+
var BOOLEAN = {
|
|
13389
|
+
kind: "fixed",
|
|
13390
|
+
result: ["boolean"]
|
|
13391
|
+
};
|
|
13392
|
+
Object.freeze({
|
|
13393
|
+
min: NUMBER,
|
|
13394
|
+
max: NUMBER,
|
|
13395
|
+
abs: NUMBER,
|
|
13396
|
+
floor: NUMBER,
|
|
13397
|
+
ceil: NUMBER,
|
|
13398
|
+
sqrt: NUMBER,
|
|
13399
|
+
round: NUMBER,
|
|
13400
|
+
pow: NUMBER,
|
|
13401
|
+
clamp: NUMBER,
|
|
13402
|
+
avg: NUMBER,
|
|
13403
|
+
sum: NUMBER,
|
|
13404
|
+
age: NUMBER,
|
|
13405
|
+
convert: NUMBER,
|
|
13406
|
+
coalesce: { kind: "coalesce" },
|
|
13407
|
+
any: BOOLEAN,
|
|
13408
|
+
all: BOOLEAN,
|
|
13409
|
+
within: BOOLEAN,
|
|
13410
|
+
latest: {
|
|
13411
|
+
kind: "fixed",
|
|
13412
|
+
result: ["number", "null"]
|
|
13413
|
+
},
|
|
13414
|
+
number: {
|
|
13415
|
+
kind: "fixed",
|
|
13416
|
+
result: ["number", "null"]
|
|
13417
|
+
},
|
|
13418
|
+
rose: {
|
|
13419
|
+
kind: "fixed",
|
|
13420
|
+
result: ["number", "null"]
|
|
13421
|
+
},
|
|
13422
|
+
count: NUMBER
|
|
13423
|
+
});
|
|
13424
|
+
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
13425
|
+
/**
|
|
13426
|
+
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
13427
|
+
* device of that type, or an existing one that lacks them, can be given. The
|
|
13428
|
+
* blockers are the validator's own refusal codes, and a spec compares this
|
|
13429
|
+
* listing with `planComposition` for every capability — the editor can never
|
|
13430
|
+
* offer a feature the save would refuse for the same reason.
|
|
13431
|
+
*/
|
|
13432
|
+
var ComposableFieldSchema = object({
|
|
13433
|
+
path: string(),
|
|
13434
|
+
kind: CompositionFieldKindSchema,
|
|
13435
|
+
nullable: boolean(),
|
|
13436
|
+
required: boolean(),
|
|
13437
|
+
enumValues: array(string()).optional()
|
|
13438
|
+
});
|
|
13439
|
+
var ComposableCapabilitiesSchema = object({ caps: array(object({
|
|
13440
|
+
cap: string(),
|
|
13441
|
+
fields: array(ComposableFieldSchema),
|
|
13442
|
+
/** Present for an item-array cap (`consumables.items`). */
|
|
13443
|
+
itemArray: object({
|
|
13444
|
+
path: string(),
|
|
13445
|
+
keyField: string()
|
|
13446
|
+
}).optional()
|
|
13447
|
+
})) });
|
|
13448
|
+
/** Where a block runs. The operator chooses — a block driving a device on an
|
|
13449
|
+
* agent is the reason placement is not fixed to the hub. */
|
|
13450
|
+
var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
|
|
13451
|
+
/** What a block's process is doing. Mirrors the addon runner's own lifecycle so
|
|
13452
|
+
* a failing block reads the same way a failing addon does. `degraded` is a
|
|
13453
|
+
* composition on an existing device with a field handed back to the native
|
|
13454
|
+
* provider while its source is unavailable (S1b, D663); the error names it. */
|
|
13455
|
+
var CoreBlockStatusSchema = _enum([
|
|
13456
|
+
"stopped",
|
|
13457
|
+
"starting",
|
|
13458
|
+
"running",
|
|
13459
|
+
"degraded",
|
|
13460
|
+
"failed"
|
|
13461
|
+
]);
|
|
13462
|
+
/** Client-authored fields. */
|
|
13463
|
+
var CoreBlockInputSchema = object({
|
|
13464
|
+
name: string().min(1).max(120),
|
|
13465
|
+
/** TypeScript source. Compiled server-side before it is ever stored — a
|
|
13466
|
+
* block that does not compile is a fork failure the operator would meet
|
|
13467
|
+
* minutes later, in a log, instead of in the editor. */
|
|
13468
|
+
code: string().max(2e5),
|
|
13469
|
+
enabled: boolean(),
|
|
13470
|
+
placement: CoreBlockPlacementSchema,
|
|
13471
|
+
/**
|
|
13472
|
+
* Integration the block's devices hang from. Absent = the system integration
|
|
13473
|
+
* blocks share. A block may declare its own instead.
|
|
13474
|
+
*/
|
|
13475
|
+
integrationId: string().optional()
|
|
13476
|
+
});
|
|
13477
|
+
/**
|
|
13478
|
+
* What a block IS (D659). Absent means `code` — every row stored before this
|
|
13479
|
+
* union keeps working unchanged.
|
|
13480
|
+
* - `code`: the TypeScript in `code`, compiled and run in its own runner;
|
|
13481
|
+
* - `recipe`: RESERVED (automations), stored shape only; refused at run by name;
|
|
13482
|
+
* - `composition`: declarative, run by the shared `composer`; `code` is `''`.
|
|
13483
|
+
*/
|
|
13484
|
+
var CoreBlockSourceSchema = discriminatedUnion("kind", [
|
|
13485
|
+
object({ kind: literal("code") }),
|
|
13486
|
+
object({
|
|
13487
|
+
kind: literal("recipe"),
|
|
13488
|
+
recipe: AutomationRecipeSchema
|
|
13489
|
+
}),
|
|
13490
|
+
object({
|
|
13491
|
+
kind: literal("composition"),
|
|
13492
|
+
composition: CompositionSchema
|
|
13493
|
+
})
|
|
13494
|
+
]);
|
|
13495
|
+
/**
|
|
13496
|
+
* The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7).
|
|
13497
|
+
*
|
|
13498
|
+
* `name`: REQUIRED for a `new` target — the block's name IS the device's name
|
|
13499
|
+
* (D659). ABSENT for an `existing` target — a customization has no name of its
|
|
13500
|
+
* own; the server derives one (`customizationBlockName`, D663) and refuses a
|
|
13501
|
+
* client-sent name by name.
|
|
13502
|
+
*/
|
|
13503
|
+
var CompositionBlockInputSchema = object({
|
|
13504
|
+
name: string().min(1).max(120).optional(),
|
|
13505
|
+
enabled: boolean(),
|
|
13506
|
+
composition: CompositionSchema
|
|
13507
|
+
});
|
|
13508
|
+
/** A stored block. */
|
|
13509
|
+
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
13510
|
+
id: string(),
|
|
13511
|
+
createdAt: number(),
|
|
13512
|
+
updatedAt: number(),
|
|
13513
|
+
/** Server-stamped author. */
|
|
13514
|
+
createdBy: string(),
|
|
13515
|
+
status: CoreBlockStatusSchema,
|
|
13516
|
+
/**
|
|
13517
|
+
* Why the block is not running, when it is not. The operator's ONLY window
|
|
13518
|
+
* into a block that failed at load — a block that is silently absent is the
|
|
13519
|
+
* failure mode this whole feature has to avoid.
|
|
13520
|
+
*/
|
|
13521
|
+
lastError: string().optional(),
|
|
13522
|
+
/** Ms epoch of the last state change. */
|
|
13523
|
+
lastChangedAt: number(),
|
|
13524
|
+
/** What the block is. Absent means `code` (D659). */
|
|
13525
|
+
source: CoreBlockSourceSchema.optional()
|
|
13526
|
+
});
|
|
13527
|
+
/** A stored composition block and what the composer says about it. */
|
|
13528
|
+
var CompositionViewSchema = object({
|
|
13529
|
+
block: CoreBlockSchema,
|
|
13530
|
+
state: discriminatedUnion("kind", [object({
|
|
13531
|
+
kind: literal("answered"),
|
|
13532
|
+
state: CompositionBlockStateSchema.nullable()
|
|
13533
|
+
}), object({
|
|
13534
|
+
kind: literal("unreachable"),
|
|
13535
|
+
error: string()
|
|
13536
|
+
})])
|
|
13537
|
+
});
|
|
13538
|
+
/**
|
|
13539
|
+
* A read of the stored compositions. `not-loaded` while the `core_blocks`
|
|
13540
|
+
* table has not been READ: an empty answer then would make "not yet known"
|
|
13541
|
+
* look like "none", and invite the operator to recreate what exists (D315).
|
|
13542
|
+
*/
|
|
13543
|
+
var CompositionsNotLoadedSchema = object({
|
|
13544
|
+
state: literal("not-loaded"),
|
|
13545
|
+
reason: string()
|
|
13546
|
+
});
|
|
13547
|
+
var CompositionListReadSchema = discriminatedUnion("state", [object({
|
|
13548
|
+
state: literal("loaded"),
|
|
13549
|
+
views: array(CompositionViewSchema)
|
|
13550
|
+
}), CompositionsNotLoadedSchema]);
|
|
13551
|
+
var CompositionGetReadSchema = discriminatedUnion("state", [object({
|
|
13552
|
+
state: literal("loaded"),
|
|
13553
|
+
view: CompositionViewSchema.nullable()
|
|
13554
|
+
}), CompositionsNotLoadedSchema]);
|
|
13555
|
+
/** The customization of one existing device, found by its TARGET, or `not-loaded` (D315). */
|
|
13556
|
+
var CompositionCustomizationReadSchema = discriminatedUnion("state", [object({
|
|
13557
|
+
state: literal("loaded"),
|
|
13558
|
+
view: CompositionViewSchema.nullable()
|
|
13559
|
+
}), CompositionsNotLoadedSchema]);
|
|
13560
|
+
/** What a compile attempt produced. */
|
|
13561
|
+
var CoreBlockCompileResultSchema = object({
|
|
13562
|
+
ok: boolean(),
|
|
13563
|
+
/** Present when `ok` is false — the first error, in the author's words. */
|
|
13564
|
+
error: string().optional(),
|
|
13565
|
+
line: number().optional(),
|
|
13566
|
+
column: number().optional()
|
|
13567
|
+
});
|
|
13568
|
+
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 }), {
|
|
13569
|
+
kind: "mutation",
|
|
13570
|
+
auth: "admin",
|
|
13571
|
+
caller: "required"
|
|
13572
|
+
}), method(object({
|
|
13573
|
+
blockId: string(),
|
|
13574
|
+
block: CoreBlockInputSchema.partial()
|
|
13575
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13576
|
+
kind: "mutation",
|
|
13577
|
+
auth: "admin",
|
|
13578
|
+
caller: "required"
|
|
13579
|
+
}), method(object({ blockId: string() }), object({ success: literal(true) }), {
|
|
13580
|
+
kind: "mutation",
|
|
13581
|
+
auth: "admin"
|
|
13582
|
+
}), method(object({
|
|
13583
|
+
blockId: string(),
|
|
13584
|
+
enabled: boolean()
|
|
13585
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13586
|
+
kind: "mutation",
|
|
13587
|
+
auth: "admin"
|
|
13588
|
+
}), method(object({ blockId: string() }), object({ block: CoreBlockSchema }), {
|
|
13589
|
+
kind: "mutation",
|
|
13590
|
+
auth: "admin"
|
|
13591
|
+
}), method(object({ code: string() }), CoreBlockCompileResultSchema, {
|
|
13592
|
+
kind: "mutation",
|
|
13593
|
+
auth: "admin"
|
|
13594
|
+
}), method(object({}), object({ libs: array(object({
|
|
13595
|
+
filePath: string(),
|
|
13596
|
+
content: string()
|
|
13597
|
+
})) }), { auth: "admin" }), method(object({ block: CompositionBlockInputSchema }), object({ block: CoreBlockSchema }), {
|
|
13598
|
+
kind: "mutation",
|
|
13599
|
+
auth: "admin",
|
|
13600
|
+
caller: "required"
|
|
13601
|
+
}), method(object({
|
|
13602
|
+
blockId: string(),
|
|
13603
|
+
expectedUpdatedAt: number(),
|
|
13604
|
+
block: CompositionBlockInputSchema.partial()
|
|
13605
|
+
}), object({ block: CoreBlockSchema }), {
|
|
13606
|
+
kind: "mutation",
|
|
13607
|
+
auth: "admin",
|
|
13608
|
+
caller: "required"
|
|
13609
|
+
}), method(object({ blockId: string() }), CompositionGetReadSchema, { auth: "admin" }), method(object({}), CompositionListReadSchema, { auth: "admin" }), method(object({
|
|
13610
|
+
addonId: string().min(1),
|
|
13611
|
+
stableId: string().min(1)
|
|
13612
|
+
}), CompositionCustomizationReadSchema, { auth: "admin" }), method(object({ deviceType: _enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }), method(object({
|
|
13613
|
+
composition: CompositionSchema,
|
|
13614
|
+
blockId: string().optional()
|
|
13615
|
+
}), CompositionValidationSchema, {
|
|
13616
|
+
kind: "mutation",
|
|
13617
|
+
auth: "admin",
|
|
13618
|
+
access: "view"
|
|
13619
|
+
});
|
|
13545
13620
|
/**
|
|
13546
13621
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
13547
13622
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -13836,7 +13911,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
13836
13911
|
*
|
|
13837
13912
|
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
13838
13913
|
* was wrong — corrected 2026-08-26 after the hop map
|
|
13839
|
-
* (`docs/design/2026-08-26-
|
|
13914
|
+
* (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
|
|
13840
13915
|
* There is **no Zod parse at all** between the door and the engine: the
|
|
13841
13916
|
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
13842
13917
|
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
@@ -14699,7 +14774,17 @@ var SiteZoneSchema = object({
|
|
|
14699
14774
|
var ProviderStatusSchema = object({
|
|
14700
14775
|
connected: boolean(),
|
|
14701
14776
|
deviceCount: number(),
|
|
14702
|
-
error: string().optional()
|
|
14777
|
+
error: string().optional(),
|
|
14778
|
+
/**
|
|
14779
|
+
* `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
|
|
14780
|
+
* — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
|
|
14781
|
+
* which every provider bundles, so only a provider BUILT from D696-amended
|
|
14782
|
+
* code says it. ABSENT means an older provider that may still write it (raw
|
|
14783
|
+
* VMD writes, a boot seed), and the orchestrator's provider gate keeps that
|
|
14784
|
+
* provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
|
|
14785
|
+
* — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
|
|
14786
|
+
*/
|
|
14787
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
14703
14788
|
});
|
|
14704
14789
|
object({
|
|
14705
14790
|
externalId: string(),
|
|
@@ -15578,6 +15663,121 @@ method(object({
|
|
|
15578
15663
|
deviceIds: array(number()).readonly(),
|
|
15579
15664
|
caps: array(string()).readonly().optional()
|
|
15580
15665
|
}), record(string(), record(string(), unknown().nullable())));
|
|
15666
|
+
var ExtensionSlotIdSchema = _enum(["linked-devices"]);
|
|
15667
|
+
DeviceType.Camera;
|
|
15668
|
+
/** A slot's editable value, discriminated on `slot`. */
|
|
15669
|
+
var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
15670
|
+
DeviceType.Camera;
|
|
15671
|
+
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
15672
|
+
state: literal("unreachable"),
|
|
15673
|
+
reason: string()
|
|
15674
|
+
})]);
|
|
15675
|
+
/** One provider of slots — the D554 source-listing row. */
|
|
15676
|
+
var ExtensionSourceSchema = object({
|
|
15677
|
+
/** The routing prefix of every `slotRef` this provider serves. */
|
|
15678
|
+
source: string(),
|
|
15679
|
+
label: string(),
|
|
15680
|
+
/** Stamped by the dispatcher from the registry (D557). */
|
|
15681
|
+
addonId: string().optional(),
|
|
15682
|
+
availability: ExtensionSourceAvailabilitySchema
|
|
15683
|
+
});
|
|
15684
|
+
/**
|
|
15685
|
+
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
15686
|
+
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
15687
|
+
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
15688
|
+
* valid source now (a container, which is never a pick). A source in any of
|
|
15689
|
+
* these states is SHOWN, never silently dropped or re-pointed.
|
|
15690
|
+
*/
|
|
15691
|
+
var ExtensionSourceHealthSchema = _enum([
|
|
15692
|
+
"ok",
|
|
15693
|
+
"missing",
|
|
15694
|
+
"foreign",
|
|
15695
|
+
"unavailable"
|
|
15696
|
+
]);
|
|
15697
|
+
var ExtensionSlotSourceSchema = object({
|
|
15698
|
+
deviceId: number().int(),
|
|
15699
|
+
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
15700
|
+
name: string().nullable(),
|
|
15701
|
+
health: ExtensionSourceHealthSchema,
|
|
15702
|
+
detail: string().optional()
|
|
15703
|
+
});
|
|
15704
|
+
/**
|
|
15705
|
+
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
15706
|
+
* reported read-only, named, never written through this contract (D62) — e.g.
|
|
15707
|
+
* a slot whose sources act only while a wrapper is bound to the host, a
|
|
15708
|
+
* binding that belongs to `deviceManager.setWrapperActive`. No slot reports
|
|
15709
|
+
* one today (`linked-devices` answers `null`). `unknown` means the gate could
|
|
15710
|
+
* not be read; it is not "inactive" (D315).
|
|
15711
|
+
*/
|
|
15712
|
+
var ExtensionSlotActivationSchema = object({
|
|
15713
|
+
state: _enum([
|
|
15714
|
+
"active",
|
|
15715
|
+
"inactive",
|
|
15716
|
+
"unknown"
|
|
15717
|
+
]),
|
|
15718
|
+
authority: string(),
|
|
15719
|
+
detail: string().optional()
|
|
15720
|
+
});
|
|
15721
|
+
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
15722
|
+
state: literal("ok"),
|
|
15723
|
+
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
15724
|
+
slotRef: string(),
|
|
15725
|
+
slot: ExtensionSlotIdSchema,
|
|
15726
|
+
/** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
|
|
15727
|
+
authority: string(),
|
|
15728
|
+
activation: ExtensionSlotActivationSchema.nullable(),
|
|
15729
|
+
value: ExtensionSlotValueSchema,
|
|
15730
|
+
sources: array(ExtensionSlotSourceSchema),
|
|
15731
|
+
/**
|
|
15732
|
+
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
15733
|
+
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
15734
|
+
* the child a picked container stands for (D356 — a container is never a
|
|
15735
|
+
* pick, its children are). Read-only; the editor shows them and may offer
|
|
15736
|
+
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
15737
|
+
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
15738
|
+
* older than D655.
|
|
15739
|
+
*/
|
|
15740
|
+
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
15741
|
+
}), object({
|
|
15742
|
+
state: literal("unreachable"),
|
|
15743
|
+
addonId: string(),
|
|
15744
|
+
reason: string()
|
|
15745
|
+
})]);
|
|
15746
|
+
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
15747
|
+
deviceId: number().int(),
|
|
15748
|
+
name: string(),
|
|
15749
|
+
type: string(),
|
|
15750
|
+
location: string().nullable(),
|
|
15751
|
+
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
15752
|
+
parentName: string().nullable(),
|
|
15753
|
+
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
15754
|
+
suggested: boolean(),
|
|
15755
|
+
/** Why it is suggested ("same location"), null when it is not. */
|
|
15756
|
+
reason: string().nullable()
|
|
15757
|
+
})) });
|
|
15758
|
+
/**
|
|
15759
|
+
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
15760
|
+
* reloaded the host (or, for an accessory child, its parent) because the
|
|
15761
|
+
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
15762
|
+
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
15763
|
+
*/
|
|
15764
|
+
var ExtensionSetResultSchema = object({
|
|
15765
|
+
applied: literal(true),
|
|
15766
|
+
reload: _enum([
|
|
15767
|
+
"none",
|
|
15768
|
+
"host",
|
|
15769
|
+
"parent"
|
|
15770
|
+
])
|
|
15771
|
+
});
|
|
15772
|
+
var ExtensionSlotRefInputSchema = object({
|
|
15773
|
+
deviceId: number().int(),
|
|
15774
|
+
slotRef: string().min(1)
|
|
15775
|
+
});
|
|
15776
|
+
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
15777
|
+
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
15778
|
+
kind: "mutation",
|
|
15779
|
+
auth: "admin"
|
|
15780
|
+
});
|
|
15581
15781
|
/**
|
|
15582
15782
|
* Per-field ownership (D663). A composition may CLAIM fields of a native
|
|
15583
15783
|
* cap's runtime-state slice on an existing device: `replace` overlays the
|
|
@@ -15801,7 +16001,7 @@ method(object({
|
|
|
15801
16001
|
* per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
|
|
15802
16002
|
* ends in a log line, and a log line is the thing the operator asked to stop
|
|
15803
16003
|
* needing: *"possiamo armare questi errori intanto? Così al prossimo giro
|
|
15804
|
-
* ricontrolliamo tutti questi punti"
|
|
16004
|
+
* 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
|
|
15805
16005
|
* hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
|
|
15806
16006
|
* media blackout were both diagnosed. The counters stay; this is where they can
|
|
15807
16007
|
* be READ.
|
|
@@ -17177,7 +17377,7 @@ var BrokerStatusSchema$1 = _enum([
|
|
|
17177
17377
|
"unreachable",
|
|
17178
17378
|
"tls-error"
|
|
17179
17379
|
]);
|
|
17180
|
-
var BrokerInfoSchema = object({
|
|
17380
|
+
var BrokerInfoSchema$1 = object({
|
|
17181
17381
|
id: string(),
|
|
17182
17382
|
name: string(),
|
|
17183
17383
|
url: string(),
|
|
@@ -17240,7 +17440,7 @@ var StatusSchema = object({
|
|
|
17240
17440
|
brokerCount: number(),
|
|
17241
17441
|
embeddedRunning: boolean()
|
|
17242
17442
|
});
|
|
17243
|
-
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17443
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
17244
17444
|
kind: "mutation",
|
|
17245
17445
|
auth: "admin"
|
|
17246
17446
|
}), method(IdInputSchema, _void(), {
|
|
@@ -18588,17 +18788,25 @@ var NcScheduleSchema = object({
|
|
|
18588
18788
|
*/
|
|
18589
18789
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
18590
18790
|
/**
|
|
18791
|
+
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
18792
|
+
* every section; `section` = one notification per section with something to
|
|
18793
|
+
* say (an unavailable section included), each titled by its section.
|
|
18794
|
+
*/
|
|
18795
|
+
var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
18796
|
+
/**
|
|
18591
18797
|
* `summary`: the rule sends NOTHING per event. When a window of `schedule`
|
|
18592
18798
|
* CLOSES, it sends one notification with the current state of its kinds
|
|
18593
18799
|
* (low batteries, consumables to replace, devices offline, updates
|
|
18594
|
-
* available, ...), after its own filters
|
|
18800
|
+
* available, ...), after its own filters — or, with `split: 'section'`
|
|
18801
|
+
* (D698), one notification per section. Nothing to report sends nothing.
|
|
18595
18802
|
* The schedule is the ordinary `NcSchedule` (weekly windows, IANA timezone,
|
|
18596
18803
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
18597
18804
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
18598
18805
|
*/
|
|
18599
18806
|
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [object({ mode: literal("instant") }), object({
|
|
18600
18807
|
mode: literal("summary"),
|
|
18601
|
-
schedule: NcScheduleSchema
|
|
18808
|
+
schedule: NcScheduleSchema,
|
|
18809
|
+
split: NcStateSummarySplitSchema.optional()
|
|
18602
18810
|
})]);
|
|
18603
18811
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
18604
18812
|
var NcPlateMatcherSchema = object({
|
|
@@ -18738,8 +18946,14 @@ var NcSensorTransitionSchema = _enum(["raised", "cleared"]);
|
|
|
18738
18946
|
/** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
|
|
18739
18947
|
var NcZoneConditionSchema = object({
|
|
18740
18948
|
ids: array(string().min(1)).min(1),
|
|
18741
|
-
/**
|
|
18742
|
-
|
|
18949
|
+
/**
|
|
18950
|
+
* LEGACY quantifier over `ids`. Absent = `any` (at least one visited), which
|
|
18951
|
+
* is what both editors mean and all they write since D690: "all of" was
|
|
18952
|
+
* removed from the editors because on an immediate rule it asked one
|
|
18953
|
+
* detection to stand in every zone at once. Still ACCEPTED, and `all` still
|
|
18954
|
+
* evaluated, so a stored rule keeps parsing and meaning what it meant.
|
|
18955
|
+
*/
|
|
18956
|
+
match: _enum(["any", "all"]).optional()
|
|
18743
18957
|
});
|
|
18744
18958
|
/**
|
|
18745
18959
|
* The P1 condition set — a flat AND of groups; absent group = pass;
|
|
@@ -19243,10 +19457,12 @@ var NcMediaPolicySchema = object({
|
|
|
19243
19457
|
/**
|
|
19244
19458
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
19245
19459
|
* notification suppresses.
|
|
19246
|
-
* - `
|
|
19247
|
-
*
|
|
19248
|
-
*
|
|
19249
|
-
*
|
|
19460
|
+
* - `per-class` (default, and the absent value since 2026-10-01 — D36) — an
|
|
19461
|
+
* independent window per detected class: cat→dog fires at once, cat→cat
|
|
19462
|
+
* still waits.
|
|
19463
|
+
* - `shared` — one window for the whole rule/scope: a cat silences the next
|
|
19464
|
+
* dog for `cooldownSec`. Only written when an operator picks it; it is no
|
|
19465
|
+
* longer what an unset rule means.
|
|
19250
19466
|
*
|
|
19251
19467
|
* AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
|
|
19252
19468
|
* must not be swallowed by a bark's window (the precedent this generalizes —
|
|
@@ -19261,8 +19477,11 @@ var NcThrottleSchema = object({
|
|
|
19261
19477
|
/**
|
|
19262
19478
|
* Class granularity of the cooldown key. Optional rather than defaulted:
|
|
19263
19479
|
* a Zod default does NOT run on the addon→addon cap path, so a persisted
|
|
19264
|
-
* rule authored before this field simply carries none
|
|
19265
|
-
*
|
|
19480
|
+
* rule authored before this field simply carries none. The engine used to
|
|
19481
|
+
* read absent as `shared` (D36); since 2026-10-01 it reads absent as
|
|
19482
|
+
* `per-class` — the operator's default — and only an explicit `shared`
|
|
19483
|
+
* still means `shared`. See `cooldownKey` / `keysPerClass` in the rule
|
|
19484
|
+
* engine, and D36's dated note.
|
|
19266
19485
|
*/
|
|
19267
19486
|
granularity: NcThrottleGranularitySchema.optional()
|
|
19268
19487
|
});
|
|
@@ -19435,78 +19654,16 @@ var NcRuleInputSchema = object({
|
|
|
19435
19654
|
*/
|
|
19436
19655
|
confirm: NcConfirmSchema.optional(),
|
|
19437
19656
|
/**
|
|
19438
|
-
*
|
|
19439
|
-
*
|
|
19440
|
-
*
|
|
19441
|
-
*
|
|
19442
|
-
*
|
|
19443
|
-
*
|
|
19444
|
-
*
|
|
19445
|
-
*
|
|
19446
|
-
*
|
|
19447
|
-
* Only two honest answers exist, and this flag picks between them. It has
|
|
19448
|
-
* effect ONLY on a rule that declares a recognition scope
|
|
19449
|
-
* ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
|
|
19450
|
-
* other rule there is nothing to wait for and the flag is inert.
|
|
19451
|
-
*
|
|
19452
|
-
* | value | what happens |
|
|
19453
|
-
* | --- | --- |
|
|
19454
|
-
* | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
|
|
19455
|
-
* | 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) |
|
|
19456
|
-
*
|
|
19457
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19458
|
-
* on the addon cap path, and absent has to keep meaning exactly what every
|
|
19459
|
-
* rule authored before this field meant.
|
|
19460
|
-
*
|
|
19461
|
-
* The cost of `true` is stated here because the editor states it too: a rule
|
|
19462
|
-
* that waits also inherits track-close SEMANTICS — its `zones` condition
|
|
19463
|
-
* tests every zone the track visited and a `crossing` condition can no longer
|
|
19464
|
-
* be satisfied, because a closed track carries no crossing.
|
|
19465
|
-
*/
|
|
19466
|
-
waitForEnhancement: boolean().optional(),
|
|
19467
|
-
/**
|
|
19468
|
-
* GROUP a burst of subjects into ONE notification that grows.
|
|
19469
|
-
*
|
|
19470
|
-
* Seconds of quiet after the last matching subject before the burst is
|
|
19471
|
-
* considered over. While it is open, the first subject enqueues immediately —
|
|
19472
|
-
* **exactly as today, with no added latency** — and every real growth (a new
|
|
19473
|
-
* subject, or a name confirmed on one already in it) REPLACES that
|
|
19474
|
-
* notification with an updated one naming everybody. The push carries the
|
|
19475
|
-
* group's own coalescing tag, so the phone replaces rather than stacks.
|
|
19476
|
-
*
|
|
19477
|
-
* `0` / absent = off, and off is today's behaviour byte for byte.
|
|
19478
|
-
*
|
|
19479
|
-
* ### Why an idle cutoff and not a window
|
|
19480
|
-
*
|
|
19481
|
-
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
19482
|
-
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
19483
|
-
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
19484
|
-
* 30 s is a widely shipped value for the same decision.
|
|
19485
|
-
*
|
|
19486
|
-
* ### What it replaces
|
|
19487
|
-
*
|
|
19488
|
-
* The blind cooldown, which collapses a burst by DISCARDING it. Measured on
|
|
19489
|
-
* device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
|
|
19490
|
-
* notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
|
|
19491
|
-
* track that did fire and 7 carrying a confirmed identity nobody heard about.
|
|
19492
|
-
* A group collapses the same volume by MERGING, so the cooldown becomes a
|
|
19493
|
-
* budget over GROUPS — which is what it always meant — and a growth is never
|
|
19494
|
-
* throttled by the window its own first member spent.
|
|
19495
|
-
*
|
|
19496
|
-
* ### Interaction with {@link waitForEnhancement}
|
|
19497
|
-
*
|
|
19498
|
-
* They compose, and the order matters. `waitForEnhancement` defers the rule to
|
|
19499
|
-
* TRACK CLOSE, so with both set the group is opened by the first member to
|
|
19500
|
-
* CLOSE — already carrying its name — and grows as later members close. That
|
|
19501
|
-
* is later, and complete. With grouping alone the group opens on the first
|
|
19502
|
-
* object event and picks up names as they are confirmed, through the growth
|
|
19503
|
-
* path. Neither combination fires twice for one subject.
|
|
19504
|
-
*
|
|
19505
|
-
* `.optional()` and deliberately NOT `.default()`: a Zod default does not run
|
|
19506
|
-
* on the addon cap path, so absent must keep meaning what it meant before this
|
|
19507
|
-
* field existed.
|
|
19657
|
+
* IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
|
|
19658
|
+
* seconds; the rule sends ONE message when the window closes — early, once every
|
|
19659
|
+
* subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
|
|
19660
|
+
* the rule matched, with one mosaic tile per subject.
|
|
19661
|
+
* Absent = plain immediate (one message per track, at the first match).
|
|
19662
|
+
* Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
|
|
19663
|
+
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
19664
|
+
* path does not run Zod defaults.
|
|
19508
19665
|
*/
|
|
19509
|
-
|
|
19666
|
+
groupingSec: number().int().min(5).max(60).optional()
|
|
19510
19667
|
});
|
|
19511
19668
|
/**
|
|
19512
19669
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -19554,9 +19711,10 @@ var NcRuleClearableKeySchema = _enum([
|
|
|
19554
19711
|
"targetUsers",
|
|
19555
19712
|
"snoozeOptions",
|
|
19556
19713
|
"snoozeAllowGlobal",
|
|
19557
|
-
"waitForEnhancement",
|
|
19558
19714
|
"actions",
|
|
19559
19715
|
"confirm",
|
|
19716
|
+
"groupingSec",
|
|
19717
|
+
"waitForEnhancement",
|
|
19560
19718
|
"groupIdleSec"
|
|
19561
19719
|
]);
|
|
19562
19720
|
var NcRuleUpdateInputSchema = object({
|
|
@@ -19578,19 +19736,47 @@ var NcRuleSchema = NcRuleInputSchema.extend({
|
|
|
19578
19736
|
*/
|
|
19579
19737
|
disabledTargetIds: array(string()).default([])
|
|
19580
19738
|
});
|
|
19739
|
+
/**
|
|
19740
|
+
* The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
|
|
19741
|
+
* still-true state. `backups-exports` and `alarm` are not sections — a completed
|
|
19742
|
+
* job is not an open state, and the alarm stays instant.
|
|
19743
|
+
*/
|
|
19744
|
+
var NcStateSummarySectionIdSchema = _enum([
|
|
19745
|
+
"device-state",
|
|
19746
|
+
"streams",
|
|
19747
|
+
"battery",
|
|
19748
|
+
"consumables",
|
|
19749
|
+
"tanks",
|
|
19750
|
+
"detection-blind",
|
|
19751
|
+
"nodes",
|
|
19752
|
+
"addons",
|
|
19753
|
+
"updates"
|
|
19754
|
+
]);
|
|
19581
19755
|
/** One section of a previewed state summary. `unavailable` = its state could not be read. */
|
|
19582
19756
|
var NcStateSummaryPreviewSectionSchema = object({
|
|
19583
|
-
id:
|
|
19757
|
+
id: NcStateSummarySectionIdSchema,
|
|
19584
19758
|
status: _enum(["read", "unavailable"]),
|
|
19585
19759
|
items: number().int().nonnegative(),
|
|
19586
19760
|
reason: string().optional()
|
|
19587
19761
|
});
|
|
19588
19762
|
/**
|
|
19763
|
+
* One notification a previewed summary would send (D698): the whole summary on
|
|
19764
|
+
* a `rule` split (no `section`), one section's on a `section` split.
|
|
19765
|
+
*/
|
|
19766
|
+
var NcStateSummaryPreviewRowSchema = object({
|
|
19767
|
+
section: NcStateSummarySectionIdSchema.optional(),
|
|
19768
|
+
/** The section's name on a per-section row; every reported section's, joined, on a combined one. */
|
|
19769
|
+
title: string(),
|
|
19770
|
+
text: string(),
|
|
19771
|
+
count: number().int().nonnegative()
|
|
19772
|
+
});
|
|
19773
|
+
/**
|
|
19589
19774
|
* The summary a rule would send now. `empty` = nothing to report and every
|
|
19590
19775
|
* section read: such a summary is NOT sent. `dropped` counts the open states
|
|
19591
19776
|
* the rule's own filters (or a camera mute) left out, by reason.
|
|
19592
19777
|
* `excludedGroups` names the kind groups selected that have no state to report
|
|
19593
|
-
* (backups & exports).
|
|
19778
|
+
* (backups & exports). `split` and `rows` (D698) say how it would be sent —
|
|
19779
|
+
* optional, so an older hub's answer still parses.
|
|
19594
19780
|
*/
|
|
19595
19781
|
var NcStateSummaryPreviewSchema = object({
|
|
19596
19782
|
empty: boolean(),
|
|
@@ -19598,7 +19784,9 @@ var NcStateSummaryPreviewSchema = object({
|
|
|
19598
19784
|
text: string(),
|
|
19599
19785
|
sections: array(NcStateSummaryPreviewSectionSchema),
|
|
19600
19786
|
dropped: record(string(), number().int().nonnegative()),
|
|
19601
|
-
excludedGroups: array(string())
|
|
19787
|
+
excludedGroups: array(string()),
|
|
19788
|
+
split: NcStateSummarySplitSchema.optional(),
|
|
19789
|
+
rows: array(NcStateSummaryPreviewRowSchema).optional()
|
|
19602
19790
|
});
|
|
19603
19791
|
var NcTestResultSchema = object({
|
|
19604
19792
|
recordId: string(),
|
|
@@ -20013,6 +20201,29 @@ object({
|
|
|
20013
20201
|
firstAt: number(),
|
|
20014
20202
|
lastAt: number()
|
|
20015
20203
|
});
|
|
20204
|
+
var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
|
|
20205
|
+
var NcAlarmDelaySecSchema = number().int().min(0).max(600);
|
|
20206
|
+
var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
|
|
20207
|
+
var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
|
|
20208
|
+
var NcAlarmModeDelaysListSchema = array(object({
|
|
20209
|
+
mode: AlarmArmModeSchema,
|
|
20210
|
+
exitDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20211
|
+
entryDelaySec: NcAlarmDelaySecSchema.optional(),
|
|
20212
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
|
|
20213
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
20214
|
+
var NcAlarmModeDelaysEditListSchema = array(object({
|
|
20215
|
+
mode: AlarmArmModeSchema,
|
|
20216
|
+
exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20217
|
+
entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
|
|
20218
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
|
|
20219
|
+
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
20220
|
+
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
20221
|
+
var NcAlarmNonBlockingEditSchema = object({
|
|
20222
|
+
mode: AlarmArmModeSchema,
|
|
20223
|
+
deviceId: number().int().positive(),
|
|
20224
|
+
/** true = on the list (may be open, does not block); false = off the list (blocks). */
|
|
20225
|
+
nonBlocking: boolean()
|
|
20226
|
+
});
|
|
20016
20227
|
/**
|
|
20017
20228
|
* The per-mode lists, at most one per mode. Two lists for one mode have no
|
|
20018
20229
|
* meaning a reader could agree on (union? the last one?), so they are refused
|
|
@@ -20021,10 +20232,10 @@ object({
|
|
|
20021
20232
|
var NcAlarmNonBlockingListSchema = array(object({
|
|
20022
20233
|
mode: AlarmArmModeSchema,
|
|
20023
20234
|
deviceIds: array(number().int()).max(200)
|
|
20024
|
-
})).max(8).refine(
|
|
20235
|
+
})).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
|
|
20025
20236
|
/**
|
|
20026
|
-
* The three durations
|
|
20027
|
-
* transitions, and which openings each mode tolerates.
|
|
20237
|
+
* The three durations — global, and per mode since D697 — the panel's state
|
|
20238
|
+
* machine runs on, who hears about its transitions, and which openings each mode tolerates.
|
|
20028
20239
|
*
|
|
20029
20240
|
* They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
|
|
20030
20241
|
* `alarm-panel` is `deviceNative` and its other provider mirrors somebody
|
|
@@ -20034,15 +20245,15 @@ var NcAlarmNonBlockingListSchema = array(object({
|
|
|
20034
20245
|
*/
|
|
20035
20246
|
var NcAlarmSettingsSchema = object({
|
|
20036
20247
|
/** Grace period between arming and the mode taking effect. 0 = immediate. */
|
|
20037
|
-
exitDelaySec:
|
|
20248
|
+
exitDelaySec: NcAlarmDelaySecSchema,
|
|
20038
20249
|
/** Grace period between a trigger and the alarm firing. 0 = immediate. */
|
|
20039
|
-
entryDelaySec:
|
|
20250
|
+
entryDelaySec: NcAlarmDelaySecSchema,
|
|
20040
20251
|
/**
|
|
20041
20252
|
* How long `triggered` lasts before the panel re-arms itself.
|
|
20042
20253
|
* **0 = until an operator disarms it** — the behaviour before this field
|
|
20043
20254
|
* existed, and therefore what an untouched install keeps doing.
|
|
20044
20255
|
*/
|
|
20045
|
-
triggeredDurationSec:
|
|
20256
|
+
triggeredDurationSec: NcAlarmTriggeredSecSchema,
|
|
20046
20257
|
/**
|
|
20047
20258
|
* Deprecated by D630 — every transition is announced. Parsed, never read;
|
|
20048
20259
|
* remove after one release. Optional so an older admin's patch (which still
|
|
@@ -20065,17 +20276,30 @@ var NcAlarmSettingsSchema = object({
|
|
|
20065
20276
|
* per mode is meaningful. Defaulted to `[]` so a blob stored before D630
|
|
20066
20277
|
* parses as "every opening blocks" — the behaviour it was written under.
|
|
20067
20278
|
*/
|
|
20068
|
-
nonBlocking: NcAlarmNonBlockingListSchema.default([])
|
|
20279
|
+
nonBlocking: NcAlarmNonBlockingListSchema.default([]),
|
|
20280
|
+
/**
|
|
20281
|
+
* Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
|
|
20282
|
+
* without a field, uses the global value above — so `[]`, the default, is exactly the
|
|
20283
|
+
* behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
|
|
20284
|
+
*/
|
|
20285
|
+
modeDelays: NcAlarmModeDelaysListSchema.default([])
|
|
20069
20286
|
});
|
|
20070
20287
|
/**
|
|
20071
20288
|
* Every field optional — a tab edits one control at a time.
|
|
20072
20289
|
*
|
|
20073
|
-
* `nonBlocking`
|
|
20074
|
-
* remove an inner `.default()`, so a patch that never
|
|
20075
|
-
* parse to `
|
|
20076
|
-
* (the same trap {@link NcRulePatchSchema} documents).
|
|
20290
|
+
* `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
|
|
20291
|
+
* `.partial()` does not remove an inner `.default()`, so a patch that never
|
|
20292
|
+
* named the field would parse to `[]` and wipe every mode's list on an
|
|
20293
|
+
* unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
|
|
20294
|
+
* `modeDelays` means EDITS, not the stored overrides.
|
|
20077
20295
|
*/
|
|
20078
|
-
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20296
|
+
var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
|
|
20297
|
+
nonBlocking: NcAlarmNonBlockingListSchema,
|
|
20298
|
+
/** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
|
|
20299
|
+
modeDelays: NcAlarmModeDelaysEditListSchema,
|
|
20300
|
+
/** ONE membership change; the panel applies it to the list it holds at its turn. */
|
|
20301
|
+
nonBlockingEdit: NcAlarmNonBlockingEditSchema
|
|
20302
|
+
}).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
|
|
20079
20303
|
/**
|
|
20080
20304
|
* What one arm mode actually arms, DERIVED from the enabled rules gated on it.
|
|
20081
20305
|
* Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
|
|
@@ -20175,6 +20399,28 @@ var NcAlarmConfigSchema = object({
|
|
|
20175
20399
|
*/
|
|
20176
20400
|
live: NcAlarmLiveSchema.optional()
|
|
20177
20401
|
});
|
|
20402
|
+
var NcAlarmSensorReadingSchema = _enum([
|
|
20403
|
+
"open",
|
|
20404
|
+
"closed",
|
|
20405
|
+
"unknown",
|
|
20406
|
+
"not-opening"
|
|
20407
|
+
]);
|
|
20408
|
+
/** One device's state as the alarm reads it — the classifier the arm check uses. */
|
|
20409
|
+
var NcAlarmSensorStateSchema = object({
|
|
20410
|
+
deviceId: number().int().positive(),
|
|
20411
|
+
reading: NcAlarmSensorReadingSchema,
|
|
20412
|
+
/** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
|
|
20413
|
+
state: string().nullable(),
|
|
20414
|
+
/** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
|
|
20415
|
+
unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
|
|
20416
|
+
/** The device manager's liveness as the centre mirrors it; null = not known. */
|
|
20417
|
+
online: boolean().nullable()
|
|
20418
|
+
});
|
|
20419
|
+
var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
|
|
20420
|
+
var NcAlarmSensorsSchema = object({
|
|
20421
|
+
sensors: array(NcAlarmSensorStateSchema),
|
|
20422
|
+
readAt: number().int().nonnegative()
|
|
20423
|
+
});
|
|
20178
20424
|
/**
|
|
20179
20425
|
* ONE rule's demand on ONE camera's clip ring.
|
|
20180
20426
|
*
|
|
@@ -20265,7 +20511,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
|
|
|
20265
20511
|
}), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
|
|
20266
20512
|
kind: "mutation",
|
|
20267
20513
|
auth: "admin"
|
|
20268
|
-
});
|
|
20514
|
+
}), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
|
|
20269
20515
|
/**
|
|
20270
20516
|
* Zod schemas for persisted record types.
|
|
20271
20517
|
*
|
|
@@ -20612,12 +20858,26 @@ var CameraSensorRefSchema = object({
|
|
|
20612
20858
|
function cameraSensorRefKey(ref) {
|
|
20613
20859
|
return `${ref.addonId}/${ref.stableId}`;
|
|
20614
20860
|
}
|
|
20615
|
-
/**
|
|
20616
|
-
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20861
|
+
/**
|
|
20862
|
+
* A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
|
|
20863
|
+
* `replace`: its motion is the camera's, and while one is READY the camera's
|
|
20864
|
+
* own motion no longer counts on its own. `confirm`: while one is READY the
|
|
20865
|
+
* camera's own motion counts only while a confirm sensor is active — with or
|
|
20866
|
+
* without a replace sensor (spec C2, the controller's ruling on Q1).
|
|
20867
|
+
*/
|
|
20868
|
+
var CameraSensorModeSchema = _enum([
|
|
20869
|
+
"in-addition",
|
|
20870
|
+
"confirm",
|
|
20871
|
+
"replace"
|
|
20872
|
+
]);
|
|
20873
|
+
/** A stored sensor with no mode — every CS-1 row — is in addition. */
|
|
20874
|
+
var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
|
|
20875
|
+
/**
|
|
20876
|
+
* A camera's attached sensors. A CS-1 row carried an envelope
|
|
20877
|
+
* `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
|
|
20878
|
+
* what the write stores (D672 rule 3), so it is never written again.
|
|
20879
|
+
*/
|
|
20880
|
+
var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
|
|
20621
20881
|
const seen = /* @__PURE__ */ new Set();
|
|
20622
20882
|
value.sensors.forEach((ref, index) => {
|
|
20623
20883
|
const key = cameraSensorRefKey(ref);
|
|
@@ -20629,39 +20889,41 @@ var CameraSensorsConfigSchema = object({
|
|
|
20629
20889
|
seen.add(key);
|
|
20630
20890
|
});
|
|
20631
20891
|
});
|
|
20632
|
-
|
|
20892
|
+
/** Every attachment names its mode; an older orchestrator that does not is in addition. */
|
|
20893
|
+
var AttachmentFields = {
|
|
20633
20894
|
addonId: string(),
|
|
20634
|
-
stableId: string()
|
|
20895
|
+
stableId: string(),
|
|
20896
|
+
mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
|
|
20635
20897
|
};
|
|
20636
20898
|
var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
20637
20899
|
object({
|
|
20638
|
-
...
|
|
20900
|
+
...AttachmentFields,
|
|
20639
20901
|
state: literal("ready"),
|
|
20640
20902
|
deviceId: number(),
|
|
20641
20903
|
name: string(),
|
|
20642
20904
|
caps: array(string()).readonly()
|
|
20643
20905
|
}),
|
|
20644
20906
|
object({
|
|
20645
|
-
...
|
|
20907
|
+
...AttachmentFields,
|
|
20646
20908
|
state: literal("offline"),
|
|
20647
20909
|
deviceId: number(),
|
|
20648
20910
|
name: string(),
|
|
20649
20911
|
reason: _enum(["offline", "disabled"])
|
|
20650
20912
|
}),
|
|
20651
20913
|
object({
|
|
20652
|
-
...
|
|
20914
|
+
...AttachmentFields,
|
|
20653
20915
|
state: literal("missing"),
|
|
20654
20916
|
reason: string()
|
|
20655
20917
|
}),
|
|
20656
20918
|
object({
|
|
20657
|
-
...
|
|
20919
|
+
...AttachmentFields,
|
|
20658
20920
|
state: literal("unsupported"),
|
|
20659
20921
|
deviceId: number(),
|
|
20660
20922
|
name: string(),
|
|
20661
20923
|
reason: string()
|
|
20662
20924
|
}),
|
|
20663
20925
|
object({
|
|
20664
|
-
...
|
|
20926
|
+
...AttachmentFields,
|
|
20665
20927
|
state: literal("unreadable"),
|
|
20666
20928
|
reason: string()
|
|
20667
20929
|
})
|
|
@@ -20674,17 +20936,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
|
|
|
20674
20936
|
* say.
|
|
20675
20937
|
*/
|
|
20676
20938
|
var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
|
|
20939
|
+
/** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
|
|
20940
|
+
var CameraOwnMotionSchema = _enum([
|
|
20941
|
+
"always",
|
|
20942
|
+
"when-confirmed",
|
|
20943
|
+
"never"
|
|
20944
|
+
]);
|
|
20945
|
+
/** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
|
|
20946
|
+
var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
|
|
20947
|
+
/**
|
|
20948
|
+
* The camera's OWN onboard motion (D696): the raw input the bridge combines,
|
|
20949
|
+
* never the effective value. The camera's `motion` slice is the effective one,
|
|
20950
|
+
* so a view of the camera's own row reads this.
|
|
20951
|
+
* - `atMs`: when the bridge received the camera's last own edge.
|
|
20952
|
+
* - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
|
|
20953
|
+
* AND it is younger than the window the bridge counts the camera's own motion
|
|
20954
|
+
* for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
|
|
20955
|
+
* sends a clear (heartbeats only) therefore reads `false` once no push came
|
|
20956
|
+
* within the window; a status read is a snapshot, so a live view re-asks.
|
|
20957
|
+
* Absent = this orchestrator has not received the camera's own motion since it
|
|
20958
|
+
* started (unknown, never "quiet"), or an orchestrator older than D696.
|
|
20959
|
+
*/
|
|
20960
|
+
var CameraRawLevelSchema = object({
|
|
20961
|
+
detected: boolean(),
|
|
20962
|
+
atMs: number()
|
|
20963
|
+
});
|
|
20677
20964
|
var CameraSensorsStatusSchema = discriminatedUnion("state", [
|
|
20678
|
-
object({
|
|
20965
|
+
object({
|
|
20966
|
+
state: literal("not-configured"),
|
|
20967
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20968
|
+
}),
|
|
20679
20969
|
object({
|
|
20680
20970
|
state: literal("unreadable"),
|
|
20681
|
-
reason: string()
|
|
20971
|
+
reason: string(),
|
|
20972
|
+
cameraLevel: CameraRawLevelSchema.optional()
|
|
20682
20973
|
}),
|
|
20683
20974
|
object({
|
|
20684
20975
|
state: literal("configured"),
|
|
20685
|
-
|
|
20976
|
+
cameraLevel: CameraRawLevelSchema.optional(),
|
|
20686
20977
|
sensors: array(CameraSensorAttachmentSchema).readonly(),
|
|
20687
|
-
|
|
20978
|
+
/** Absent = an orchestrator older than CS-2: it does not say (D315). */
|
|
20979
|
+
cameraMotion: CameraOwnMotionSchema.optional(),
|
|
20980
|
+
notForwarded: CameraSensorsNotForwardedSchema.optional(),
|
|
20981
|
+
notEnforced: CameraSensorsNotEnforcedSchema.optional()
|
|
20688
20982
|
})
|
|
20689
20983
|
]);
|
|
20690
20984
|
Object.freeze({
|
|
@@ -21369,14 +21663,14 @@ var TrackSchema = object({
|
|
|
21369
21663
|
* `derive-returned-null tile=standin`,
|
|
21370
21664
|
* `native-tile tile=native no-key-frame-at-close`, …) written at close and
|
|
21371
21665
|
* CLEARED by the late-keyFrame upgrade when a native tile lands after all.
|
|
21372
|
-
* The operator-facing answer to "perché manca l'immagine?" on a track whose
|
|
21666
|
+
* The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
|
|
21373
21667
|
* tile is a face/plate stand-in, a raster crop, or an icon.
|
|
21374
21668
|
*
|
|
21375
21669
|
* **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
|
|
21376
21670
|
* the TILE ranked below native, so a track whose thumbnail landed natively
|
|
21377
21671
|
* while its key frame missed carried no reason at all — three of the four
|
|
21378
21672
|
* `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
|
|
21379
|
-
* that shape, and their "niente ultimo" had no cause anywhere on the row.
|
|
21673
|
+
* that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
|
|
21380
21674
|
* The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
|
|
21381
21675
|
* lastFrame copy source`), so its absence is now on this line whatever the
|
|
21382
21676
|
* tile ended up being.
|
|
@@ -21463,7 +21757,7 @@ var MotionEventSchema = object({
|
|
|
21463
21757
|
/**
|
|
21464
21758
|
* Ms offsets from `timestamp` (the episode's own first rising edge, so the
|
|
21465
21759
|
* first entry is always `0`) of every genuine off→on transition the
|
|
21466
|
-
* episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
|
|
21760
|
+
* episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
|
|
21467
21761
|
* push: a firmware source that keepalives at ~1 Hz for the whole burst
|
|
21468
21762
|
* (Reolink, Hikvision) produces exactly one edge; a source that reports an
|
|
21469
21763
|
* explicit `false` mid-episode and then resumes before the quiet window
|
|
@@ -21987,6 +22281,7 @@ var KeyEventSchema = object({
|
|
|
21987
22281
|
bestEventId: string(),
|
|
21988
22282
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
21989
22283
|
windowMs: number().optional(),
|
|
22284
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
21990
22285
|
...TrackFlagFields,
|
|
21991
22286
|
...TrackRetrainFields
|
|
21992
22287
|
});
|
|
@@ -22519,7 +22814,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
22519
22814
|
trackIds: array(string()).min(1)
|
|
22520
22815
|
}), object({
|
|
22521
22816
|
deleted: number().int(),
|
|
22522
|
-
failed: array(string()).readonly()
|
|
22817
|
+
failed: array(string()).readonly(),
|
|
22818
|
+
sparedMediaIds: array(number().int()).readonly().optional()
|
|
22523
22819
|
}), {
|
|
22524
22820
|
kind: "mutation",
|
|
22525
22821
|
auth: "admin"
|
|
@@ -23914,8 +24210,10 @@ var RunnerCameraConfigSchema = object({
|
|
|
23914
24210
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
23915
24211
|
* analyzer providers) running on decoded frames in this runner.
|
|
23916
24212
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
23917
|
-
* analytics). The provider emits ProviderMotion
|
|
23918
|
-
*
|
|
24213
|
+
* analytics). The provider emits its raw push as `ProviderMotion`
|
|
24214
|
+
* (D673); the orchestrator's camera-sensors bridge re-emits the camera's
|
|
24215
|
+
* effective motion as `MotionOnMotionChanged`, which is what reaches
|
|
24216
|
+
* `reportMotion`.
|
|
23919
24217
|
*/
|
|
23920
24218
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
23921
24219
|
/**
|
|
@@ -24092,7 +24390,15 @@ var RunnerLocalLoadSchema = object({
|
|
|
24092
24390
|
hasGpu: boolean(),
|
|
24093
24391
|
inferenceBackend: string().optional(),
|
|
24094
24392
|
cpuCores: number().optional()
|
|
24095
|
-
})
|
|
24393
|
+
}),
|
|
24394
|
+
/**
|
|
24395
|
+
* Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
|
|
24396
|
+
* runner never writes it. ABSENT = a runner older than D696, which still
|
|
24397
|
+
* writes the slice from its phase machine; the orchestrator does not write
|
|
24398
|
+
* while any runner node is absent-or-unanswered, so one slice never has two
|
|
24399
|
+
* writers.
|
|
24400
|
+
*/
|
|
24401
|
+
motionSliceWriter: literal("orchestrator").optional()
|
|
24096
24402
|
});
|
|
24097
24403
|
/**
|
|
24098
24404
|
* Aggregate runtime metrics for the runner's whole local pool. Mirrors the
|
|
@@ -24748,7 +25054,42 @@ var SetCameraSensorsInputSchema = object({
|
|
|
24748
25054
|
/** `null` removes the attachment: the camera goes back to `not-configured`. */
|
|
24749
25055
|
config: CameraSensorsConfigSchema.nullable()
|
|
24750
25056
|
});
|
|
24751
|
-
|
|
25057
|
+
/**
|
|
25058
|
+
* Why an early occupancy look (D691) was not scheduled.
|
|
25059
|
+
*
|
|
25060
|
+
* - `unknown-camera` — no session was ever dispatched for it, so there is no
|
|
25061
|
+
* node and no config to attach a burst with.
|
|
25062
|
+
* - `out-of-range` — the ask is negative or further out than the orchestrator
|
|
25063
|
+
* will hold a timer for; the parked-object cadence is the answer there.
|
|
25064
|
+
* - `no-burst-producer` — this build has no burst producer at all.
|
|
25065
|
+
* - `already-looked` — this camera's ONE early look since its last session has
|
|
25066
|
+
* been spent. A look's own burst can re-arm a flickering flip, and a look
|
|
25067
|
+
* per arm would chain a burst every ~30 s forever (review H2); the next
|
|
25068
|
+
* real session re-arms the budget.
|
|
25069
|
+
*/
|
|
25070
|
+
var OccupancyLookRefusalSchema = _enum([
|
|
25071
|
+
"unknown-camera",
|
|
25072
|
+
"out-of-range",
|
|
25073
|
+
"no-burst-producer",
|
|
25074
|
+
"already-looked"
|
|
25075
|
+
]);
|
|
25076
|
+
method(object({
|
|
25077
|
+
deviceId: number().int().nonnegative(),
|
|
25078
|
+
/** How long from NOW until the pending flip's sustain window ends. RELATIVE,
|
|
25079
|
+
* so the caller's clock and the orchestrator's never have to agree. */
|
|
25080
|
+
afterMs: number().finite(),
|
|
25081
|
+
/** Why, for the log. */
|
|
25082
|
+
reason: string()
|
|
25083
|
+
}), object({
|
|
25084
|
+
scheduled: boolean(),
|
|
25085
|
+
/** When `scheduled`: how long until the burst is dialled. */
|
|
25086
|
+
dueInMs: number().optional(),
|
|
25087
|
+
/** When not `scheduled`: why. */
|
|
25088
|
+
refusedBecause: OccupancyLookRefusalSchema.optional()
|
|
25089
|
+
}), {
|
|
25090
|
+
kind: "mutation",
|
|
25091
|
+
auth: "admin"
|
|
25092
|
+
}), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
24752
25093
|
kind: "mutation",
|
|
24753
25094
|
auth: "admin"
|
|
24754
25095
|
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
@@ -26826,7 +27167,7 @@ var ClipPlaybackSchema = object({
|
|
|
26826
27167
|
* **One authorised yes is one wake.** `next-natural` — take the clip the next
|
|
26827
27168
|
* time the camera is awake for its own reasons — is deliberately not a member:
|
|
26828
27169
|
* it was proposed, it is free on the battery, and the operator declined it on
|
|
26829
|
-
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."
|
|
27170
|
+
* 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
|
|
26830
27171
|
* D558 "Considered and not taken").
|
|
26831
27172
|
*/
|
|
26832
27173
|
var ClipWakeSchema = _enum(["authorised"]);
|
|
@@ -27087,7 +27428,7 @@ DeviceType.Camera, method(object({
|
|
|
27087
27428
|
* It replaced `sources?: string[]`, a VIEW filter over source ids that
|
|
27088
27429
|
* assumed the answer was a fan-out over everything a camera has. The
|
|
27089
27430
|
* operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
|
|
27090
|
-
* solo"* — so the list is asked of one provider at a time and there is
|
|
27431
|
+
* solo"* [there is only one user] — so the list is asked of one provider at a time and there is
|
|
27091
27432
|
* nothing to filter out of it.
|
|
27092
27433
|
*/
|
|
27093
27434
|
provider: string().min(1)
|
|
@@ -27215,219 +27556,6 @@ DeviceType.Camera, method(object({
|
|
|
27215
27556
|
auth: "protected"
|
|
27216
27557
|
});
|
|
27217
27558
|
/**
|
|
27218
|
-
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
27219
|
-
* name (same pattern as `snapshot`):
|
|
27220
|
-
*
|
|
27221
|
-
* - **Native** providers: registered per-device by device-driver
|
|
27222
|
-
* addons via `ctx.registerNativeCap` — either on a
|
|
27223
|
-
* `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
|
|
27224
|
-
* or directly on the camera (Reolink registers at camera level).
|
|
27225
|
-
* Emits an `onPressed` event every time the firmware pushes a
|
|
27226
|
-
* ring; status tracks the last press and a pressCount since start
|
|
27227
|
-
* (diagnostic).
|
|
27228
|
-
*
|
|
27229
|
-
* - **Wrapper** provider: the `virtual-doorbell` system builtin
|
|
27230
|
-
* (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
|
|
27231
|
-
* device (contact / switch / event-emitter …) into a doorbell for
|
|
27232
|
-
* a camera. `defaultActive: false` — the operator explicitly binds
|
|
27233
|
-
* it per camera in the device-bindings UI, then picks the source
|
|
27234
|
-
* device + trigger in the per-device settings.
|
|
27235
|
-
*
|
|
27236
|
-
* The DeviceEventPropagator re-emits `onPressed` on the camera parent
|
|
27237
|
-
* — subscribers listening at the camera level receive ring events
|
|
27238
|
-
* with `via[]` populated. No code on the parent needed.
|
|
27239
|
-
*/
|
|
27240
|
-
var DoorbellStatusSchema = object({
|
|
27241
|
-
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
27242
|
-
lastPressedAt: number().nullable(),
|
|
27243
|
-
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
27244
|
-
pressCountSinceStart: number()
|
|
27245
|
-
});
|
|
27246
|
-
var DoorbellPressEventSchema = object({
|
|
27247
|
-
deviceId: number(),
|
|
27248
|
-
timestamp: number()
|
|
27249
|
-
});
|
|
27250
|
-
/**
|
|
27251
|
-
* The `doorbell-source` extension slot's editable value (D648): the camera's
|
|
27252
|
-
* virtual-doorbell trigger devices, exactly what the wrapper's
|
|
27253
|
-
* `doorbellSources` persists (as `{ deviceId }` records).
|
|
27254
|
-
*/
|
|
27255
|
-
var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
|
|
27256
|
-
/**
|
|
27257
|
-
* The `doorbell-source` slot — which devices ring this camera's VIRTUAL
|
|
27258
|
-
* doorbell, owned by the `virtual-doorbell` wrapper over its
|
|
27259
|
-
* `doorbellSources` store (D648). A source rings when one of its
|
|
27260
|
-
* `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
|
|
27261
|
-
* different authority (`deviceManager.setWrapperActive`, D62) — the slot
|
|
27262
|
-
* reports it, it never writes it.
|
|
27263
|
-
*/
|
|
27264
|
-
var DOORBELL_SOURCE_SLOT = {
|
|
27265
|
-
id: "doorbell-source",
|
|
27266
|
-
label: "Doorbell trigger devices",
|
|
27267
|
-
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.",
|
|
27268
|
-
shape: "association",
|
|
27269
|
-
hostDeviceTypes: [DeviceType.Camera],
|
|
27270
|
-
sourceCaps: SOURCE_CAPS,
|
|
27271
|
-
cardinality: "many",
|
|
27272
|
-
value: DoorbellSourceSlotValueSchema
|
|
27273
|
-
};
|
|
27274
|
-
var doorbellCapability = {
|
|
27275
|
-
name: "doorbell",
|
|
27276
|
-
scope: "device",
|
|
27277
|
-
deviceNative: true,
|
|
27278
|
-
mode: "singleton",
|
|
27279
|
-
kind: "wrapper",
|
|
27280
|
-
defaultActive: false,
|
|
27281
|
-
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
27282
|
-
extensionSlots: [DOORBELL_SOURCE_SLOT],
|
|
27283
|
-
methods: {},
|
|
27284
|
-
events: {
|
|
27285
|
-
/**
|
|
27286
|
-
* Fires once per physical press. Reolink delivers via Baichuan
|
|
27287
|
-
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
27288
|
-
* release/duration — it's a pulse.
|
|
27289
|
-
*/
|
|
27290
|
-
onPressed: {
|
|
27291
|
-
data: DoorbellPressEventSchema,
|
|
27292
|
-
fromState: {
|
|
27293
|
-
field: "lastPressedAt",
|
|
27294
|
-
on: "advance"
|
|
27295
|
-
}
|
|
27296
|
-
} },
|
|
27297
|
-
status: {
|
|
27298
|
-
schema: DoorbellStatusSchema,
|
|
27299
|
-
kind: "push"
|
|
27300
|
-
},
|
|
27301
|
-
/**
|
|
27302
|
-
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
27303
|
-
* Mirrored by the kernel and readable via
|
|
27304
|
-
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
27305
|
-
* without subscribing.
|
|
27306
|
-
*/
|
|
27307
|
-
runtimeState: DoorbellStatusSchema,
|
|
27308
|
-
/**
|
|
27309
|
-
* 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.
|
|
27310
|
-
*
|
|
27311
|
-
* See `RuntimeStateDurability`. Enforced by
|
|
27312
|
-
* `scripts/check-runtime-state-durability.ts`.
|
|
27313
|
-
*/
|
|
27314
|
-
durability: "restored"
|
|
27315
|
-
};
|
|
27316
|
-
var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
|
|
27317
|
-
DeviceType.Camera, DeviceType.Camera;
|
|
27318
|
-
/** A slot's editable value, discriminated on `slot`. */
|
|
27319
|
-
var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
|
|
27320
|
-
DeviceType.Camera;
|
|
27321
|
-
var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
|
|
27322
|
-
state: literal("unreachable"),
|
|
27323
|
-
reason: string()
|
|
27324
|
-
})]);
|
|
27325
|
-
/** One provider of slots — the D554 source-listing row. */
|
|
27326
|
-
var ExtensionSourceSchema = object({
|
|
27327
|
-
/** The routing prefix of every `slotRef` this provider serves. */
|
|
27328
|
-
source: string(),
|
|
27329
|
-
label: string(),
|
|
27330
|
-
/** Stamped by the dispatcher from the registry (D557). */
|
|
27331
|
-
addonId: string().optional(),
|
|
27332
|
-
availability: ExtensionSourceAvailabilitySchema
|
|
27333
|
-
});
|
|
27334
|
-
/**
|
|
27335
|
-
* How one picked source stands. `missing` — no such device (deleted, or an id
|
|
27336
|
-
* that never existed); `foreign` — a device the slot's owner cannot read from
|
|
27337
|
-
* (a source owned by another addon); `unavailable` — it exists but is not a
|
|
27338
|
-
* valid source now (a container, which is never a pick). A source in any of
|
|
27339
|
-
* these states is SHOWN, never silently dropped or re-pointed.
|
|
27340
|
-
*/
|
|
27341
|
-
var ExtensionSourceHealthSchema = _enum([
|
|
27342
|
-
"ok",
|
|
27343
|
-
"missing",
|
|
27344
|
-
"foreign",
|
|
27345
|
-
"unavailable"
|
|
27346
|
-
]);
|
|
27347
|
-
var ExtensionSlotSourceSchema = object({
|
|
27348
|
-
deviceId: number().int(),
|
|
27349
|
-
/** The device's name, or null when it could not be resolved (`missing`). */
|
|
27350
|
-
name: string().nullable(),
|
|
27351
|
-
health: ExtensionSourceHealthSchema,
|
|
27352
|
-
detail: string().optional()
|
|
27353
|
-
});
|
|
27354
|
-
/**
|
|
27355
|
-
* A DIFFERENT authority that gates whether the slot's sources do anything —
|
|
27356
|
-
* reported read-only, named, never written through this contract (D62). The
|
|
27357
|
-
* virtual doorbell's sources ring only while the wrapper is bound to the
|
|
27358
|
-
* camera, and that binding belongs to `deviceManager.setWrapperActive`.
|
|
27359
|
-
* `unknown` means the gate could not be read; it is not "inactive" (D315).
|
|
27360
|
-
*/
|
|
27361
|
-
var ExtensionSlotActivationSchema = object({
|
|
27362
|
-
state: _enum([
|
|
27363
|
-
"active",
|
|
27364
|
-
"inactive",
|
|
27365
|
-
"unknown"
|
|
27366
|
-
]),
|
|
27367
|
-
authority: string(),
|
|
27368
|
-
detail: string().optional()
|
|
27369
|
-
});
|
|
27370
|
-
var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
|
|
27371
|
-
state: literal("ok"),
|
|
27372
|
-
/** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
|
|
27373
|
-
slotRef: string(),
|
|
27374
|
-
slot: ExtensionSlotIdSchema,
|
|
27375
|
-
/** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
|
|
27376
|
-
authority: string(),
|
|
27377
|
-
activation: ExtensionSlotActivationSchema.nullable(),
|
|
27378
|
-
value: ExtensionSlotValueSchema,
|
|
27379
|
-
sources: array(ExtensionSlotSourceSchema),
|
|
27380
|
-
/**
|
|
27381
|
-
* Devices the owner links to the host ON ITS OWN, by structure, and that
|
|
27382
|
-
* are therefore not in `value` (D655): a camera's device-tree children, and
|
|
27383
|
-
* the child a picked container stands for (D356 — a container is never a
|
|
27384
|
-
* pick, its children are). Read-only; the editor shows them and may offer
|
|
27385
|
-
* per-device options on them (the linked-devices tracked-event opt-in).
|
|
27386
|
-
* Absent when the owner links nothing beyond the picks, and from an owner
|
|
27387
|
-
* older than D655.
|
|
27388
|
-
*/
|
|
27389
|
-
impliedSources: array(ExtensionSlotSourceSchema).optional()
|
|
27390
|
-
}), object({
|
|
27391
|
-
state: literal("unreachable"),
|
|
27392
|
-
addonId: string(),
|
|
27393
|
-
reason: string()
|
|
27394
|
-
})]);
|
|
27395
|
-
var ExtensionCandidatesSchema = object({ candidates: array(object({
|
|
27396
|
-
deviceId: number().int(),
|
|
27397
|
-
name: string(),
|
|
27398
|
-
type: string(),
|
|
27399
|
-
location: string().nullable(),
|
|
27400
|
-
/** The container a child belongs to — "Spotlight 2" alone does not say which. */
|
|
27401
|
-
parentName: string().nullable(),
|
|
27402
|
-
/** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
|
|
27403
|
-
suggested: boolean(),
|
|
27404
|
-
/** Why it is suggested ("same location"), null when it is not. */
|
|
27405
|
-
reason: string().nullable()
|
|
27406
|
-
})) });
|
|
27407
|
-
/**
|
|
27408
|
-
* What a write did. `none` — applied in place. `host` / `parent` — the owner
|
|
27409
|
-
* reloaded the host (or, for an accessory child, its parent) because the
|
|
27410
|
-
* write changed what the host REGISTERS. A slot never adds a capability to its
|
|
27411
|
-
* host — that is a composition (D663) — so today's owners answer `none`.
|
|
27412
|
-
*/
|
|
27413
|
-
var ExtensionSetResultSchema = object({
|
|
27414
|
-
applied: literal(true),
|
|
27415
|
-
reload: _enum([
|
|
27416
|
-
"none",
|
|
27417
|
-
"host",
|
|
27418
|
-
"parent"
|
|
27419
|
-
])
|
|
27420
|
-
});
|
|
27421
|
-
var ExtensionSlotRefInputSchema = object({
|
|
27422
|
-
deviceId: number().int(),
|
|
27423
|
-
slotRef: string().min(1)
|
|
27424
|
-
});
|
|
27425
|
-
var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
|
|
27426
|
-
method(object({ deviceId: number().int() }), array(ExtensionSourceSchema)), method(object({ deviceId: number().int() }), array(ExtensionSlotRowSchema)), method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema), method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
|
|
27427
|
-
kind: "mutation",
|
|
27428
|
-
auth: "admin"
|
|
27429
|
-
});
|
|
27430
|
-
/**
|
|
27431
27559
|
* Optional client-side hints sent at session creation to help the provider
|
|
27432
27560
|
* pick the best native source. All fields optional — a viewer that knows
|
|
27433
27561
|
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
@@ -29903,6 +30031,70 @@ onStatusChanged: { data: object({
|
|
|
29903
30031
|
* whether persisting is worth a SQLite commit. */
|
|
29904
30032
|
volatileStateFields: ["lastChangedAt"]
|
|
29905
30033
|
};
|
|
30034
|
+
var DoorbellStatusSchema = object({
|
|
30035
|
+
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
30036
|
+
lastPressedAt: number().nullable(),
|
|
30037
|
+
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
30038
|
+
pressCountSinceStart: number()
|
|
30039
|
+
});
|
|
30040
|
+
var DoorbellPressEventSchema = object({
|
|
30041
|
+
deviceId: number(),
|
|
30042
|
+
timestamp: number()
|
|
30043
|
+
});
|
|
30044
|
+
/**
|
|
30045
|
+
* Doorbell button cap. Two kinds of provider serve it, and to every consumer
|
|
30046
|
+
* they are the same cap:
|
|
30047
|
+
*
|
|
30048
|
+
* - **Native** providers, registered per device by a driver addon through
|
|
30049
|
+
* `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
|
|
30050
|
+
* `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
|
|
30051
|
+
* camera level). They emit `onPressed` on every firmware ring.
|
|
30052
|
+
* - **A composed doorbell** (D670, D671): a camera's customization gives it
|
|
30053
|
+
* the cap, its `lastPressedAt` rising from the sources the operator
|
|
30054
|
+
* assigned in Customize → Doorbell, and the composer emits `onPressed`
|
|
30055
|
+
* from that field's advance (`fromState`).
|
|
30056
|
+
*
|
|
30057
|
+
* The DeviceEventPropagator re-emits `onPressed` on the camera parent.
|
|
30058
|
+
*/
|
|
30059
|
+
var doorbellCapability = {
|
|
30060
|
+
name: "doorbell",
|
|
30061
|
+
scope: "device",
|
|
30062
|
+
deviceNative: true,
|
|
30063
|
+
mode: "singleton",
|
|
30064
|
+
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
30065
|
+
methods: {},
|
|
30066
|
+
events: {
|
|
30067
|
+
/**
|
|
30068
|
+
* Fires once per physical press. Reolink delivers via Baichuan
|
|
30069
|
+
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
30070
|
+
* release/duration — it's a pulse.
|
|
30071
|
+
*/
|
|
30072
|
+
onPressed: {
|
|
30073
|
+
data: DoorbellPressEventSchema,
|
|
30074
|
+
fromState: {
|
|
30075
|
+
field: "lastPressedAt",
|
|
30076
|
+
on: "advance"
|
|
30077
|
+
}
|
|
30078
|
+
} },
|
|
30079
|
+
status: {
|
|
30080
|
+
schema: DoorbellStatusSchema,
|
|
30081
|
+
kind: "push"
|
|
30082
|
+
},
|
|
30083
|
+
/**
|
|
30084
|
+
* Runtime-state slice — last press timestamp + lifetime press count.
|
|
30085
|
+
* Mirrored by the kernel and readable via
|
|
30086
|
+
* `device.state.doorbell.value`. UIs can show "last ring 5m ago"
|
|
30087
|
+
* without subscribing.
|
|
30088
|
+
*/
|
|
30089
|
+
runtimeState: DoorbellStatusSchema,
|
|
30090
|
+
/**
|
|
30091
|
+
* 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.
|
|
30092
|
+
*
|
|
30093
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
30094
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
30095
|
+
*/
|
|
30096
|
+
durability: "restored"
|
|
30097
|
+
};
|
|
29906
30098
|
/**
|
|
29907
30099
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
29908
30100
|
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
@@ -32047,9 +32239,9 @@ var MotionStatusSchema = object({
|
|
|
32047
32239
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
32048
32240
|
lastDetectedAt: number().nullable(),
|
|
32049
32241
|
/**
|
|
32050
|
-
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device
|
|
32051
|
-
* `null` while false and on every `Sensor`
|
|
32052
|
-
* constant's doc for the one-authority rule.
|
|
32242
|
+
* `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
|
|
32243
|
+
* orchestrator writes it, D696), `null` while false and on every `Sensor`
|
|
32244
|
+
* device (D475) — see that constant's doc for the one-authority rule.
|
|
32053
32245
|
*
|
|
32054
32246
|
* ## Reading this field still arms nothing
|
|
32055
32247
|
*
|
|
@@ -32067,34 +32259,31 @@ var MotionStatusSchema = object({
|
|
|
32067
32259
|
* `addon-export-alexa/src/motion-clear-hold.ts` and
|
|
32068
32260
|
* `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
|
|
32069
32261
|
*
|
|
32070
|
-
* ## Who writes it
|
|
32071
|
-
*
|
|
32072
|
-
* - **Cameras** — the
|
|
32073
|
-
*
|
|
32074
|
-
* `
|
|
32075
|
-
* `
|
|
32076
|
-
*
|
|
32077
|
-
*
|
|
32078
|
-
* a
|
|
32079
|
-
*
|
|
32080
|
-
*
|
|
32081
|
-
*
|
|
32082
|
-
*
|
|
32083
|
-
*
|
|
32084
|
-
*
|
|
32085
|
-
*
|
|
32086
|
-
*
|
|
32087
|
-
*
|
|
32088
|
-
* `
|
|
32089
|
-
*
|
|
32090
|
-
*
|
|
32091
|
-
*
|
|
32092
|
-
*
|
|
32093
|
-
*
|
|
32094
|
-
*
|
|
32095
|
-
* This predates D475 and is not fixed there: the fix touches every
|
|
32096
|
-
* camera provider. Recorded in D475's Consequences. Do not restore the
|
|
32097
|
-
* "sole writer" wording without also removing the other writers.
|
|
32262
|
+
* ## Who writes it (D696)
|
|
32263
|
+
*
|
|
32264
|
+
* - **Cameras** — the orchestrator, and nothing else. It writes the camera's
|
|
32265
|
+
* EFFECTIVE motion (`addon-pipeline-orchestrator`
|
|
32266
|
+
* `camera-sensors/motion-slice.ts`), alongside the effective
|
|
32267
|
+
* `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
|
|
32268
|
+
* for a split camera, an unsplit emitter's direct event, the analyzer and
|
|
32269
|
+
* device activity, as the camera's `motionSources` counts them. A source
|
|
32270
|
+
* that never sends a clear falls one window after its last `true`.
|
|
32271
|
+
* `lastDetectedAt` moves only on an effective rise. No camera provider
|
|
32272
|
+
* writes this slice (not even a boot seed), and neither does the runner's
|
|
32273
|
+
* phase machine: its phase is "a session is attached" for every on-motion
|
|
32274
|
+
* session, not motion, and it now has its own `DetectionPhaseTransition`.
|
|
32275
|
+
* A provider's `isDetected` answers from the hub's slice.
|
|
32276
|
+
* - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
|
|
32277
|
+
* imports) — the provider pushes both edges itself, from the upstream
|
|
32278
|
+
* system's own state change. That is the sensor's own fact.
|
|
32279
|
+
*
|
|
32280
|
+
* `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
|
|
32281
|
+
* `motion` slice; each sensor writer is a named exemption.
|
|
32282
|
+
*
|
|
32283
|
+
* This replaces the D475 §4 rule ("the phase machine is the sole writer").
|
|
32284
|
+
* That rule was never true: Hikvision and Amcrest wrote the slice raw beside
|
|
32285
|
+
* it, every provider seeded it at boot, and every session left it
|
|
32286
|
+
* `detected: true` after its detach.
|
|
32098
32287
|
*/
|
|
32099
32288
|
autoClearAfterMs: number().nullable()
|
|
32100
32289
|
});
|
|
@@ -32166,11 +32355,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
32166
32355
|
*/
|
|
32167
32356
|
runtimeState: MotionStatusSchema,
|
|
32168
32357
|
/**
|
|
32169
|
-
* Runtime-state durability: **session** —
|
|
32358
|
+
* Runtime-state durability: **session** — the writer of this slice
|
|
32170
32359
|
* writes only on an EDGE, so a restored `detected: true` would stay
|
|
32171
32360
|
* frozen until the next one instead of being corrected. The next edge
|
|
32172
|
-
* re-publishes the real state
|
|
32173
|
-
*
|
|
32361
|
+
* re-publishes the real state, and the orchestrator re-publishes every
|
|
32362
|
+
* camera when it starts writing (D696; on who writes it, see
|
|
32363
|
+
* `autoClearAfterMs` above).
|
|
32174
32364
|
*
|
|
32175
32365
|
* See `RuntimeStateDurability`. Enforced by
|
|
32176
32366
|
* `scripts/check-runtime-state-durability.ts`.
|
|
@@ -34553,8 +34743,7 @@ var ptzAutotrackCapability = {
|
|
|
34553
34743
|
deviceNative: true,
|
|
34554
34744
|
mode: "singleton",
|
|
34555
34745
|
/**
|
|
34556
|
-
* Two kinds of provider behind one name, the same shape `snapshot`
|
|
34557
|
-
* `doorbell` use:
|
|
34746
|
+
* Two kinds of provider behind one name, the same shape `snapshot` uses:
|
|
34558
34747
|
*
|
|
34559
34748
|
* - **Native**: the camera's own firmware autotrack, registered per device by
|
|
34560
34749
|
* the driver when the probe says it exists (Reolink: yes; Hikvision:
|
|
@@ -34562,7 +34751,7 @@ var ptzAutotrackCapability = {
|
|
|
34562
34751
|
* - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
|
|
34563
34752
|
* which follows a subject with `ptz.move` pulses driven by the detection
|
|
34564
34753
|
* pipeline. `defaultActive: false` — the operator binds it per camera in
|
|
34565
|
-
* the bindings UI
|
|
34754
|
+
* the bindings UI.
|
|
34566
34755
|
*
|
|
34567
34756
|
* The binding chooses WHICH implementation answers; `setEnabled` stays the
|
|
34568
34757
|
* one switch for the function either way. A camera never has both driving its
|
|
@@ -35237,7 +35426,7 @@ var ReadGopBytesResultSchema = object({
|
|
|
35237
35426
|
/**
|
|
35238
35427
|
* A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
|
|
35239
35428
|
* twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
|
|
35240
|
-
* replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-
|
|
35429
|
+
* replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
|
|
35241
35430
|
* a replay needs several seconds of native pixels, not one frame.
|
|
35242
35431
|
*
|
|
35243
35432
|
* `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
|
|
@@ -38601,6 +38790,7 @@ var zoneRulesCapability = {
|
|
|
38601
38790
|
*/
|
|
38602
38791
|
durability: "restored"
|
|
38603
38792
|
};
|
|
38793
|
+
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
38604
38794
|
/**
|
|
38605
38795
|
* Accessory device helpers — shared across drivers.
|
|
38606
38796
|
*
|
|
@@ -39660,13 +39850,14 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
39660
39850
|
async getStatus() {
|
|
39661
39851
|
const all = await this.ctx.kernel.devices?.getAll() ?? [];
|
|
39662
39852
|
const summary = this.restoreFailureSummary();
|
|
39663
|
-
|
|
39853
|
+
const base = {
|
|
39664
39854
|
connected: true,
|
|
39665
|
-
deviceCount: all.length
|
|
39855
|
+
deviceCount: all.length,
|
|
39856
|
+
motionSliceWriter: "orchestrator"
|
|
39666
39857
|
};
|
|
39858
|
+
if (summary === null) return base;
|
|
39667
39859
|
return {
|
|
39668
|
-
|
|
39669
|
-
deviceCount: all.length,
|
|
39860
|
+
...base,
|
|
39670
39861
|
error: summary
|
|
39671
39862
|
};
|
|
39672
39863
|
}
|
|
@@ -42696,6 +42887,18 @@ Object.freeze({
|
|
|
42696
42887
|
addonId: null,
|
|
42697
42888
|
access: "view"
|
|
42698
42889
|
},
|
|
42890
|
+
"databaseSnapshot.listDatabases": {
|
|
42891
|
+
capName: "database-snapshot",
|
|
42892
|
+
capScope: "system",
|
|
42893
|
+
addonId: null,
|
|
42894
|
+
access: "view"
|
|
42895
|
+
},
|
|
42896
|
+
"databaseSnapshot.writeSnapshot": {
|
|
42897
|
+
capName: "database-snapshot",
|
|
42898
|
+
capScope: "system",
|
|
42899
|
+
addonId: null,
|
|
42900
|
+
access: "create"
|
|
42901
|
+
},
|
|
42699
42902
|
"dataStoreProvider.aggregate": {
|
|
42700
42903
|
capName: "data-store-provider",
|
|
42701
42904
|
capScope: "system",
|
|
@@ -45156,6 +45359,12 @@ Object.freeze({
|
|
|
45156
45359
|
addonId: null,
|
|
45157
45360
|
access: "view"
|
|
45158
45361
|
},
|
|
45362
|
+
"notificationRules.getAlarmSensors": {
|
|
45363
|
+
capName: "notification-rules",
|
|
45364
|
+
capScope: "system",
|
|
45365
|
+
addonId: null,
|
|
45366
|
+
access: "view"
|
|
45367
|
+
},
|
|
45159
45368
|
"notificationRules.getClipRetentionAsks": {
|
|
45160
45369
|
capName: "notification-rules",
|
|
45161
45370
|
capScope: "system",
|
|
@@ -46260,6 +46469,12 @@ Object.freeze({
|
|
|
46260
46469
|
addonId: null,
|
|
46261
46470
|
access: "delete"
|
|
46262
46471
|
},
|
|
46472
|
+
"pipelineOrchestrator.requestOccupancyLook": {
|
|
46473
|
+
capName: "pipeline-orchestrator",
|
|
46474
|
+
capScope: "system",
|
|
46475
|
+
addonId: null,
|
|
46476
|
+
access: "create"
|
|
46477
|
+
},
|
|
46263
46478
|
"pipelineOrchestrator.resetNodePipelineDefaults": {
|
|
46264
46479
|
capName: "pipeline-orchestrator",
|
|
46265
46480
|
capScope: "system",
|
|
@@ -48728,6 +48943,11 @@ Object.freeze({
|
|
|
48728
48943
|
}
|
|
48729
48944
|
});
|
|
48730
48945
|
Object.freeze({
|
|
48946
|
+
"accessories.getStatus": [{
|
|
48947
|
+
name: "deviceId",
|
|
48948
|
+
form: "single",
|
|
48949
|
+
optional: false
|
|
48950
|
+
}],
|
|
48731
48951
|
"accessories.setChildHidden": [{
|
|
48732
48952
|
name: "childDeviceId",
|
|
48733
48953
|
form: "single",
|
|
@@ -48747,6 +48967,11 @@ Object.freeze({
|
|
|
48747
48967
|
form: "single",
|
|
48748
48968
|
optional: false
|
|
48749
48969
|
}],
|
|
48970
|
+
"airQualitySensor.getStatus": [{
|
|
48971
|
+
name: "deviceId",
|
|
48972
|
+
form: "single",
|
|
48973
|
+
optional: false
|
|
48974
|
+
}],
|
|
48750
48975
|
"alarmPanel.arm": [{
|
|
48751
48976
|
name: "deviceId",
|
|
48752
48977
|
form: "single",
|
|
@@ -48757,11 +48982,36 @@ Object.freeze({
|
|
|
48757
48982
|
form: "single",
|
|
48758
48983
|
optional: false
|
|
48759
48984
|
}],
|
|
48985
|
+
"alarmPanel.getStatus": [{
|
|
48986
|
+
name: "deviceId",
|
|
48987
|
+
form: "single",
|
|
48988
|
+
optional: false
|
|
48989
|
+
}],
|
|
48760
48990
|
"alarmPanel.trigger": [{
|
|
48761
48991
|
name: "deviceId",
|
|
48762
48992
|
form: "single",
|
|
48763
48993
|
optional: false
|
|
48764
48994
|
}],
|
|
48995
|
+
"ambientLightSensor.getStatus": [{
|
|
48996
|
+
name: "deviceId",
|
|
48997
|
+
form: "single",
|
|
48998
|
+
optional: false
|
|
48999
|
+
}],
|
|
49000
|
+
"audioAnalysis.applyDeviceSettingsPatch": [{
|
|
49001
|
+
name: "deviceId",
|
|
49002
|
+
form: "single",
|
|
49003
|
+
optional: false
|
|
49004
|
+
}],
|
|
49005
|
+
"audioAnalysis.getDeviceLiveContribution": [{
|
|
49006
|
+
name: "deviceId",
|
|
49007
|
+
form: "single",
|
|
49008
|
+
optional: false
|
|
49009
|
+
}],
|
|
49010
|
+
"audioAnalysis.getDeviceSettingsContribution": [{
|
|
49011
|
+
name: "deviceId",
|
|
49012
|
+
form: "single",
|
|
49013
|
+
optional: false
|
|
49014
|
+
}],
|
|
48765
49015
|
"audioAnalysis.resolveDeviceSettings": [{
|
|
48766
49016
|
name: "deviceId",
|
|
48767
49017
|
form: "single",
|
|
@@ -48802,16 +49052,36 @@ Object.freeze({
|
|
|
48802
49052
|
form: "single",
|
|
48803
49053
|
optional: false
|
|
48804
49054
|
}],
|
|
49055
|
+
"automationControl.getStatus": [{
|
|
49056
|
+
name: "deviceId",
|
|
49057
|
+
form: "single",
|
|
49058
|
+
optional: false
|
|
49059
|
+
}],
|
|
48805
49060
|
"automationControl.trigger": [{
|
|
48806
49061
|
name: "deviceId",
|
|
48807
49062
|
form: "single",
|
|
48808
49063
|
optional: false
|
|
48809
49064
|
}],
|
|
49065
|
+
"battery.getStatus": [{
|
|
49066
|
+
name: "deviceId",
|
|
49067
|
+
form: "single",
|
|
49068
|
+
optional: false
|
|
49069
|
+
}],
|
|
48810
49070
|
"battery.wakeForStream": [{
|
|
48811
49071
|
name: "deviceId",
|
|
48812
49072
|
form: "single",
|
|
48813
49073
|
optional: false
|
|
48814
49074
|
}],
|
|
49075
|
+
"binary.getStatus": [{
|
|
49076
|
+
name: "deviceId",
|
|
49077
|
+
form: "single",
|
|
49078
|
+
optional: false
|
|
49079
|
+
}],
|
|
49080
|
+
"brightness.getStatus": [{
|
|
49081
|
+
name: "deviceId",
|
|
49082
|
+
form: "single",
|
|
49083
|
+
optional: false
|
|
49084
|
+
}],
|
|
48815
49085
|
"brightness.setBrightness": [{
|
|
48816
49086
|
name: "deviceId",
|
|
48817
49087
|
form: "single",
|
|
@@ -48827,6 +49097,26 @@ Object.freeze({
|
|
|
48827
49097
|
form: "single",
|
|
48828
49098
|
optional: false
|
|
48829
49099
|
}],
|
|
49100
|
+
"cameraCredentials.getStatus": [{
|
|
49101
|
+
name: "deviceId",
|
|
49102
|
+
form: "single",
|
|
49103
|
+
optional: false
|
|
49104
|
+
}],
|
|
49105
|
+
"cameraGridLayout.applyDeviceSettingsPatch": [{
|
|
49106
|
+
name: "deviceId",
|
|
49107
|
+
form: "single",
|
|
49108
|
+
optional: false
|
|
49109
|
+
}],
|
|
49110
|
+
"cameraGridLayout.getDeviceLiveContribution": [{
|
|
49111
|
+
name: "deviceId",
|
|
49112
|
+
form: "single",
|
|
49113
|
+
optional: false
|
|
49114
|
+
}],
|
|
49115
|
+
"cameraGridLayout.getDeviceSettingsContribution": [{
|
|
49116
|
+
name: "deviceId",
|
|
49117
|
+
form: "single",
|
|
49118
|
+
optional: false
|
|
49119
|
+
}],
|
|
48830
49120
|
"cameraGridLayout.getLayout": [{
|
|
48831
49121
|
name: "deviceId",
|
|
48832
49122
|
form: "single",
|
|
@@ -48842,6 +49132,21 @@ Object.freeze({
|
|
|
48842
49132
|
form: "single",
|
|
48843
49133
|
optional: false
|
|
48844
49134
|
}],
|
|
49135
|
+
"cameraPipelineConfig.applyDeviceSettingsPatch": [{
|
|
49136
|
+
name: "deviceId",
|
|
49137
|
+
form: "single",
|
|
49138
|
+
optional: false
|
|
49139
|
+
}],
|
|
49140
|
+
"cameraPipelineConfig.getDeviceLiveContribution": [{
|
|
49141
|
+
name: "deviceId",
|
|
49142
|
+
form: "single",
|
|
49143
|
+
optional: false
|
|
49144
|
+
}],
|
|
49145
|
+
"cameraPipelineConfig.getDeviceSettingsContribution": [{
|
|
49146
|
+
name: "deviceId",
|
|
49147
|
+
form: "single",
|
|
49148
|
+
optional: false
|
|
49149
|
+
}],
|
|
48845
49150
|
"cameraStreams.getBrokerStreams": [{
|
|
48846
49151
|
name: "deviceId",
|
|
48847
49152
|
form: "single",
|
|
@@ -48867,6 +49172,16 @@ Object.freeze({
|
|
|
48867
49172
|
form: "single",
|
|
48868
49173
|
optional: false
|
|
48869
49174
|
}],
|
|
49175
|
+
"carbonMonoxide.getStatus": [{
|
|
49176
|
+
name: "deviceId",
|
|
49177
|
+
form: "single",
|
|
49178
|
+
optional: false
|
|
49179
|
+
}],
|
|
49180
|
+
"climateControl.getStatus": [{
|
|
49181
|
+
name: "deviceId",
|
|
49182
|
+
form: "single",
|
|
49183
|
+
optional: false
|
|
49184
|
+
}],
|
|
48870
49185
|
"climateControl.setFanMode": [{
|
|
48871
49186
|
name: "deviceId",
|
|
48872
49187
|
form: "single",
|
|
@@ -48907,16 +49222,41 @@ Object.freeze({
|
|
|
48907
49222
|
form: "single",
|
|
48908
49223
|
optional: false
|
|
48909
49224
|
}],
|
|
49225
|
+
"color.getStatus": [{
|
|
49226
|
+
name: "deviceId",
|
|
49227
|
+
form: "single",
|
|
49228
|
+
optional: false
|
|
49229
|
+
}],
|
|
48910
49230
|
"color.setColor": [{
|
|
48911
49231
|
name: "deviceId",
|
|
48912
49232
|
form: "single",
|
|
48913
49233
|
optional: false
|
|
48914
49234
|
}],
|
|
49235
|
+
"connectivity.getStatus": [{
|
|
49236
|
+
name: "deviceId",
|
|
49237
|
+
form: "single",
|
|
49238
|
+
optional: false
|
|
49239
|
+
}],
|
|
49240
|
+
"consumables.getStatus": [{
|
|
49241
|
+
name: "deviceId",
|
|
49242
|
+
form: "single",
|
|
49243
|
+
optional: false
|
|
49244
|
+
}],
|
|
48915
49245
|
"consumables.reset": [{
|
|
48916
49246
|
name: "deviceId",
|
|
48917
49247
|
form: "single",
|
|
48918
49248
|
optional: false
|
|
48919
49249
|
}],
|
|
49250
|
+
"contact.getStatus": [{
|
|
49251
|
+
name: "deviceId",
|
|
49252
|
+
form: "single",
|
|
49253
|
+
optional: false
|
|
49254
|
+
}],
|
|
49255
|
+
"control.getStatus": [{
|
|
49256
|
+
name: "deviceId",
|
|
49257
|
+
form: "single",
|
|
49258
|
+
optional: false
|
|
49259
|
+
}],
|
|
48920
49260
|
"control.setValue": [{
|
|
48921
49261
|
name: "deviceId",
|
|
48922
49262
|
form: "single",
|
|
@@ -48927,6 +49267,11 @@ Object.freeze({
|
|
|
48927
49267
|
form: "single",
|
|
48928
49268
|
optional: false
|
|
48929
49269
|
}],
|
|
49270
|
+
"cover.getStatus": [{
|
|
49271
|
+
name: "deviceId",
|
|
49272
|
+
form: "single",
|
|
49273
|
+
optional: false
|
|
49274
|
+
}],
|
|
48930
49275
|
"cover.open": [{
|
|
48931
49276
|
name: "deviceId",
|
|
48932
49277
|
form: "single",
|
|
@@ -48952,6 +49297,11 @@ Object.freeze({
|
|
|
48952
49297
|
form: "single",
|
|
48953
49298
|
optional: false
|
|
48954
49299
|
}],
|
|
49300
|
+
"dayNight.getStatus": [{
|
|
49301
|
+
name: "deviceId",
|
|
49302
|
+
form: "single",
|
|
49303
|
+
optional: false
|
|
49304
|
+
}],
|
|
48955
49305
|
"dayNight.setSettings": [{
|
|
48956
49306
|
name: "deviceId",
|
|
48957
49307
|
form: "single",
|
|
@@ -48962,11 +49312,31 @@ Object.freeze({
|
|
|
48962
49312
|
form: "single",
|
|
48963
49313
|
optional: true
|
|
48964
49314
|
}],
|
|
49315
|
+
"detectionPipeline.applyDeviceSettingsPatch": [{
|
|
49316
|
+
name: "deviceId",
|
|
49317
|
+
form: "single",
|
|
49318
|
+
optional: false
|
|
49319
|
+
}],
|
|
49320
|
+
"detectionPipeline.getDeviceLiveContribution": [{
|
|
49321
|
+
name: "deviceId",
|
|
49322
|
+
form: "single",
|
|
49323
|
+
optional: false
|
|
49324
|
+
}],
|
|
49325
|
+
"detectionPipeline.getDeviceSettingsContribution": [{
|
|
49326
|
+
name: "deviceId",
|
|
49327
|
+
form: "single",
|
|
49328
|
+
optional: false
|
|
49329
|
+
}],
|
|
48965
49330
|
"deviceAdminLink.getAdminLink": [{
|
|
48966
49331
|
name: "deviceId",
|
|
48967
49332
|
form: "single",
|
|
48968
49333
|
optional: false
|
|
48969
49334
|
}],
|
|
49335
|
+
"deviceAdoption.getStatus": [{
|
|
49336
|
+
name: "deviceId",
|
|
49337
|
+
form: "single",
|
|
49338
|
+
optional: false
|
|
49339
|
+
}],
|
|
48970
49340
|
"deviceAdoption.release": [{
|
|
48971
49341
|
name: "camDeviceId",
|
|
48972
49342
|
form: "single",
|
|
@@ -48982,6 +49352,11 @@ Object.freeze({
|
|
|
48982
49352
|
form: "single",
|
|
48983
49353
|
optional: false
|
|
48984
49354
|
}],
|
|
49355
|
+
"deviceDiscovery.getStatus": [{
|
|
49356
|
+
name: "deviceId",
|
|
49357
|
+
form: "single",
|
|
49358
|
+
optional: false
|
|
49359
|
+
}],
|
|
48985
49360
|
"deviceDiscovery.listDiscovered": [{
|
|
48986
49361
|
name: "deviceId",
|
|
48987
49362
|
form: "single",
|
|
@@ -49001,6 +49376,21 @@ Object.freeze({
|
|
|
49001
49376
|
form: "single",
|
|
49002
49377
|
optional: false
|
|
49003
49378
|
}],
|
|
49379
|
+
"deviceExport.applyDeviceSettingsPatch": [{
|
|
49380
|
+
name: "deviceId",
|
|
49381
|
+
form: "single",
|
|
49382
|
+
optional: false
|
|
49383
|
+
}],
|
|
49384
|
+
"deviceExport.getDeviceLiveContribution": [{
|
|
49385
|
+
name: "deviceId",
|
|
49386
|
+
form: "single",
|
|
49387
|
+
optional: false
|
|
49388
|
+
}],
|
|
49389
|
+
"deviceExport.getDeviceSettingsContribution": [{
|
|
49390
|
+
name: "deviceId",
|
|
49391
|
+
form: "single",
|
|
49392
|
+
optional: false
|
|
49393
|
+
}],
|
|
49004
49394
|
"deviceExtension.listCandidates": [{
|
|
49005
49395
|
name: "deviceId",
|
|
49006
49396
|
form: "single",
|
|
@@ -49349,6 +49739,26 @@ Object.freeze({
|
|
|
49349
49739
|
form: "single",
|
|
49350
49740
|
optional: false
|
|
49351
49741
|
}],
|
|
49742
|
+
"deviceStatus.getStatus": [{
|
|
49743
|
+
name: "deviceId",
|
|
49744
|
+
form: "single",
|
|
49745
|
+
optional: false
|
|
49746
|
+
}],
|
|
49747
|
+
"doorbell.getStatus": [{
|
|
49748
|
+
name: "deviceId",
|
|
49749
|
+
form: "single",
|
|
49750
|
+
optional: false
|
|
49751
|
+
}],
|
|
49752
|
+
"enumSensor.getStatus": [{
|
|
49753
|
+
name: "deviceId",
|
|
49754
|
+
form: "single",
|
|
49755
|
+
optional: false
|
|
49756
|
+
}],
|
|
49757
|
+
"eventEmitter.getStatus": [{
|
|
49758
|
+
name: "deviceId",
|
|
49759
|
+
form: "single",
|
|
49760
|
+
optional: false
|
|
49761
|
+
}],
|
|
49352
49762
|
"faceGallery.getFaceByTrack": [{
|
|
49353
49763
|
name: "deviceId",
|
|
49354
49764
|
form: "single",
|
|
@@ -49363,6 +49773,11 @@ Object.freeze({
|
|
|
49363
49773
|
form: "array",
|
|
49364
49774
|
optional: true
|
|
49365
49775
|
}],
|
|
49776
|
+
"fanControl.getStatus": [{
|
|
49777
|
+
name: "deviceId",
|
|
49778
|
+
form: "single",
|
|
49779
|
+
optional: false
|
|
49780
|
+
}],
|
|
49366
49781
|
"fanControl.setDirection": [{
|
|
49367
49782
|
name: "deviceId",
|
|
49368
49783
|
form: "single",
|
|
@@ -49383,6 +49798,26 @@ Object.freeze({
|
|
|
49383
49798
|
form: "single",
|
|
49384
49799
|
optional: false
|
|
49385
49800
|
}],
|
|
49801
|
+
"featureProbe.getStatus": [{
|
|
49802
|
+
name: "deviceId",
|
|
49803
|
+
form: "single",
|
|
49804
|
+
optional: false
|
|
49805
|
+
}],
|
|
49806
|
+
"flood.getStatus": [{
|
|
49807
|
+
name: "deviceId",
|
|
49808
|
+
form: "single",
|
|
49809
|
+
optional: false
|
|
49810
|
+
}],
|
|
49811
|
+
"gas.getStatus": [{
|
|
49812
|
+
name: "deviceId",
|
|
49813
|
+
form: "single",
|
|
49814
|
+
optional: false
|
|
49815
|
+
}],
|
|
49816
|
+
"humidifier.getStatus": [{
|
|
49817
|
+
name: "deviceId",
|
|
49818
|
+
form: "single",
|
|
49819
|
+
optional: false
|
|
49820
|
+
}],
|
|
49386
49821
|
"humidifier.setMode": [{
|
|
49387
49822
|
name: "deviceId",
|
|
49388
49823
|
form: "single",
|
|
@@ -49398,11 +49833,26 @@ Object.freeze({
|
|
|
49398
49833
|
form: "single",
|
|
49399
49834
|
optional: false
|
|
49400
49835
|
}],
|
|
49836
|
+
"humiditySensor.getStatus": [{
|
|
49837
|
+
name: "deviceId",
|
|
49838
|
+
form: "single",
|
|
49839
|
+
optional: false
|
|
49840
|
+
}],
|
|
49841
|
+
"image.getStatus": [{
|
|
49842
|
+
name: "deviceId",
|
|
49843
|
+
form: "single",
|
|
49844
|
+
optional: false
|
|
49845
|
+
}],
|
|
49401
49846
|
"imageSettings.getOptions": [{
|
|
49402
49847
|
name: "deviceId",
|
|
49403
49848
|
form: "single",
|
|
49404
49849
|
optional: false
|
|
49405
49850
|
}],
|
|
49851
|
+
"imageSettings.getStatus": [{
|
|
49852
|
+
name: "deviceId",
|
|
49853
|
+
form: "single",
|
|
49854
|
+
optional: false
|
|
49855
|
+
}],
|
|
49406
49856
|
"imageSettings.setSettings": [{
|
|
49407
49857
|
name: "deviceId",
|
|
49408
49858
|
form: "single",
|
|
@@ -49413,6 +49863,11 @@ Object.freeze({
|
|
|
49413
49863
|
form: "single",
|
|
49414
49864
|
optional: false
|
|
49415
49865
|
}],
|
|
49866
|
+
"intercom.getStatus": [{
|
|
49867
|
+
name: "deviceId",
|
|
49868
|
+
form: "single",
|
|
49869
|
+
optional: false
|
|
49870
|
+
}],
|
|
49416
49871
|
"intercom.handleAnswer": [{
|
|
49417
49872
|
name: "deviceId",
|
|
49418
49873
|
form: "single",
|
|
@@ -49443,6 +49898,11 @@ Object.freeze({
|
|
|
49443
49898
|
form: "single",
|
|
49444
49899
|
optional: false
|
|
49445
49900
|
}],
|
|
49901
|
+
"lawnMowerControl.getStatus": [{
|
|
49902
|
+
name: "deviceId",
|
|
49903
|
+
form: "single",
|
|
49904
|
+
optional: false
|
|
49905
|
+
}],
|
|
49446
49906
|
"lawnMowerControl.pause": [{
|
|
49447
49907
|
name: "deviceId",
|
|
49448
49908
|
form: "single",
|
|
@@ -49453,6 +49913,11 @@ Object.freeze({
|
|
|
49453
49913
|
form: "single",
|
|
49454
49914
|
optional: false
|
|
49455
49915
|
}],
|
|
49916
|
+
"lockControl.getStatus": [{
|
|
49917
|
+
name: "deviceId",
|
|
49918
|
+
form: "single",
|
|
49919
|
+
optional: false
|
|
49920
|
+
}],
|
|
49456
49921
|
"lockControl.lock": [{
|
|
49457
49922
|
name: "deviceId",
|
|
49458
49923
|
form: "single",
|
|
@@ -49468,6 +49933,11 @@ Object.freeze({
|
|
|
49468
49933
|
form: "single",
|
|
49469
49934
|
optional: false
|
|
49470
49935
|
}],
|
|
49936
|
+
"mediaPlayer.getStatus": [{
|
|
49937
|
+
name: "deviceId",
|
|
49938
|
+
form: "single",
|
|
49939
|
+
optional: false
|
|
49940
|
+
}],
|
|
49471
49941
|
"mediaPlayer.next": [{
|
|
49472
49942
|
name: "deviceId",
|
|
49473
49943
|
form: "single",
|
|
@@ -49528,6 +49998,11 @@ Object.freeze({
|
|
|
49528
49998
|
form: "single",
|
|
49529
49999
|
optional: false
|
|
49530
50000
|
}],
|
|
50001
|
+
"motion.getStatus": [{
|
|
50002
|
+
name: "deviceId",
|
|
50003
|
+
form: "single",
|
|
50004
|
+
optional: false
|
|
50005
|
+
}],
|
|
49531
50006
|
"motion.isDetected": [{
|
|
49532
50007
|
name: "deviceId",
|
|
49533
50008
|
form: "single",
|
|
@@ -49538,11 +50013,31 @@ Object.freeze({
|
|
|
49538
50013
|
form: "single",
|
|
49539
50014
|
optional: false
|
|
49540
50015
|
}],
|
|
50016
|
+
"motionDetection.applyDeviceSettingsPatch": [{
|
|
50017
|
+
name: "deviceId",
|
|
50018
|
+
form: "single",
|
|
50019
|
+
optional: false
|
|
50020
|
+
}],
|
|
50021
|
+
"motionDetection.getDeviceLiveContribution": [{
|
|
50022
|
+
name: "deviceId",
|
|
50023
|
+
form: "single",
|
|
50024
|
+
optional: false
|
|
50025
|
+
}],
|
|
50026
|
+
"motionDetection.getDeviceSettingsContribution": [{
|
|
50027
|
+
name: "deviceId",
|
|
50028
|
+
form: "single",
|
|
50029
|
+
optional: false
|
|
50030
|
+
}],
|
|
49541
50031
|
"motionDetection.removeCamera": [{
|
|
49542
50032
|
name: "deviceId",
|
|
49543
50033
|
form: "single",
|
|
49544
50034
|
optional: false
|
|
49545
50035
|
}],
|
|
50036
|
+
"motionTrigger.getStatus": [{
|
|
50037
|
+
name: "deviceId",
|
|
50038
|
+
form: "single",
|
|
50039
|
+
optional: false
|
|
50040
|
+
}],
|
|
49546
50041
|
"motionTrigger.setMotionTrigger": [{
|
|
49547
50042
|
name: "deviceId",
|
|
49548
50043
|
form: "single",
|
|
@@ -49553,6 +50048,11 @@ Object.freeze({
|
|
|
49553
50048
|
form: "single",
|
|
49554
50049
|
optional: false
|
|
49555
50050
|
}],
|
|
50051
|
+
"motionZones.getStatus": [{
|
|
50052
|
+
name: "deviceId",
|
|
50053
|
+
form: "single",
|
|
50054
|
+
optional: false
|
|
50055
|
+
}],
|
|
49556
50056
|
"motionZones.setZone": [{
|
|
49557
50057
|
name: "deviceId",
|
|
49558
50058
|
form: "single",
|
|
@@ -49563,6 +50063,11 @@ Object.freeze({
|
|
|
49563
50063
|
form: "single",
|
|
49564
50064
|
optional: false
|
|
49565
50065
|
}],
|
|
50066
|
+
"nativeObjectDetection.getStatus": [{
|
|
50067
|
+
name: "deviceId",
|
|
50068
|
+
form: "single",
|
|
50069
|
+
optional: false
|
|
50070
|
+
}],
|
|
49566
50071
|
"nativeObjectDetection.setEnabled": [{
|
|
49567
50072
|
name: "deviceId",
|
|
49568
50073
|
form: "single",
|
|
@@ -49578,6 +50083,11 @@ Object.freeze({
|
|
|
49578
50083
|
form: "single",
|
|
49579
50084
|
optional: false
|
|
49580
50085
|
}],
|
|
50086
|
+
"navigation.getStatus": [{
|
|
50087
|
+
name: "deviceId",
|
|
50088
|
+
form: "single",
|
|
50089
|
+
optional: false
|
|
50090
|
+
}],
|
|
49581
50091
|
"navigation.goToPoint": [{
|
|
49582
50092
|
name: "deviceId",
|
|
49583
50093
|
form: "single",
|
|
@@ -49623,6 +50133,11 @@ Object.freeze({
|
|
|
49623
50133
|
form: "single",
|
|
49624
50134
|
optional: false
|
|
49625
50135
|
}],
|
|
50136
|
+
"networkLink.getStatus": [{
|
|
50137
|
+
name: "deviceId",
|
|
50138
|
+
form: "single",
|
|
50139
|
+
optional: false
|
|
50140
|
+
}],
|
|
49626
50141
|
"networkQuality.getDeviceStats": [{
|
|
49627
50142
|
name: "deviceId",
|
|
49628
50143
|
form: "single",
|
|
@@ -49633,6 +50148,11 @@ Object.freeze({
|
|
|
49633
50148
|
form: "single",
|
|
49634
50149
|
optional: false
|
|
49635
50150
|
}],
|
|
50151
|
+
"notificationRules.getAlarmSensors": [{
|
|
50152
|
+
name: "deviceIds",
|
|
50153
|
+
form: "array",
|
|
50154
|
+
optional: false
|
|
50155
|
+
}],
|
|
49636
50156
|
"notificationRules.setDeviceMuted": [{
|
|
49637
50157
|
name: "deviceId",
|
|
49638
50158
|
form: "single",
|
|
@@ -49643,11 +50163,26 @@ Object.freeze({
|
|
|
49643
50163
|
form: "single",
|
|
49644
50164
|
optional: false
|
|
49645
50165
|
}],
|
|
50166
|
+
"notifier.getStatus": [{
|
|
50167
|
+
name: "deviceId",
|
|
50168
|
+
form: "single",
|
|
50169
|
+
optional: false
|
|
50170
|
+
}],
|
|
49646
50171
|
"notifier.send": [{
|
|
49647
50172
|
name: "deviceId",
|
|
49648
50173
|
form: "single",
|
|
49649
50174
|
optional: false
|
|
49650
50175
|
}],
|
|
50176
|
+
"numericSensor.getStatus": [{
|
|
50177
|
+
name: "deviceId",
|
|
50178
|
+
form: "single",
|
|
50179
|
+
optional: false
|
|
50180
|
+
}],
|
|
50181
|
+
"osd.getStatus": [{
|
|
50182
|
+
name: "deviceId",
|
|
50183
|
+
form: "single",
|
|
50184
|
+
optional: false
|
|
50185
|
+
}],
|
|
49651
50186
|
"osd.setOverlay": [{
|
|
49652
50187
|
name: "deviceId",
|
|
49653
50188
|
form: "single",
|
|
@@ -49707,6 +50242,11 @@ Object.freeze({
|
|
|
49707
50242
|
form: "single",
|
|
49708
50243
|
optional: false
|
|
49709
50244
|
}],
|
|
50245
|
+
"petFeeder.getStatus": [{
|
|
50246
|
+
name: "deviceId",
|
|
50247
|
+
form: "single",
|
|
50248
|
+
optional: false
|
|
50249
|
+
}],
|
|
49710
50250
|
"petFeeder.markFoodReplenished": [{
|
|
49711
50251
|
name: "deviceId",
|
|
49712
50252
|
form: "single",
|
|
@@ -49742,6 +50282,11 @@ Object.freeze({
|
|
|
49742
50282
|
form: "single",
|
|
49743
50283
|
optional: false
|
|
49744
50284
|
}],
|
|
50285
|
+
"pipelineAnalytics.applyDeviceSettingsPatch": [{
|
|
50286
|
+
name: "deviceId",
|
|
50287
|
+
form: "single",
|
|
50288
|
+
optional: false
|
|
50289
|
+
}],
|
|
49745
50290
|
"pipelineAnalytics.clearTrackRelation": [{
|
|
49746
50291
|
name: "deviceId",
|
|
49747
50292
|
form: "single",
|
|
@@ -49782,6 +50327,16 @@ Object.freeze({
|
|
|
49782
50327
|
form: "single",
|
|
49783
50328
|
optional: false
|
|
49784
50329
|
}],
|
|
50330
|
+
"pipelineAnalytics.getDeviceLiveContribution": [{
|
|
50331
|
+
name: "deviceId",
|
|
50332
|
+
form: "single",
|
|
50333
|
+
optional: false
|
|
50334
|
+
}],
|
|
50335
|
+
"pipelineAnalytics.getDeviceSettingsContribution": [{
|
|
50336
|
+
name: "deviceId",
|
|
50337
|
+
form: "single",
|
|
50338
|
+
optional: false
|
|
50339
|
+
}],
|
|
49785
50340
|
"pipelineAnalytics.getEventDensity": [{
|
|
49786
50341
|
name: "deviceId",
|
|
49787
50342
|
form: "single",
|
|
@@ -49997,6 +50552,11 @@ Object.freeze({
|
|
|
49997
50552
|
form: "single",
|
|
49998
50553
|
optional: true
|
|
49999
50554
|
}],
|
|
50555
|
+
"pipelineOrchestrator.applyDeviceSettingsPatch": [{
|
|
50556
|
+
name: "deviceId",
|
|
50557
|
+
form: "single",
|
|
50558
|
+
optional: false
|
|
50559
|
+
}],
|
|
50000
50560
|
"pipelineOrchestrator.assignAudio": [{
|
|
50001
50561
|
name: "deviceId",
|
|
50002
50562
|
form: "single",
|
|
@@ -50042,6 +50602,16 @@ Object.freeze({
|
|
|
50042
50602
|
form: "single",
|
|
50043
50603
|
optional: false
|
|
50044
50604
|
}],
|
|
50605
|
+
"pipelineOrchestrator.getDeviceLiveContribution": [{
|
|
50606
|
+
name: "deviceId",
|
|
50607
|
+
form: "single",
|
|
50608
|
+
optional: false
|
|
50609
|
+
}],
|
|
50610
|
+
"pipelineOrchestrator.getDeviceSettingsContribution": [{
|
|
50611
|
+
name: "deviceId",
|
|
50612
|
+
form: "single",
|
|
50613
|
+
optional: false
|
|
50614
|
+
}],
|
|
50045
50615
|
"pipelineOrchestrator.getPipelineAssignment": [{
|
|
50046
50616
|
name: "deviceId",
|
|
50047
50617
|
form: "single",
|
|
@@ -50052,6 +50622,11 @@ Object.freeze({
|
|
|
50052
50622
|
form: "single",
|
|
50053
50623
|
optional: false
|
|
50054
50624
|
}],
|
|
50625
|
+
"pipelineOrchestrator.requestOccupancyLook": [{
|
|
50626
|
+
name: "deviceId",
|
|
50627
|
+
form: "single",
|
|
50628
|
+
optional: false
|
|
50629
|
+
}],
|
|
50055
50630
|
"pipelineOrchestrator.resolvePipeline": [{
|
|
50056
50631
|
name: "deviceId",
|
|
50057
50632
|
form: "single",
|
|
@@ -50157,11 +50732,31 @@ Object.freeze({
|
|
|
50157
50732
|
form: "single",
|
|
50158
50733
|
optional: true
|
|
50159
50734
|
}],
|
|
50735
|
+
"powerMeter.getStatus": [{
|
|
50736
|
+
name: "deviceId",
|
|
50737
|
+
form: "single",
|
|
50738
|
+
optional: false
|
|
50739
|
+
}],
|
|
50740
|
+
"presence.getStatus": [{
|
|
50741
|
+
name: "deviceId",
|
|
50742
|
+
form: "single",
|
|
50743
|
+
optional: false
|
|
50744
|
+
}],
|
|
50745
|
+
"pressureSensor.getStatus": [{
|
|
50746
|
+
name: "deviceId",
|
|
50747
|
+
form: "single",
|
|
50748
|
+
optional: false
|
|
50749
|
+
}],
|
|
50160
50750
|
"privacyMask.getOptions": [{
|
|
50161
50751
|
name: "deviceId",
|
|
50162
50752
|
form: "single",
|
|
50163
50753
|
optional: false
|
|
50164
50754
|
}],
|
|
50755
|
+
"privacyMask.getStatus": [{
|
|
50756
|
+
name: "deviceId",
|
|
50757
|
+
form: "single",
|
|
50758
|
+
optional: false
|
|
50759
|
+
}],
|
|
50165
50760
|
"privacyMask.setAudioEnabled": [{
|
|
50166
50761
|
name: "deviceId",
|
|
50167
50762
|
form: "single",
|
|
@@ -50212,6 +50807,11 @@ Object.freeze({
|
|
|
50212
50807
|
form: "single",
|
|
50213
50808
|
optional: false
|
|
50214
50809
|
}],
|
|
50810
|
+
"ptz.getStatus": [{
|
|
50811
|
+
name: "deviceId",
|
|
50812
|
+
form: "single",
|
|
50813
|
+
optional: false
|
|
50814
|
+
}],
|
|
50215
50815
|
"ptz.goHome": [{
|
|
50216
50816
|
name: "deviceId",
|
|
50217
50817
|
form: "single",
|
|
@@ -50302,6 +50902,11 @@ Object.freeze({
|
|
|
50302
50902
|
form: "single",
|
|
50303
50903
|
optional: false
|
|
50304
50904
|
}],
|
|
50905
|
+
"recordingArchive.applyDeviceSettingsPatch": [{
|
|
50906
|
+
name: "deviceId",
|
|
50907
|
+
form: "single",
|
|
50908
|
+
optional: false
|
|
50909
|
+
}],
|
|
50305
50910
|
"recordingArchive.deleteFootprint": [{
|
|
50306
50911
|
name: "deviceId",
|
|
50307
50912
|
form: "single",
|
|
@@ -50322,6 +50927,21 @@ Object.freeze({
|
|
|
50322
50927
|
form: "single",
|
|
50323
50928
|
optional: false
|
|
50324
50929
|
}],
|
|
50930
|
+
"recordingArchive.getDeviceLiveContribution": [{
|
|
50931
|
+
name: "deviceId",
|
|
50932
|
+
form: "single",
|
|
50933
|
+
optional: false
|
|
50934
|
+
}],
|
|
50935
|
+
"recordingArchive.getDeviceSettingsContribution": [{
|
|
50936
|
+
name: "deviceId",
|
|
50937
|
+
form: "single",
|
|
50938
|
+
optional: false
|
|
50939
|
+
}],
|
|
50940
|
+
"recordingArchive.getStatus": [{
|
|
50941
|
+
name: "deviceId",
|
|
50942
|
+
form: "single",
|
|
50943
|
+
optional: false
|
|
50944
|
+
}],
|
|
50325
50945
|
"recordingArchive.listOpsLog": [{
|
|
50326
50946
|
name: "deviceId",
|
|
50327
50947
|
form: "single",
|
|
@@ -50407,6 +51027,11 @@ Object.freeze({
|
|
|
50407
51027
|
form: "single",
|
|
50408
51028
|
optional: false
|
|
50409
51029
|
}],
|
|
51030
|
+
"recordingOnboard.getStatus": [{
|
|
51031
|
+
name: "deviceId",
|
|
51032
|
+
form: "single",
|
|
51033
|
+
optional: false
|
|
51034
|
+
}],
|
|
50410
51035
|
"recordingOnboard.setSettings": [{
|
|
50411
51036
|
name: "deviceId",
|
|
50412
51037
|
form: "single",
|
|
@@ -50437,6 +51062,11 @@ Object.freeze({
|
|
|
50437
51062
|
form: "single",
|
|
50438
51063
|
optional: false
|
|
50439
51064
|
}],
|
|
51065
|
+
"sceneMonitor.getStatus": [{
|
|
51066
|
+
name: "deviceId",
|
|
51067
|
+
form: "single",
|
|
51068
|
+
optional: false
|
|
51069
|
+
}],
|
|
50440
51070
|
"sceneMonitor.listScenes": [{
|
|
50441
51071
|
name: "deviceId",
|
|
50442
51072
|
form: "single",
|
|
@@ -50462,6 +51092,11 @@ Object.freeze({
|
|
|
50462
51092
|
form: "single",
|
|
50463
51093
|
optional: false
|
|
50464
51094
|
}],
|
|
51095
|
+
"scriptRunner.getStatus": [{
|
|
51096
|
+
name: "deviceId",
|
|
51097
|
+
form: "single",
|
|
51098
|
+
optional: false
|
|
51099
|
+
}],
|
|
50465
51100
|
"scriptRunner.run": [{
|
|
50466
51101
|
name: "deviceId",
|
|
50467
51102
|
form: "single",
|
|
@@ -50472,11 +51107,31 @@ Object.freeze({
|
|
|
50472
51107
|
form: "single",
|
|
50473
51108
|
optional: false
|
|
50474
51109
|
}],
|
|
51110
|
+
"smoke.getStatus": [{
|
|
51111
|
+
name: "deviceId",
|
|
51112
|
+
form: "single",
|
|
51113
|
+
optional: false
|
|
51114
|
+
}],
|
|
51115
|
+
"snapshot.applyDeviceSettingsPatch": [{
|
|
51116
|
+
name: "deviceId",
|
|
51117
|
+
form: "single",
|
|
51118
|
+
optional: false
|
|
51119
|
+
}],
|
|
50475
51120
|
"snapshot.getDebugState": [{
|
|
50476
51121
|
name: "deviceId",
|
|
50477
51122
|
form: "single",
|
|
50478
51123
|
optional: false
|
|
50479
51124
|
}],
|
|
51125
|
+
"snapshot.getDeviceLiveContribution": [{
|
|
51126
|
+
name: "deviceId",
|
|
51127
|
+
form: "single",
|
|
51128
|
+
optional: false
|
|
51129
|
+
}],
|
|
51130
|
+
"snapshot.getDeviceSettingsContribution": [{
|
|
51131
|
+
name: "deviceId",
|
|
51132
|
+
form: "single",
|
|
51133
|
+
optional: false
|
|
51134
|
+
}],
|
|
50480
51135
|
"snapshot.getSnapshot": [{
|
|
50481
51136
|
name: "deviceId",
|
|
50482
51137
|
form: "single",
|
|
@@ -50493,6 +51148,11 @@ Object.freeze({
|
|
|
50493
51148
|
form: "array",
|
|
50494
51149
|
optional: false
|
|
50495
51150
|
}],
|
|
51151
|
+
"snapshot.getStatus": [{
|
|
51152
|
+
name: "deviceId",
|
|
51153
|
+
form: "single",
|
|
51154
|
+
optional: false
|
|
51155
|
+
}],
|
|
50496
51156
|
"snapshot.invalidateCache": [{
|
|
50497
51157
|
name: "deviceId",
|
|
50498
51158
|
form: "single",
|
|
@@ -50503,6 +51163,11 @@ Object.freeze({
|
|
|
50503
51163
|
form: "single",
|
|
50504
51164
|
optional: false
|
|
50505
51165
|
}],
|
|
51166
|
+
"streamBroker.applyDeviceSettingsPatch": [{
|
|
51167
|
+
name: "deviceId",
|
|
51168
|
+
form: "single",
|
|
51169
|
+
optional: false
|
|
51170
|
+
}],
|
|
50506
51171
|
"streamBroker.assignProfile": [{
|
|
50507
51172
|
name: "deviceId",
|
|
50508
51173
|
form: "single",
|
|
@@ -50518,6 +51183,16 @@ Object.freeze({
|
|
|
50518
51183
|
form: "single",
|
|
50519
51184
|
optional: false
|
|
50520
51185
|
}],
|
|
51186
|
+
"streamBroker.getDeviceLiveContribution": [{
|
|
51187
|
+
name: "deviceId",
|
|
51188
|
+
form: "single",
|
|
51189
|
+
optional: false
|
|
51190
|
+
}],
|
|
51191
|
+
"streamBroker.getDeviceSettingsContribution": [{
|
|
51192
|
+
name: "deviceId",
|
|
51193
|
+
form: "single",
|
|
51194
|
+
optional: false
|
|
51195
|
+
}],
|
|
50521
51196
|
"streamBroker.getStreamWithCodec": [{
|
|
50522
51197
|
name: "deviceId",
|
|
50523
51198
|
form: "single",
|
|
@@ -50578,16 +51253,46 @@ Object.freeze({
|
|
|
50578
51253
|
form: "single",
|
|
50579
51254
|
optional: false
|
|
50580
51255
|
}],
|
|
51256
|
+
"streamParams.getStatus": [{
|
|
51257
|
+
name: "deviceId",
|
|
51258
|
+
form: "single",
|
|
51259
|
+
optional: false
|
|
51260
|
+
}],
|
|
50581
51261
|
"streamParams.setProfile": [{
|
|
50582
51262
|
name: "deviceId",
|
|
50583
51263
|
form: "single",
|
|
50584
51264
|
optional: false
|
|
50585
51265
|
}],
|
|
51266
|
+
"switch.getStatus": [{
|
|
51267
|
+
name: "deviceId",
|
|
51268
|
+
form: "single",
|
|
51269
|
+
optional: false
|
|
51270
|
+
}],
|
|
50586
51271
|
"switch.setState": [{
|
|
50587
51272
|
name: "deviceId",
|
|
50588
51273
|
form: "single",
|
|
50589
51274
|
optional: false
|
|
50590
51275
|
}],
|
|
51276
|
+
"tamper.getStatus": [{
|
|
51277
|
+
name: "deviceId",
|
|
51278
|
+
form: "single",
|
|
51279
|
+
optional: false
|
|
51280
|
+
}],
|
|
51281
|
+
"temperatureSensor.getStatus": [{
|
|
51282
|
+
name: "deviceId",
|
|
51283
|
+
form: "single",
|
|
51284
|
+
optional: false
|
|
51285
|
+
}],
|
|
51286
|
+
"update.getStatus": [{
|
|
51287
|
+
name: "deviceId",
|
|
51288
|
+
form: "single",
|
|
51289
|
+
optional: false
|
|
51290
|
+
}],
|
|
51291
|
+
"vacuumControl.getStatus": [{
|
|
51292
|
+
name: "deviceId",
|
|
51293
|
+
form: "single",
|
|
51294
|
+
optional: false
|
|
51295
|
+
}],
|
|
50591
51296
|
"vacuumControl.locate": [{
|
|
50592
51297
|
name: "deviceId",
|
|
50593
51298
|
form: "single",
|
|
@@ -50623,6 +51328,11 @@ Object.freeze({
|
|
|
50623
51328
|
form: "single",
|
|
50624
51329
|
optional: false
|
|
50625
51330
|
}],
|
|
51331
|
+
"valve.getStatus": [{
|
|
51332
|
+
name: "deviceId",
|
|
51333
|
+
form: "single",
|
|
51334
|
+
optional: false
|
|
51335
|
+
}],
|
|
50626
51336
|
"valve.open": [{
|
|
50627
51337
|
name: "deviceId",
|
|
50628
51338
|
form: "single",
|
|
@@ -50638,6 +51348,11 @@ Object.freeze({
|
|
|
50638
51348
|
form: "single",
|
|
50639
51349
|
optional: false
|
|
50640
51350
|
}],
|
|
51351
|
+
"vibration.getStatus": [{
|
|
51352
|
+
name: "deviceId",
|
|
51353
|
+
form: "single",
|
|
51354
|
+
optional: false
|
|
51355
|
+
}],
|
|
50641
51356
|
"videoclips.dialClipStream": [{
|
|
50642
51357
|
name: "deviceId",
|
|
50643
51358
|
form: "single",
|
|
@@ -50673,6 +51388,11 @@ Object.freeze({
|
|
|
50673
51388
|
form: "single",
|
|
50674
51389
|
optional: false
|
|
50675
51390
|
}],
|
|
51391
|
+
"waterHeater.getStatus": [{
|
|
51392
|
+
name: "deviceId",
|
|
51393
|
+
form: "single",
|
|
51394
|
+
optional: false
|
|
51395
|
+
}],
|
|
50676
51396
|
"waterHeater.setAway": [{
|
|
50677
51397
|
name: "deviceId",
|
|
50678
51398
|
form: "single",
|
|
@@ -50688,6 +51408,11 @@ Object.freeze({
|
|
|
50688
51408
|
form: "single",
|
|
50689
51409
|
optional: false
|
|
50690
51410
|
}],
|
|
51411
|
+
"weather.getStatus": [{
|
|
51412
|
+
name: "deviceId",
|
|
51413
|
+
form: "single",
|
|
51414
|
+
optional: false
|
|
51415
|
+
}],
|
|
50691
51416
|
"webrtcSession.addIceCandidate": [{
|
|
50692
51417
|
name: "deviceId",
|
|
50693
51418
|
form: "single",
|
|
@@ -51213,6 +51938,18 @@ var STATE_SUMMARY_VARS = [
|
|
|
51213
51938
|
systemEventKinds: [...SUMMARISABLE],
|
|
51214
51939
|
systemEventDeliveries: ["summary"]
|
|
51215
51940
|
},
|
|
51941
|
+
{
|
|
51942
|
+
name: "summarySection",
|
|
51943
|
+
label: "Summary: this section",
|
|
51944
|
+
description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
|
|
51945
|
+
example: "Batterie scariche",
|
|
51946
|
+
group: "system",
|
|
51947
|
+
families: ["rule"],
|
|
51948
|
+
fields: [...RULE_TEXT],
|
|
51949
|
+
kinds: ["system"],
|
|
51950
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
51951
|
+
systemEventDeliveries: ["summary"]
|
|
51952
|
+
},
|
|
51216
51953
|
...STATE_SUMMARY_SECTION_VARS.map((v) => ({
|
|
51217
51954
|
name: v.name,
|
|
51218
51955
|
label: v.label,
|
|
@@ -51289,6 +52026,37 @@ var STATE_SUMMARY_VARS = [
|
|
|
51289
52026
|
[...RULE_TEXT],
|
|
51290
52027
|
...STATE_SUMMARY_VARS
|
|
51291
52028
|
];
|
|
52029
|
+
new Set([
|
|
52030
|
+
"disarmed",
|
|
52031
|
+
"armed_home",
|
|
52032
|
+
"armed_away",
|
|
52033
|
+
"armed_night",
|
|
52034
|
+
"armed_vacation",
|
|
52035
|
+
"armed_custom_bypass",
|
|
52036
|
+
"arming",
|
|
52037
|
+
"disarming",
|
|
52038
|
+
"pending",
|
|
52039
|
+
"triggered",
|
|
52040
|
+
"open",
|
|
52041
|
+
"opening",
|
|
52042
|
+
"closing",
|
|
52043
|
+
"closed",
|
|
52044
|
+
"stopped",
|
|
52045
|
+
"locked",
|
|
52046
|
+
"unlocked",
|
|
52047
|
+
"locking",
|
|
52048
|
+
"unlocking",
|
|
52049
|
+
"jammed",
|
|
52050
|
+
"on",
|
|
52051
|
+
"off",
|
|
52052
|
+
"home",
|
|
52053
|
+
"not_home",
|
|
52054
|
+
"matched",
|
|
52055
|
+
"diverged",
|
|
52056
|
+
"unknown",
|
|
52057
|
+
"latched",
|
|
52058
|
+
"live"
|
|
52059
|
+
]);
|
|
51292
52060
|
/**
|
|
51293
52061
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
51294
52062
|
*
|
|
@@ -51382,7 +52150,7 @@ var PreviewTextField = string().max(200);
|
|
|
51382
52150
|
* Whether the notification's preview is a STILL or a short animation.
|
|
51383
52151
|
*
|
|
51384
52152
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
51385
|
-
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
52153
|
+
* rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
|
|
51386
52154
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
51387
52155
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
51388
52156
|
* simply applies it to a dozen frames sampled across the render and assembles
|
|
@@ -51520,6 +52288,7 @@ TimelapseRuleInputSchema.extend({
|
|
|
51520
52288
|
createdAt: number(),
|
|
51521
52289
|
updatedAt: number()
|
|
51522
52290
|
});
|
|
52291
|
+
MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
|
|
51523
52292
|
object({
|
|
51524
52293
|
/**
|
|
51525
52294
|
* Fraction of the box's own size added on EACH side before cutting.
|